Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72ddaf0d authored by Kelvin Kwan's avatar Kelvin Kwan Committed by Android (Google) Code Review
Browse files

Merge "Load and cache thumbnail with correct user"

parents 55dccc9d 4cf7314f
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static com.android.documentsui.base.DocumentInfo.getCursorString;
import static com.android.documentsui.base.SharedMinimal.DEBUG;
import static com.android.documentsui.base.SharedMinimal.VERBOSE;

import androidx.annotation.IntDef;
import android.app.AuthenticationRequiredException;
import android.database.Cursor;
import android.net.Uri;
@@ -29,6 +28,7 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.selection.Selection;
@@ -37,6 +37,7 @@ import com.android.documentsui.base.DocumentFilters;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.EventListener;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.UserId;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -258,6 +259,11 @@ public class Model {
        return DocumentInfo.getUri(cursor);
    }

    public UserId getItemUserId(String modelId) {
        final Cursor cursor = getItem(modelId);
        return DocumentInfo.getUserId(cursor);
    }

    /**
     * @return An ordered array of model IDs representing the documents in the model. It is sorted
     *         according to the current sort order, which was set by the last model update.
+102 −29
Original line number Diff line number Diff line
@@ -16,23 +16,26 @@

package com.android.documentsui;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.core.util.Pools;
import static androidx.core.util.Preconditions.checkNotNull;

import android.content.ComponentCallbacks2;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.net.Uri;
import android.util.LruCache;
import android.util.Pair;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.core.util.Pools;

import com.android.documentsui.base.Shared;
import com.android.documentsui.base.UserId;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;

/**
@@ -44,10 +47,10 @@ public class ThumbnailCache {
    private static final SizeComparator SIZE_COMPARATOR = new SizeComparator();

    /**
     * A 2-dimensional index into {@link #mCache} entries. Pair<Uri, Point> is the key to
     * A 2-dimensional index into {@link #mCache} entries. {@link CacheKey} is the key to
     * {@link #mCache}. TreeMap is used to search the closest size to a given size and a given uri.
     */
    private final HashMap<Uri, TreeMap<Point, Pair<Uri, Point>>> mSizeIndex;
    private final HashMap<SizeIndexKey, TreeMap<Point, CacheKey>> mSizeIndex;
    private final Cache mCache;

    /**
@@ -67,16 +70,16 @@ public class ThumbnailCache {
     * @param size the desired size of the thumbnail
     * @return the thumbnail result
     */
    public Result getThumbnail(Uri uri, Point size) {
        TreeMap<Point, Pair<Uri, Point>> sizeMap;
        sizeMap = mSizeIndex.get(uri);
    public Result getThumbnail(Uri uri, UserId userId, Point size) {
        TreeMap<Point, CacheKey> sizeMap;
        sizeMap = mSizeIndex.get(new SizeIndexKey(uri, userId));
        if (sizeMap == null || sizeMap.isEmpty()) {
            // There is not any thumbnail for this uri.
            return Result.obtainMiss();
        }

        // Look for thumbnail of the same size.
        Pair<Uri, Point> cacheKey = sizeMap.get(size);
        CacheKey cacheKey = sizeMap.get(size);
        if (cacheKey != null) {
            Entry entry = mCache.get(cacheKey);
            if (entry != null) {
@@ -121,15 +124,16 @@ public class ThumbnailCache {
     * @param thumbnail the thumbnail to put in cache
     * @param lastModified last modified value of the thumbnail to track its validity
     */
    public void putThumbnail(Uri uri, Point size, Bitmap thumbnail, long lastModified) {
        Pair<Uri, Point> cacheKey = Pair.create(uri, size);
    public void putThumbnail(Uri uri, UserId userId, Point size, Bitmap thumbnail,
            long lastModified) {
        CacheKey cacheKey = new CacheKey(uri, userId, size);

        TreeMap<Point, Pair<Uri, Point>> sizeMap;
        TreeMap<Point, CacheKey> sizeMap;
        synchronized (mSizeIndex) {
            sizeMap = mSizeIndex.get(uri);
            sizeMap = mSizeIndex.get(new SizeIndexKey(uri, userId));
            if (sizeMap == null) {
                sizeMap = new TreeMap<>(SIZE_COMPARATOR);
                mSizeIndex.put(uri, sizeMap);
                mSizeIndex.put(new SizeIndexKey(uri, userId), sizeMap);
            }
        }

@@ -141,34 +145,34 @@ public class ThumbnailCache {
    }

    /**
     * Removes all thumbnail cache associated to the given uri.
     * Removes all thumbnail cache associated to the given uri and user.
     * @param uri the uri which thumbnail cache to remove
     */
    public void removeUri(Uri uri) {
        TreeMap<Point, Pair<Uri, Point>> sizeMap;
    public void removeUri(Uri uri, UserId userId) {
        TreeMap<Point, CacheKey> sizeMap;
        synchronized (mSizeIndex) {
            sizeMap = mSizeIndex.get(uri);
            sizeMap = mSizeIndex.get(new SizeIndexKey(uri, userId));
        }

        if (sizeMap != null) {
            // Create an array to hold all values to avoid ConcurrentModificationException because
            // removeKey() will be called by LruCache but we can't modify the map while we're
            // iterating over the collection of values.
            for (Pair<Uri, Point> index : sizeMap.values().toArray(new Pair[0])) {
            for (CacheKey index : sizeMap.values().toArray(new CacheKey[0])) {
                mCache.remove(index);
            }
        }
    }

    private void removeKey(Uri uri, Point size) {
        TreeMap<Point, Pair<Uri, Point>> sizeMap;
    private void removeKey(CacheKey cacheKey) {
        TreeMap<Point, CacheKey> sizeMap;
        synchronized (mSizeIndex) {
            sizeMap = mSizeIndex.get(uri);
            sizeMap = mSizeIndex.get(new SizeIndexKey(cacheKey.uri, cacheKey.userId));
        }

        assert (sizeMap != null);
        synchronized (sizeMap) {
            sizeMap.remove(size);
            sizeMap.remove(cacheKey.point);
        }
    }

@@ -291,22 +295,22 @@ public class ThumbnailCache {
        }
    }

    private final class Cache extends LruCache<Pair<Uri, Point>, Entry> {
    private final class Cache extends LruCache<CacheKey, Entry> {

        private Cache(int maxSizeBytes) {
            super(maxSizeBytes);
        }

        @Override
        protected int sizeOf(Pair<Uri, Point> key, Entry value) {
        protected int sizeOf(CacheKey key, Entry value) {
            return value.mThumbnail.getByteCount();
        }

        @Override
        protected void entryRemoved(
                boolean evicted, Pair<Uri, Point> key, Entry oldValue, Entry newValue) {
                boolean evicted, CacheKey key, Entry oldValue, Entry newValue) {
            if (newValue == null) {
                removeKey(key.first, key.second);
                removeKey(key);
            }
        }
    }
@@ -318,4 +322,73 @@ public class ThumbnailCache {
            return size0.x - size1.x;
        }
    }

    private static class SizeIndexKey {
        final Uri uri;
        final UserId userId;

        SizeIndexKey(Uri uri, UserId userId) {
            this.uri = checkNotNull(uri);
            this.userId = checkNotNull(userId);
        }

        @Override
        public boolean equals(Object o) {
            if (o == null) {
                return false;
            }

            if (this == o) {
                return true;
            }

            if (o instanceof SizeIndexKey) {
                SizeIndexKey other = (SizeIndexKey) o;
                return Objects.equals(uri, other.uri)
                        && Objects.equals(userId, other.userId);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(uri, userId);
        }
    }

    private static class CacheKey {
        final Uri uri;
        final UserId userId;
        final Point point;

        CacheKey(Uri uri, UserId userId, Point point) {
            this.uri = checkNotNull(uri);
            this.userId = checkNotNull(userId);
            this.point = checkNotNull(point);
        }

        @Override
        public boolean equals(Object o) {
            if (o == null) {
                return false;
            }

            if (this == o) {
                return true;
            }

            if (o instanceof CacheKey) {
                CacheKey other = (CacheKey) o;
                return Objects.equals(uri, other.uri)
                        && Objects.equals(userId, other.userId)
                        && Objects.equals(point, other.point);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(uri, userId, point);
        }
    }
}
+10 −4
Original line number Diff line number Diff line
@@ -33,7 +33,10 @@ 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;

@@ -59,6 +62,7 @@ public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implemen
    private final ImageView mIconThumb;
    private final Point mThumbSize;
    private final Uri mUri;
    private final UserId mUserId;
    private final long mLastModified;
    private final Consumer<Bitmap> mCallback;
    private final boolean mAddToCache;
@@ -66,15 +70,17 @@ public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implemen

    /**
     * @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, ImageView iconThumb, Point thumbSize, long lastModified,
        Consumer<Bitmap> callback, boolean addToCache) {
    public ThumbnailLoader(Uri uri, UserId userId, ImageView iconThumb, Point thumbSize,
            long lastModified, Consumer<Bitmap> callback, boolean addToCache) {

        mUri = uri;
        mUserId = userId;
        mIconThumb = iconThumb;
        mThumbSize = thumbSize;
        mLastModified = lastModified;
@@ -100,7 +106,7 @@ public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implemen
        }

        final Context context = mIconThumb.getContext();
        final ContentResolver resolver = context.getContentResolver();
        final ContentResolver resolver = mUserId.getContentResolver(context);

        ContentProviderClient client = null;
        Bitmap result = null;
@@ -111,7 +117,7 @@ public final class ThumbnailLoader extends AsyncTask<Uri, Void, Bitmap> implemen
                    mUri, mThumbSize, mSignal);
            if (result != null && mAddToCache) {
                final ThumbnailCache cache = DocumentsApplication.getThumbnailCache(context);
                cache.putThumbnail(mUri, mThumbSize, result, mLastModified);
                cache.putThumbnail(mUri, mUserId, mThumbSize, result, mLastModified);
            }
        } catch (Exception e) {
            if (!(e instanceof OperationCanceledException)) {
+4 −0
Original line number Diff line number Diff line
@@ -418,6 +418,10 @@ public class DocumentInfo implements Durable, Parcelable {
            getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
    }

    public static UserId getUserId(Cursor cursor) {
        return UserId.of(getCursorInt(cursor, RootCursorWrapper.COLUMN_USER_ID));
    }

    public static void addMimeTypes(ContentResolver resolver, Uri uri, Set<String> mimeTypes) {
        assert(uri != null);
        if ("content".equals(uri.getScheme())) {
+1 −1
Original line number Diff line number Diff line
@@ -1161,7 +1161,7 @@ public class DirectoryFragment extends Fragment implements SwipeRefreshLayout.On
        String[] ids = mModel.getModelIds();
        int numOfEvicts = Math.min(ids.length, CACHE_EVICT_LIMIT);
        for (int i = 0; i < numOfEvicts; ++i) {
            cache.removeUri(mModel.getItemUri(ids[i]));
            cache.removeUri(mModel.getItemUri(ids[i]), mModel.getItemUserId(ids[i]));
        }

        final DocumentInfo doc = mActivity.getCurrentDirectory();
Loading