• 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.documentsui;
17 
18 import static com.android.documentsui.base.SharedMinimal.VERBOSE;
19 
20 import android.content.ContentProviderClient;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.graphics.Bitmap;
24 import android.graphics.Point;
25 import android.net.Uri;
26 import android.os.AsyncTask;
27 import android.os.CancellationSignal;
28 import android.os.OperationCanceledException;
29 import android.provider.DocumentsContract;
30 import android.util.Log;
31 import android.view.View;
32 import android.widget.ImageView;
33 import com.android.documentsui.ProviderExecutor.Preemptable;
34 import java.util.function.BiConsumer;
35 import java.util.function.Consumer;
36 
37 /**
38  *  Loads a Thumbnails asynchronously then animates from the mime icon to the thumbnail
39  */
40 public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implements Preemptable {
41 
42     private static final String TAG = ThumbnailLoader.class.getCanonicalName();
43 
44     /**
45      * Two animations applied to image views. The first is used to switch mime icon and thumbnail.
46      * The second is used when we need to update thumbnail.
47      */
48     public static final BiConsumer<View, View> ANIM_FADE_IN = (mime, thumb) -> {
49         float alpha = mime.getAlpha();
50         mime.animate().alpha(0f).start();
51         thumb.setAlpha(0f);
52         thumb.animate().alpha(alpha).start();
53     };
54     public static final BiConsumer<View, View> ANIM_NO_OP = (mime, thumb) -> {};
55 
56     private final ImageView mIconThumb;
57     private final Point mThumbSize;
58     private final Uri mUri;
59     private final long mLastModified;
60     private final Consumer<Bitmap> mCallback;
61     private final boolean mAddToCache;
62     private final CancellationSignal mSignal;
63 
64     /**
65      * @param uri - to a thumbnail.
66      * @param iconThumb - ImageView to display the thumbnail.
67      * @param thumbSize - size of the thumbnail.
68      * @param lastModified - used for updating thumbnail caches.
69      * @param addToCache - flag that determines if the loader saves the thumbnail to the cache.
70      */
ThumbnailLoader(Uri uri, ImageView iconThumb, Point thumbSize, long lastModified, Consumer<Bitmap> callback, boolean addToCache)71     public ThumbnailLoader(Uri uri, ImageView iconThumb, Point thumbSize, long lastModified,
72         Consumer<Bitmap> callback, boolean addToCache) {
73 
74         mUri = uri;
75         mIconThumb = iconThumb;
76         mThumbSize = thumbSize;
77         mLastModified = lastModified;
78         mCallback = callback;
79         mAddToCache = addToCache;
80         mSignal = new CancellationSignal();
81         mIconThumb.setTag(this);
82 
83         if (VERBOSE) Log.v(TAG, "Starting icon loader task for " + mUri);
84     }
85 
86     @Override
preempt()87     public void preempt() {
88         if (VERBOSE) Log.v(TAG, "Icon loader task for " + mUri + " was cancelled.");
89         cancel(false);
90         mSignal.cancel();
91     }
92 
93     @Override
doInBackground(Uri... params)94     protected Bitmap doInBackground(Uri... params) {
95         if (isCancelled()) {
96             return null;
97         }
98 
99         final Context context = mIconThumb.getContext();
100         final ContentResolver resolver = context.getContentResolver();
101 
102         ContentProviderClient client = null;
103         Bitmap result = null;
104         try {
105             client = DocumentsApplication.acquireUnstableProviderOrThrow(
106                 resolver, mUri.getAuthority());
107             result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
108             if (result != null && mAddToCache) {
109                 final ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context);
110                 cache.putThumbnail(mUri, mThumbSize, result, mLastModified);
111             }
112         } catch (Exception e) {
113             if (!(e instanceof OperationCanceledException)) {
114                 Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
115             }
116         } finally {
117             ContentProviderClient.releaseQuietly(client);
118         }
119         return result;
120     }
121 
122     @Override
onPostExecute(Bitmap result)123     protected void onPostExecute(Bitmap result) {
124         if (VERBOSE) Log.v(TAG, "Loader task for " + mUri + " completed");
125 
126         if (mIconThumb.getTag() == this) {
127             mIconThumb.setTag(null);
128             mCallback.accept(result);
129         }
130     }
131 }