• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.wallpaper.picker.individual;
17 
18 import android.Manifest.permission;
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.database.Cursor;
23 import android.net.Uri;
24 import android.os.AsyncTask;
25 import android.provider.MediaStore;
26 import android.view.View;
27 import android.widget.ImageView;
28 
29 import androidx.annotation.Nullable;
30 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
31 
32 import com.android.wallpaper.R;
33 import com.android.wallpaper.asset.Asset;
34 import com.android.wallpaper.asset.ContentUriAsset;
35 import com.android.wallpaper.picker.MyPhotosStarter;
36 
37 /**
38  * ViewHolder for a "my photos" tile presented in an individual category grid.
39  */
40 public class MyPhotosViewHolder extends ViewHolder implements View.OnClickListener,
41         MyPhotosStarter.PermissionChangedListener {
42 
43     private final Activity mActivity;
44     private final MyPhotosStarter mMyPhotosStarter;
45     private final ImageView mThumbnailView;
46     private final ImageView mOverlayIconView;
47 
MyPhotosViewHolder(Activity activity, MyPhotosStarter myPhotosStarter, int tileHeightPx, View itemView)48     /* package */ MyPhotosViewHolder(Activity activity, MyPhotosStarter myPhotosStarter,
49             int tileHeightPx, View itemView) {
50         super(itemView);
51 
52         mActivity = activity;
53         mMyPhotosStarter = myPhotosStarter;
54         itemView.getLayoutParams().height = tileHeightPx;
55 
56         itemView.findViewById(R.id.tile).setOnClickListener(this);
57 
58         mThumbnailView = itemView.findViewById(R.id.thumbnail);
59         mOverlayIconView = itemView.findViewById(R.id.overlay_icon);
60     }
61 
62     /**
63      * Fetches a thumbnail asset to represent "my photos" (as the most recently taken photo from the
64      * user's custom photo collection(s)) and calls back to the main thread with the asset.
65      */
fetchThumbnail(final Context context, final AssetListener listener)66     private static void fetchThumbnail(final Context context, final AssetListener listener) {
67         if (!isReadExternalStoragePermissionGranted(context)) {
68             // MediaStore.Images.Media.EXTERNAL_CONTENT_URI requires the READ_EXTERNAL_STORAGE permission.
69             listener.onAssetRetrieved(null);
70         }
71 
72         new AsyncTask<Void, Void, Asset>() {
73             @Override
74             protected Asset doInBackground(Void... params) {
75                 String[] projection = new String[]{
76                         MediaStore.Images.ImageColumns._ID,
77                         MediaStore.Images.ImageColumns.DATE_TAKEN,
78                 };
79                 String sortOrder = MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC LIMIT 1";
80                 Cursor cursor = context.getContentResolver().query(
81                         MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
82                         projection,
83                         null /* selection */,
84                         null /* selectionArgs */,
85                         sortOrder);
86 
87                 Asset asset = null;
88                 if (cursor != null) {
89                     if (cursor.moveToNext()) {
90                         asset = new ContentUriAsset(context, Uri.parse(
91                                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI + "/" + cursor.getString(0)));
92                     }
93                     cursor.close();
94                 }
95 
96                 return asset;
97             }
98 
99             @Override
100             protected void onPostExecute(Asset thumbnail) {
101                 listener.onAssetRetrieved(thumbnail);
102             }
103         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
104     }
105 
106     /**
107      * Returns whether READ_EXTERNAL_STORAGE has been granted for the application.
108      */
isReadExternalStoragePermissionGranted(Context context)109     private static boolean isReadExternalStoragePermissionGranted(Context context) {
110         return context.getPackageManager().checkPermission(permission.READ_EXTERNAL_STORAGE,
111                 context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
112     }
113 
114     @Override
onClick(View view)115     public void onClick(View view) {
116         mMyPhotosStarter.requestCustomPhotoPicker(this);
117     }
118 
119     /**
120      * Draws the overlay icon or last-taken photo as thumbnail for the ViewHolder depending on whether
121      * storage permission has been granted to the app.
122      */
bind()123   /* package */ void bind() {
124         if (isReadExternalStoragePermissionGranted(mActivity)) {
125             mOverlayIconView.setVisibility(View.GONE);
126             drawThumbnail();
127         } else {
128             mOverlayIconView.setVisibility(View.VISIBLE);
129             mOverlayIconView.setImageDrawable(mActivity.getDrawable(
130                     R.drawable.myphotos_empty_tile_illustration));
131         }
132     }
133 
134     @Override
onPermissionsGranted()135     public void onPermissionsGranted() {
136         bind();
137     }
138 
139     @Override
onPermissionsDenied(boolean dontAskAgain)140     public void onPermissionsDenied(boolean dontAskAgain) {
141         // No-op
142     }
143 
drawThumbnail()144     private void drawThumbnail() {
145         fetchThumbnail(mActivity, new AssetListener() {
146             @Override
147             public void onAssetRetrieved(@Nullable Asset thumbnail) {
148                 if (thumbnail == null) {
149                     return;
150                 }
151 
152                 thumbnail.loadDrawable(mActivity, mThumbnailView,
153                         mActivity.getResources().getColor(R.color.secondary_color));
154             }
155         });
156     }
157 
158     private interface AssetListener {
159         /**
160          * Called when the requested Asset is retrieved.
161          */
onAssetRetrieved(@ullable Asset asset)162         void onAssetRetrieved(@Nullable Asset asset);
163     }
164 }
165