• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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