blob: 56cadc3b1b7e6dfab516839a16a5fb2bb3eafdfb [file] [log] [blame]
Austin Kolander4143e372017-07-05 14:31:37 -07001/*
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 */
16package com.android.documentsui;
17
Jeff Sharkey2c0b4852019-02-15 15:53:47 -070018import static android.content.ContentResolver.wrap;
19
Felipe Leme9de58072018-01-19 16:40:04 -080020import static com.android.documentsui.base.SharedMinimal.VERBOSE;
Austin Kolander4143e372017-07-05 14:31:37 -070021
22import android.content.ContentProviderClient;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.graphics.Bitmap;
26import android.graphics.Point;
27import android.net.Uri;
28import android.os.AsyncTask;
29import android.os.CancellationSignal;
Jeff Sharkeybb68a652019-02-19 11:17:30 -070030import android.os.FileUtils;
Austin Kolander4143e372017-07-05 14:31:37 -070031import android.os.OperationCanceledException;
32import android.provider.DocumentsContract;
33import android.util.Log;
34import android.view.View;
35import android.widget.ImageView;
36import com.android.documentsui.ProviderExecutor.Preemptable;
37import java.util.function.BiConsumer;
Austin Kolander04efd4a2017-07-14 11:23:17 -070038import java.util.function.Consumer;
Austin Kolander4143e372017-07-05 14:31:37 -070039
40/**
41 * Loads a Thumbnails asynchronously then animates from the mime icon to the thumbnail
42 */
43public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implements Preemptable {
44
45 private static final String TAG = ThumbnailLoader.class.getCanonicalName();
46
47 /**
48 * Two animations applied to image views. The first is used to switch mime icon and thumbnail.
49 * The second is used when we need to update thumbnail.
50 */
51 public static final BiConsumer<View, View> ANIM_FADE_IN = (mime, thumb) -> {
52 float alpha = mime.getAlpha();
53 mime.animate().alpha(0f).start();
54 thumb.setAlpha(0f);
55 thumb.animate().alpha(alpha).start();
56 };
57 public static final BiConsumer<View, View> ANIM_NO_OP = (mime, thumb) -> {};
58
59 private final ImageView mIconThumb;
60 private final Point mThumbSize;
Austin Kolander4143e372017-07-05 14:31:37 -070061 private final Uri mUri;
Austin Kolander4143e372017-07-05 14:31:37 -070062 private final long mLastModified;
Austin Kolander04efd4a2017-07-14 11:23:17 -070063 private final Consumer<Bitmap> mCallback;
Austin Kolander4143e372017-07-05 14:31:37 -070064 private final boolean mAddToCache;
65 private final CancellationSignal mSignal;
66
67 /**
68 * @param uri - to a thumbnail.
Austin Kolander4143e372017-07-05 14:31:37 -070069 * @param iconThumb - ImageView to display the thumbnail.
70 * @param thumbSize - size of the thumbnail.
71 * @param lastModified - used for updating thumbnail caches.
Austin Kolander4143e372017-07-05 14:31:37 -070072 * @param addToCache - flag that determines if the loader saves the thumbnail to the cache.
73 */
Austin Kolander04efd4a2017-07-14 11:23:17 -070074 public ThumbnailLoader(Uri uri, ImageView iconThumb, Point thumbSize, long lastModified,
75 Consumer<Bitmap> callback, boolean addToCache) {
76
Austin Kolander4143e372017-07-05 14:31:37 -070077 mUri = uri;
Austin Kolander4143e372017-07-05 14:31:37 -070078 mIconThumb = iconThumb;
79 mThumbSize = thumbSize;
Austin Kolander4143e372017-07-05 14:31:37 -070080 mLastModified = lastModified;
Austin Kolander04efd4a2017-07-14 11:23:17 -070081 mCallback = callback;
Austin Kolander4143e372017-07-05 14:31:37 -070082 mAddToCache = addToCache;
83 mSignal = new CancellationSignal();
84 mIconThumb.setTag(this);
Austin Kolander04efd4a2017-07-14 11:23:17 -070085
Austin Kolander4143e372017-07-05 14:31:37 -070086 if (VERBOSE) Log.v(TAG, "Starting icon loader task for " + mUri);
87 }
88
89 @Override
90 public void preempt() {
91 if (VERBOSE) Log.v(TAG, "Icon loader task for " + mUri + " was cancelled.");
92 cancel(false);
93 mSignal.cancel();
94 }
95
96 @Override
97 protected Bitmap doInBackground(Uri... params) {
98 if (isCancelled()) {
99 return null;
100 }
101
102 final Context context = mIconThumb.getContext();
103 final ContentResolver resolver = context.getContentResolver();
104
105 ContentProviderClient client = null;
106 Bitmap result = null;
107 try {
108 client = DocumentsApplication.acquireUnstableProviderOrThrow(
109 resolver, mUri.getAuthority());
Jeff Sharkey2c0b4852019-02-15 15:53:47 -0700110 result = DocumentsContract.getDocumentThumbnail(wrap(client),
111 mUri, mThumbSize, mSignal);
Austin Kolander4143e372017-07-05 14:31:37 -0700112 if (result != null && mAddToCache) {
113 final ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context);
114 cache.putThumbnail(mUri, mThumbSize, result, mLastModified);
115 }
116 } catch (Exception e) {
117 if (!(e instanceof OperationCanceledException)) {
118 Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
119 }
120 } finally {
Jeff Sharkeybb68a652019-02-19 11:17:30 -0700121 FileUtils.closeQuietly(client);
Austin Kolander4143e372017-07-05 14:31:37 -0700122 }
123 return result;
124 }
125
126 @Override
127 protected void onPostExecute(Bitmap result) {
128 if (VERBOSE) Log.v(TAG, "Loader task for " + mUri + " completed");
129
Austin Kolander04efd4a2017-07-14 11:23:17 -0700130 if (mIconThumb.getTag() == this) {
131 mIconThumb.setTag(null);
132 mCallback.accept(result);
133 }
Austin Kolander4143e372017-07-05 14:31:37 -0700134 }
Austin Kolander04efd4a2017-07-14 11:23:17 -0700135}