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

Commit eba5bb90 authored by Garfield, Tan's avatar Garfield, Tan
Browse files

Evict thumbnail caches and delay dismissing spinner on refresh finish.

Bug: 28334455
Change-Id: I338f83744d7f8b2fe9a9265dcab7ed4ec81edbfb
parent 31d9b44b
Loading
Loading
Loading
Loading
+28 −2
Original line number Diff line number Diff line
@@ -111,6 +111,13 @@ public class ThumbnailCache {
        return Result.obtainMiss();
    }

    /**
     * Puts a thumbnail for the given uri and size in to the cache.
     * @param uri the uri of the thumbnail
     * @param size the size of the thumbnail
     * @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);

@@ -130,13 +137,32 @@ public class ThumbnailCache {
        }
    }

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

        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])) {
                mCache.remove(index);
            }
        }
    }

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

        // LruCache tells us to remove a key, which should exist, so sizeMap can't be null.
        assert(sizeMap != null);
        synchronized (sizeMap) {
            sizeMap.remove(size);
+21 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -92,6 +93,7 @@ import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.ThumbnailCache;
import com.android.documentsui.clipping.DocumentClipper;
import com.android.documentsui.clipping.UrisSupplier;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
@@ -140,6 +142,9 @@ public class DirectoryFragment extends Fragment
    private static final String TAG = "DirectoryFragment";
    private static final int LOADER_ID = 42;

    private static final int CACHE_EVICT_LIMIT = 100;
    private static final int REFRESH_SPINNER_DISMISS_DELAY = 500;

    private Model mModel;
    private MultiSelectManager mSelectionMgr;
    private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
@@ -1610,6 +1615,17 @@ public class DirectoryFragment extends Fragment

    @Override
    public void onRefresh() {
        // Remove thumbnail cache. We do this not because we're worried about stale thumbnails as it
        // should be covered by last modified value we store in thumbnail cache, but rather to give
        // the user a greater sense that contents are being reloaded.
        ThumbnailCache cache = DocumentsApplication.getThumbnailCache(getContext());
        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]));
        }

        // Trigger loading
        getLoaderManager().restartLoader(LOADER_ID, null, this);
    }

@@ -1679,7 +1695,11 @@ public class DirectoryFragment extends Fragment

        mTuner.onModelLoaded(mModel, mType, mSearchMode);

        mRefreshLayout.setRefreshing(false);
        if (mRefreshLayout.isRefreshing()) {
            new Handler().postDelayed(
                    () -> mRefreshLayout.setRefreshing(false),
                    REFRESH_SPINNER_DISMISS_DELAY);
        }
    }

    @Override
+12 −0
Original line number Diff line number Diff line
@@ -176,6 +176,18 @@ public class ThumbnailCacheTest {
        assertSame(SMALL_BITMAP, result.getThumbnail());
    }

    @Test
    public void testRemoveUri() {
        mCache.putThumbnail(URI_0, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);
        mCache.putThumbnail(URI_0, SMALL_SIZE, SMALL_BITMAP, LAST_MODIFIED);
        mCache.putThumbnail(URI_1, MID_SIZE, MIDSIZE_BITMAP, LAST_MODIFIED);

        mCache.removeUri(URI_0);

        assertMiss(mCache.getThumbnail(URI_0, MID_SIZE));
        assertHitExact(mCache.getThumbnail(URI_1, MID_SIZE));
    }

    private static void assertMiss(Result result) {
        assertEquals(Result.CACHE_MISS, result.getStatus());
        assertFalse(result.isExactHit());