1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.photopicker.data.model 18 19 import android.net.Uri 20 import android.os.Parcel 21 import android.os.Parcelable 22 import com.android.photopicker.core.glide.GlideLoadable 23 import com.android.photopicker.core.glide.ParcelableGlideLoadable 24 import com.android.photopicker.core.glide.Resolution 25 import com.bumptech.glide.load.DataSource 26 import com.bumptech.glide.signature.ObjectKey 27 28 /** Holds metadata for a group of media items. */ 29 sealed interface Group : Parcelable { 30 /** Unique identifier for this group */ 31 val id: String 32 33 /** 34 * Holds metadata for a album item. It is a type of a [Group] object because it represents a 35 * collection of media items. 36 */ 37 data class Album( 38 /** This is the ID provided by the [Provider] of this data */ 39 override val id: String, 40 41 /** This is the Picker ID auto-generated in Picker DB */ 42 val pickerId: Long, 43 val authority: String, 44 val dateTakenMillisLong: Long, 45 val displayName: String, 46 val coverUri: Uri, 47 val coverMediaSource: MediaSource, 48 ) : Group, GlideLoadable { getSignaturenull49 override fun getSignature(resolution: Resolution): ObjectKey { 50 return ObjectKey("${coverUri}_$resolution") 51 } 52 getLoadableUrinull53 override fun getLoadableUri(): Uri { 54 return coverUri 55 } 56 getDataSourcenull57 override fun getDataSource(): DataSource { 58 return when (coverMediaSource) { 59 MediaSource.LOCAL -> DataSource.LOCAL 60 MediaSource.REMOTE -> DataSource.REMOTE 61 } 62 } 63 describeContentsnull64 override fun describeContents(): Int { 65 return 0 66 } 67 68 /** Implemented for [Parcelable], and handles all the common attributes. */ writeToParcelnull69 override fun writeToParcel(out: Parcel, flags: Int) { 70 out.writeString(id) 71 out.writeLong(pickerId) 72 out.writeString(authority) 73 out.writeLong(dateTakenMillisLong) 74 out.writeString(displayName) 75 out.writeString(coverUri.toString()) 76 out.writeString(coverMediaSource.name) 77 } 78 79 companion object CREATOR : Parcelable.Creator<Album> { 80 createFromParcelnull81 override fun createFromParcel(parcel: Parcel): Album { 82 val album = 83 Album( 84 /* id =*/ parcel.readString() ?: "", 85 /* pickerId=*/ parcel.readLong(), 86 /* authority=*/ parcel.readString() ?: "", 87 /* dateTakenMillisLong=*/ parcel.readLong(), 88 /* displayName =*/ parcel.readString() ?: "", 89 /* uri= */ Uri.parse(parcel.readString() ?: ""), 90 /* coverUriMediaSource =*/ MediaSource.valueOf( 91 parcel.readString() ?: "LOCAL" 92 ), 93 ) 94 return album 95 } 96 newArraynull97 override fun newArray(size: Int): Array<Album?> { 98 return arrayOfNulls(size) 99 } 100 } 101 } 102 103 /** 104 * Holds metadata for a category item. It is a type of a [Group] object which can either hold 105 * other categories or media sets. 106 */ 107 data class Category( 108 /** This is the ID provided by the [Provider] of this data */ 109 override val id: String, 110 111 /** This is the Picker ID generated in Picker Backend */ 112 val pickerId: Long, 113 /** Authority of the source [Provider]. */ 114 val authority: String, 115 val displayName: String?, 116 val categoryType: CategoryType, 117 val icons: List<ParcelableGlideLoadable>, 118 val isLeafCategory: Boolean, 119 ) : Group { 120 describeContentsnull121 override fun describeContents(): Int { 122 return 0 123 } 124 125 /** Implemented for [Parcelable], and handles all the common attributes. */ writeToParcelnull126 override fun writeToParcel(out: Parcel, flags: Int) { 127 out.writeString(id) 128 out.writeLong(pickerId) 129 out.writeString(authority) 130 out.writeString(displayName) 131 out.writeString(categoryType.name) 132 out.writeParcelableList(icons, /* flags */ 0) 133 out.writeBoolean(isLeafCategory) 134 } 135 136 companion object CREATOR : Parcelable.Creator<Category> { 137 createFromParcelnull138 override fun createFromParcel(parcel: Parcel): Category { 139 @Suppress("DEPRECATION") // For backward-compatibility 140 return Category( 141 id = parcel.readString() ?: "", 142 pickerId = parcel.readLong(), 143 authority = parcel.readString() ?: "", 144 displayName = parcel.readString(), 145 categoryType = 146 CategoryType.valueOf( 147 parcel.readString() ?: CategoryType.PEOPLE_AND_PETS.name 148 ), 149 icons = 150 arrayListOf<ParcelableGlideLoadable>().apply { 151 parcel.readParcelableList( 152 this, 153 ParcelableGlideLoadable::class.java.classLoader, 154 ) 155 }, 156 isLeafCategory = parcel.readBoolean(), 157 ) 158 } 159 newArraynull160 override fun newArray(size: Int): Array<Category?> { 161 return arrayOfNulls(size) 162 } 163 } 164 } 165 166 /** 167 * Holds metadata for a media set item. It is a type of a [Group] object which contains media 168 * items. 169 * 170 * It is very similar to albums because they both contain media items, but it's a bit more 171 * generic and meant to handle a wide range of use cases. 172 */ 173 data class MediaSet( 174 /** This is the ID provided by the [Provider] of this data */ 175 override val id: String, 176 177 /** This is the Picker ID generated in Picker Backend */ 178 val pickerId: Long, 179 /** Authority of the source [Provider]. */ 180 val authority: String, 181 val displayName: String?, 182 val icon: ParcelableGlideLoadable, 183 ) : Group { 184 describeContentsnull185 override fun describeContents(): Int { 186 return 0 187 } 188 189 /** Implemented for [Parcelable], and handles all the common attributes. */ writeToParcelnull190 override fun writeToParcel(out: Parcel, flags: Int) { 191 out.writeString(id) 192 out.writeLong(pickerId) 193 out.writeString(authority) 194 out.writeString(displayName) 195 out.writeParcelable(icon, /* flags */ 0) 196 } 197 198 companion object CREATOR : Parcelable.Creator<MediaSet> { 199 createFromParcelnull200 override fun createFromParcel(parcel: Parcel): MediaSet { 201 @Suppress("DEPRECATION") // For backward-compatibility 202 return MediaSet( 203 id = parcel.readString() ?: "", 204 pickerId = parcel.readLong(), 205 authority = parcel.readString() ?: "", 206 displayName = parcel.readString(), 207 icon = 208 parcel.readParcelable(ParcelableGlideLoadable::class.java.classLoader) 209 ?: Icon(uri = Uri.parse(""), mediaSource = MediaSource.LOCAL), 210 ) 211 } 212 newArraynull213 override fun newArray(size: Int): Array<MediaSet?> { 214 return arrayOfNulls(size) 215 } 216 } 217 } 218 } 219