1 /* 2 * Copyright (C) 2021 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.providers.media.photopicker.data.model; 18 19 import static android.provider.CloudMediaProviderContract.AlbumColumns; 20 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_VIDEOS; 21 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_SCREENSHOTS; 22 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_CAMERA; 23 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_DOWNLOADS; 24 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_FAVORITES; 25 import static com.android.providers.media.photopicker.util.CursorUtils.getCursorInt; 26 import static com.android.providers.media.photopicker.util.CursorUtils.getCursorString; 27 28 import android.annotation.StringDef; 29 import android.content.Context; 30 import android.database.Cursor; 31 import android.net.Uri; 32 import android.os.Bundle; 33 import android.os.Environment; 34 import android.provider.CloudMediaProviderContract; 35 import android.provider.MediaStore; 36 import android.provider.MediaStore.Files.FileColumns; 37 import android.text.TextUtils; 38 import android.util.ArrayMap; 39 40 import androidx.annotation.NonNull; 41 import androidx.annotation.Nullable; 42 import androidx.annotation.VisibleForTesting; 43 44 import com.android.providers.media.R; 45 import com.android.providers.media.photopicker.data.ItemsProvider; 46 47 import java.lang.annotation.Retention; 48 import java.lang.annotation.RetentionPolicy; 49 import java.util.Arrays; 50 import java.util.Collections; 51 import java.util.List; 52 import java.util.Locale; 53 54 /** 55 * Defines each category (which is group of items) for the photo picker. 56 */ 57 public class Category { 58 public static final Category DEFAULT = new Category(); 59 60 private final String mId; 61 private final String mAuthority; 62 private final String mDisplayName; 63 private final boolean mIsLocal; 64 private final Uri mCoverUri; 65 private final int mItemCount; 66 Category()67 private Category() { 68 this(null, null, null, null, 0, false); 69 } 70 71 @VisibleForTesting Category(String id, String authority, String displayName, Uri coverUri, int itemCount, boolean isLocal)72 public Category(String id, String authority, String displayName, Uri coverUri, int itemCount, 73 boolean isLocal) { 74 mId = id; 75 mAuthority = authority; 76 mDisplayName = displayName; 77 mIsLocal = isLocal; 78 mCoverUri = coverUri; 79 mItemCount = itemCount; 80 } 81 82 @Override toString()83 public String toString() { 84 return String.format(Locale.ROOT, "Category: {mId: %s, mAuthority: %s, mDisplayName: %s, " + 85 "mCoverUri: %s, mItemCount: %d, mIsLocal: %b", 86 mId, mAuthority, mDisplayName, mCoverUri, mItemCount, mIsLocal); 87 } 88 getId()89 public String getId() { 90 return mId; 91 } 92 getAuthority()93 public String getAuthority() { 94 return mAuthority; 95 } 96 getDisplayName(Context context)97 public String getDisplayName(Context context) { 98 if (mIsLocal) { 99 return getLocalizedDisplayName(context, mId); 100 } 101 return mDisplayName; 102 } 103 isLocal()104 public boolean isLocal() { 105 return mIsLocal; 106 } 107 getCoverUri()108 public Uri getCoverUri() { 109 return mCoverUri; 110 } 111 getItemCount()112 public int getItemCount() { 113 return mItemCount; 114 } 115 isDefault()116 public boolean isDefault() { 117 return TextUtils.isEmpty(mId); 118 } 119 120 /** 121 * Write the {@link Category} to the given {@code bundle}. 122 */ toBundle(@onNull Bundle bundle)123 public void toBundle(@NonNull Bundle bundle) { 124 bundle.putString(AlbumColumns.ID, mId); 125 bundle.putString(AlbumColumns.AUTHORITY, mAuthority); 126 bundle.putString(AlbumColumns.DISPLAY_NAME, mDisplayName); 127 // Re-using the 'media_cover_id' to store the media_cover_uri for lack of 128 // a different constant 129 bundle.putParcelable(AlbumColumns.MEDIA_COVER_ID, mCoverUri); 130 bundle.putInt(AlbumColumns.MEDIA_COUNT, mItemCount); 131 bundle.putBoolean(AlbumColumns.IS_LOCAL, mIsLocal); 132 } 133 134 /** 135 * Create a {@link Category} from the {@code bundle}. 136 */ fromBundle(@onNull Bundle bundle)137 public static Category fromBundle(@NonNull Bundle bundle) { 138 return new Category(bundle.getString(AlbumColumns.ID), 139 bundle.getString(AlbumColumns.AUTHORITY), 140 bundle.getString(AlbumColumns.DISPLAY_NAME), 141 bundle.getParcelable(AlbumColumns.MEDIA_COVER_ID), 142 bundle.getInt(AlbumColumns.MEDIA_COUNT), 143 bundle.getBoolean(AlbumColumns.IS_LOCAL)); 144 } 145 146 /** 147 * Create a {@link Category} from the {@code cursor}. 148 */ fromCursor(@onNull Cursor cursor, @NonNull UserId userId)149 public static Category fromCursor(@NonNull Cursor cursor, @NonNull UserId userId) { 150 final boolean isLocal; 151 String authority = getCursorString(cursor, AlbumColumns.AUTHORITY); 152 if (authority != null) { 153 isLocal = true; 154 } else { 155 isLocal = false; 156 authority = cursor.getExtras().getString(MediaStore.EXTRA_CLOUD_PROVIDER); 157 } 158 final Uri coverUri = ItemsProvider.getItemsUri( 159 getCursorString(cursor, AlbumColumns.MEDIA_COVER_ID), authority, userId); 160 161 return new Category(getCursorString(cursor, AlbumColumns.ID), 162 authority, 163 getCursorString(cursor, AlbumColumns.DISPLAY_NAME), 164 coverUri, 165 getCursorInt(cursor, AlbumColumns.MEDIA_COUNT), 166 isLocal); 167 } 168 getLocalizedDisplayName(Context context, String albumId)169 private static String getLocalizedDisplayName(Context context, String albumId) { 170 switch (albumId) { 171 case ALBUM_ID_VIDEOS: 172 return context.getString(R.string.picker_category_videos); 173 case ALBUM_ID_CAMERA: 174 return context.getString(R.string.picker_category_camera); 175 case ALBUM_ID_SCREENSHOTS: 176 return context.getString(R.string.picker_category_screenshots); 177 case ALBUM_ID_DOWNLOADS: 178 return context.getString(R.string.picker_category_downloads); 179 case ALBUM_ID_FAVORITES: 180 return context.getString(R.string.picker_category_favorites); 181 default: 182 return albumId; 183 } 184 } 185 } 186