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