14143e37643f34775a43650a650e6a032239e1ad2Austin Kolander/*
24143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * Copyright (C) 2017 The Android Open Source Project
34143e37643f34775a43650a650e6a032239e1ad2Austin Kolander *
44143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * Licensed under the Apache License, Version 2.0 (the "License");
54143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * you may not use this file except in compliance with the License.
64143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * You may obtain a copy of the License at
74143e37643f34775a43650a650e6a032239e1ad2Austin Kolander *
84143e37643f34775a43650a650e6a032239e1ad2Austin Kolander *      http://www.apache.org/licenses/LICENSE-2.0
94143e37643f34775a43650a650e6a032239e1ad2Austin Kolander *
104143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * Unless required by applicable law or agreed to in writing, software
114143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * distributed under the License is distributed on an "AS IS" BASIS,
124143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * See the License for the specific language governing permissions and
144143e37643f34775a43650a650e6a032239e1ad2Austin Kolander * limitations under the License.
154143e37643f34775a43650a650e6a032239e1ad2Austin Kolander */
164143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderpackage com.android.documentsui;
174143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
189de5807754666ce80295d15ff681c0d4921cd5e8Felipe Lemeimport static com.android.documentsui.base.SharedMinimal.VERBOSE;
194143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
204143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.content.ContentProviderClient;
214143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.content.ContentResolver;
224143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.content.Context;
234143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.graphics.Bitmap;
244143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.graphics.Point;
254143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.net.Uri;
264143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.os.AsyncTask;
274143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.os.CancellationSignal;
284143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.os.OperationCanceledException;
294143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.provider.DocumentsContract;
304143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.util.Log;
314143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.view.View;
324143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport android.widget.ImageView;
334143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport com.android.documentsui.ProviderExecutor.Preemptable;
344143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderimport java.util.function.BiConsumer;
3504efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolanderimport java.util.function.Consumer;
364143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
374143e37643f34775a43650a650e6a032239e1ad2Austin Kolander/**
384143e37643f34775a43650a650e6a032239e1ad2Austin Kolander *  Loads a Thumbnails asynchronously then animates from the mime icon to the thumbnail
394143e37643f34775a43650a650e6a032239e1ad2Austin Kolander */
404143e37643f34775a43650a650e6a032239e1ad2Austin Kolanderpublic final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implements Preemptable {
414143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
424143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private static final String TAG = ThumbnailLoader.class.getCanonicalName();
434143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
444143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    /**
454143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * Two animations applied to image views. The first is used to switch mime icon and thumbnail.
464143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * The second is used when we need to update thumbnail.
474143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     */
484143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    public static final BiConsumer<View, View> ANIM_FADE_IN = (mime, thumb) -> {
494143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        float alpha = mime.getAlpha();
504143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mime.animate().alpha(0f).start();
514143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        thumb.setAlpha(0f);
524143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        thumb.animate().alpha(alpha).start();
534143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    };
544143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    public static final BiConsumer<View, View> ANIM_NO_OP = (mime, thumb) -> {};
554143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
564143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final ImageView mIconThumb;
574143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final Point mThumbSize;
584143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final Uri mUri;
594143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final long mLastModified;
6004efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander    private final Consumer<Bitmap> mCallback;
614143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final boolean mAddToCache;
624143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    private final CancellationSignal mSignal;
634143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
644143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    /**
654143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * @param uri - to a thumbnail.
664143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * @param iconThumb - ImageView to display the thumbnail.
674143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * @param thumbSize - size of the thumbnail.
684143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * @param lastModified - used for updating thumbnail caches.
694143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     * @param addToCache - flag that determines if the loader saves the thumbnail to the cache.
704143e37643f34775a43650a650e6a032239e1ad2Austin Kolander     */
7104efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander    public ThumbnailLoader(Uri uri, ImageView iconThumb, Point thumbSize, long lastModified,
7204efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander        Consumer<Bitmap> callback, boolean addToCache) {
7304efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander
744143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mUri = uri;
754143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mIconThumb = iconThumb;
764143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mThumbSize = thumbSize;
774143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mLastModified = lastModified;
7804efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander        mCallback = callback;
794143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mAddToCache = addToCache;
804143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mSignal = new CancellationSignal();
814143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mIconThumb.setTag(this);
8204efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander
834143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        if (VERBOSE) Log.v(TAG, "Starting icon loader task for " + mUri);
844143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    }
854143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
864143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    @Override
874143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    public void preempt() {
884143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        if (VERBOSE) Log.v(TAG, "Icon loader task for " + mUri + " was cancelled.");
894143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        cancel(false);
904143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        mSignal.cancel();
914143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    }
924143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
934143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    @Override
944143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    protected Bitmap doInBackground(Uri... params) {
954143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        if (isCancelled()) {
964143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            return null;
974143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        }
984143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
994143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        final Context context = mIconThumb.getContext();
1004143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        final ContentResolver resolver = context.getContentResolver();
1014143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
1024143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        ContentProviderClient client = null;
1034143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        Bitmap result = null;
1044143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        try {
1054143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            client = DocumentsApplication.acquireUnstableProviderOrThrow(
1064143e37643f34775a43650a650e6a032239e1ad2Austin Kolander                resolver, mUri.getAuthority());
1074143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
1084143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            if (result != null && mAddToCache) {
1094143e37643f34775a43650a650e6a032239e1ad2Austin Kolander                final ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context);
1104143e37643f34775a43650a650e6a032239e1ad2Austin Kolander                cache.putThumbnail(mUri, mThumbSize, result, mLastModified);
1114143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            }
1124143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        } catch (Exception e) {
1134143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            if (!(e instanceof OperationCanceledException)) {
1144143e37643f34775a43650a650e6a032239e1ad2Austin Kolander                Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
1154143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            }
1164143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        } finally {
1174143e37643f34775a43650a650e6a032239e1ad2Austin Kolander            ContentProviderClient.releaseQuietly(client);
1184143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        }
1194143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        return result;
1204143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    }
1214143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
1224143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    @Override
1234143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    protected void onPostExecute(Bitmap result) {
1244143e37643f34775a43650a650e6a032239e1ad2Austin Kolander        if (VERBOSE) Log.v(TAG, "Loader task for " + mUri + " completed");
1254143e37643f34775a43650a650e6a032239e1ad2Austin Kolander
12604efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander        if (mIconThumb.getTag() == this) {
12704efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander            mIconThumb.setTag(null);
12804efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander            mCallback.accept(result);
12904efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander        }
1304143e37643f34775a43650a650e6a032239e1ad2Austin Kolander    }
13104efd4af8e8cfcd814377e1913e1718c3480ed53Austin Kolander}