• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.documentsui.dirlist;
18 
19 import static com.android.documentsui.base.SharedMinimal.VERBOSE;
20 import static com.android.documentsui.base.State.MODE_GRID;
21 import static com.android.documentsui.base.State.MODE_LIST;
22 
23 import android.content.Context;
24 import android.graphics.Bitmap;
25 import android.graphics.Point;
26 import android.graphics.drawable.Drawable;
27 import android.net.Uri;
28 import android.provider.DocumentsContract;
29 import android.provider.DocumentsContract.Document;
30 import android.util.Log;
31 import android.view.View;
32 import android.widget.ImageView;
33 
34 import androidx.annotation.Nullable;
35 
36 import com.android.documentsui.DocumentsApplication;
37 import com.android.documentsui.IconUtils;
38 import com.android.documentsui.ProviderExecutor;
39 import com.android.documentsui.R;
40 import com.android.documentsui.ThumbnailCache;
41 import com.android.documentsui.ThumbnailCache.Result;
42 import com.android.documentsui.ThumbnailLoader;
43 import com.android.documentsui.base.DocumentInfo;
44 import com.android.documentsui.base.MimeTypes;
45 import com.android.documentsui.base.State;
46 import com.android.documentsui.base.State.ViewMode;
47 
48 import java.util.function.BiConsumer;
49 
50 /**
51  * A class to assist with loading and managing the Images (i.e. thumbnails and icons) associated
52  * with items in the directory listing.
53  */
54 public class IconHelper {
55     private static final String TAG = "IconHelper";
56 
57     private final Context mContext;
58     private final ThumbnailCache mThumbnailCache;
59 
60     // The display mode (MODE_GRID, MODE_LIST, etc).
61     private int mMode;
62     private Point mCurrentSize;
63     private boolean mThumbnailsEnabled = true;
64 
65     /**
66      * @param context
67      * @param mode MODE_GRID or MODE_LIST
68      */
IconHelper(Context context, int mode)69     public IconHelper(Context context, int mode) {
70         mContext = context;
71         setViewMode(mode);
72         mThumbnailCache = DocumentsApplication.getThumbnailCache(context);
73     }
74 
75     /**
76      * Enables or disables thumbnails. When thumbnails are disabled, mime icons (or custom icons, if
77      * specified by the document) are used instead.
78      *
79      * @param enabled
80      */
setThumbnailsEnabled(boolean enabled)81     public void setThumbnailsEnabled(boolean enabled) {
82         mThumbnailsEnabled = enabled;
83     }
84 
85     /**
86      * Sets the current display mode. This affects the thumbnail sizes that are loaded.
87      *
88      * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
89      */
setViewMode(@iewMode int mode)90     public void setViewMode(@ViewMode int mode) {
91         mMode = mode;
92         int thumbSize = getThumbSize(mode);
93         mCurrentSize = new Point(thumbSize, thumbSize);
94     }
95 
getThumbSize(int mode)96     private int getThumbSize(int mode) {
97         int thumbSize;
98         switch (mode) {
99             case MODE_GRID:
100                 thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.grid_width);
101                 break;
102             case MODE_LIST:
103                 thumbSize = mContext.getResources().getDimensionPixelSize(
104                         R.dimen.list_item_thumbnail_size);
105                 break;
106             default:
107                 throw new IllegalArgumentException("Unsupported layout mode: " + mode);
108         }
109         return thumbSize;
110     }
111 
112     /**
113      * Cancels any ongoing load operations associated with the given ImageView.
114      *
115      * @param icon
116      */
stopLoading(ImageView icon)117     public void stopLoading(ImageView icon) {
118         final ThumbnailLoader oldTask = (ThumbnailLoader) icon.getTag();
119         if (oldTask != null) {
120             oldTask.preempt();
121             icon.setTag(null);
122         }
123     }
124 
125     /**
126      * Load thumbnails for a directory list item.
127      *
128      * @param doc The document
129      * @param iconThumb The itemview's thumbnail icon.
130      * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown.
131      * @param subIconMime The second itemview's mime icon. Always visible.
132      * @return
133      */
load( DocumentInfo doc, ImageView iconThumb, ImageView iconMime, @Nullable ImageView subIconMime)134     public void load(
135             DocumentInfo doc,
136             ImageView iconThumb,
137             ImageView iconMime,
138             @Nullable ImageView subIconMime) {
139         load(doc.derivedUri, doc.mimeType, doc.flags, doc.icon, doc.lastModified,
140                 iconThumb, iconMime, subIconMime);
141     }
142 
143     /**
144      * Load thumbnails for a directory list item.
145      *
146      * @param uri The URI for the file being represented.
147      * @param mimeType The mime type of the file being represented.
148      * @param docFlags Flags for the file being represented.
149      * @param docIcon Custom icon (if any) for the file being requested.
150      * @param docLastModified the last modified value of the file being requested.
151      * @param iconThumb The itemview's thumbnail icon.
152      * @param iconMime The itemview's mime icon. Hidden when iconThumb is shown.
153      * @param subIconMime The second itemview's mime icon. Always visible.
154      * @return
155      */
load(Uri uri, String mimeType, int docFlags, int docIcon, long docLastModified, ImageView iconThumb, ImageView iconMime, @Nullable ImageView subIconMime)156     public void load(Uri uri, String mimeType, int docFlags, int docIcon, long docLastModified,
157             ImageView iconThumb, ImageView iconMime, @Nullable ImageView subIconMime) {
158         boolean loadedThumbnail = false;
159 
160         final String docAuthority = uri.getAuthority();
161 
162         final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
163         final boolean allowThumbnail = (mMode == MODE_GRID)
164                 || MimeTypes.mimeMatches(MimeTypes.VISUAL_MIMES, mimeType);
165         final boolean showThumbnail = supportsThumbnail && allowThumbnail && mThumbnailsEnabled;
166         if (showThumbnail) {
167             loadedThumbnail =
168                 loadThumbnail(uri, docAuthority, docLastModified, iconThumb, iconMime);
169         }
170 
171         final Drawable mimeIcon = getDocumentIcon(mContext, docAuthority,
172                 DocumentsContract.getDocumentId(uri), mimeType, docIcon);
173         if (subIconMime != null) {
174             setMimeIcon(subIconMime, mimeIcon);
175         }
176 
177         if (loadedThumbnail) {
178             hideImageView(iconMime);
179         } else {
180             // Add a mime icon if the thumbnail is not shown.
181             setMimeIcon(iconMime, mimeIcon);
182             hideImageView(iconThumb);
183         }
184     }
185 
loadThumbnail(Uri uri, String docAuthority, long docLastModified, ImageView iconThumb, ImageView iconMime)186     private boolean loadThumbnail(Uri uri, String docAuthority, long docLastModified,
187             ImageView iconThumb, ImageView iconMime) {
188         final Result result = mThumbnailCache.getThumbnail(uri, mCurrentSize);
189 
190         try {
191             final Bitmap cachedThumbnail = result.getThumbnail();
192             iconThumb.setImageBitmap(cachedThumbnail);
193 
194             boolean stale = (docLastModified > result.getLastModified());
195             if (VERBOSE) Log.v(TAG,
196                     String.format("Load thumbnail for %s, got result %d and stale %b.",
197                             uri.toString(), result.getStatus(), stale));
198             if (!result.isExactHit() || stale) {
199                 final BiConsumer<View, View> animator =
200                         (cachedThumbnail == null ? ThumbnailLoader.ANIM_FADE_IN :
201                                 ThumbnailLoader.ANIM_NO_OP);
202 
203                 final ThumbnailLoader task = new ThumbnailLoader(uri, iconThumb,
204                         mCurrentSize, docLastModified,
205                         bitmap -> {
206                             if (bitmap != null) {
207                                 iconThumb.setImageBitmap(bitmap);
208                                 animator.accept(iconMime, iconThumb);
209                             }
210                         }, true /* addToCache */);
211 
212                 ProviderExecutor.forAuthority(docAuthority).execute(task);
213             }
214 
215             return result.isHit();
216         } finally {
217             result.recycle();
218         }
219     }
220 
setMimeIcon(ImageView view, Drawable icon)221     private void setMimeIcon(ImageView view, Drawable icon) {
222         view.setImageDrawable(icon);
223         view.setAlpha(1f);
224     }
225 
hideImageView(ImageView view)226     private void hideImageView(ImageView view) {
227         view.setImageDrawable(null);
228         view.setAlpha(0f);
229     }
230 
getDocumentIcon( Context context, String authority, String id, String mimeType, int icon)231     private Drawable getDocumentIcon(
232         Context context, String authority, String id, String mimeType, int icon) {
233         if (icon != 0) {
234             return IconUtils.loadPackageIcon(context, authority, icon);
235         } else {
236             return IconUtils.loadMimeIcon(context, mimeType, authority, id, mMode);
237         }
238     }
239 
240     /**
241      * Returns a mime icon or package icon for a {@link DocumentInfo}.
242      */
getDocumentIcon(Context context, DocumentInfo doc)243     public Drawable getDocumentIcon(Context context, DocumentInfo doc) {
244         return getDocumentIcon(
245                 context, doc.authority, doc.documentId, doc.mimeType, doc.icon);
246     }
247 }
248