/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.documentsui; import static android.content.ContentResolver.wrap; import static com.android.documentsui.base.SharedMinimal.VERBOSE; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Point; import android.net.Uri; import android.os.AsyncTask; import android.os.CancellationSignal; import android.os.FileUtils; import android.os.OperationCanceledException; import android.provider.DocumentsContract; import android.util.Log; import android.view.View; import android.widget.ImageView; import com.android.documentsui.ProviderExecutor.Preemptable; import com.android.documentsui.base.UserId; import java.util.function.BiConsumer; import java.util.function.Consumer; /** * Loads a Thumbnails asynchronously then animates from the mime icon to the thumbnail */ public final class ThumbnailLoader extends AsyncTask implements Preemptable { private static final String TAG = ThumbnailLoader.class.getCanonicalName(); /** * Two animations applied to image views. The first is used to switch mime icon and thumbnail. * The second is used when we need to update thumbnail. */ public static final BiConsumer ANIM_FADE_IN = (mime, thumb) -> { float alpha = mime.getAlpha(); mime.animate().alpha(0f).start(); thumb.setAlpha(0f); thumb.animate().alpha(alpha).start(); }; public static final BiConsumer ANIM_NO_OP = (mime, thumb) -> {}; private final ImageView mIconThumb; private final Point mThumbSize; private final Uri mUri; private final UserId mUserId; private final long mLastModified; private final Consumer mCallback; private final boolean mAddToCache; private final CancellationSignal mSignal; /** * @param uri - to a thumbnail. * @param userId - user of the uri. * @param iconThumb - ImageView to display the thumbnail. * @param thumbSize - size of the thumbnail. * @param lastModified - used for updating thumbnail caches. * @param addToCache - flag that determines if the loader saves the thumbnail to the cache. */ public ThumbnailLoader(Uri uri, UserId userId, ImageView iconThumb, Point thumbSize, long lastModified, Consumer callback, boolean addToCache) { mUri = uri; mUserId = userId; mIconThumb = iconThumb; mThumbSize = thumbSize; mLastModified = lastModified; mCallback = callback; mAddToCache = addToCache; mSignal = new CancellationSignal(); mIconThumb.setTag(this); if (VERBOSE) Log.v(TAG, "Starting icon loader task for " + mUri); } @Override public void preempt() { if (VERBOSE) Log.v(TAG, "Icon loader task for " + mUri + " was cancelled."); cancel(false); mSignal.cancel(); } @Override protected Bitmap doInBackground(Uri... params) { if (isCancelled()) { return null; } final Context context = mIconThumb.getContext(); final ContentResolver resolver = mUserId.getContentResolver(context); ContentProviderClient client = null; Bitmap result = null; try { client = DocumentsApplication.acquireUnstableProviderOrThrow( resolver, mUri.getAuthority()); result = DocumentsContract.getDocumentThumbnail(wrap(client), mUri, mThumbSize, mSignal); if (result != null && mAddToCache) { final ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context); cache.putThumbnail(mUri, mUserId, mThumbSize, result, mLastModified); } } catch (Exception e) { if (!(e instanceof OperationCanceledException)) { Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e); } } finally { FileUtils.closeQuietly(client); } return result; } @Override protected void onPostExecute(Bitmap result) { if (VERBOSE) Log.v(TAG, "Loader task for " + mUri + " completed"); if (mIconThumb.getTag() == this) { mIconThumb.setTag(null); mCallback.accept(result); } } }