summaryrefslogtreecommitdiff
path: root/src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java')
-rw-r--r--src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java289
1 files changed, 0 insertions, 289 deletions
diff --git a/src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java b/src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java
deleted file mode 100644
index afceadd9a3..0000000000
--- a/src/com/android/launcher3/widget/CachingWidgetPreviewLoader.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2021 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.launcher3.widget;
-
-import android.graphics.Bitmap;
-import android.os.CancellationSignal;
-import android.util.Size;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-import androidx.collection.ArrayMap;
-import androidx.collection.ArraySet;
-
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.util.ComponentKey;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/** Wrapper around {@link DatabaseWidgetPreviewLoader} that contains caching logic. */
-public class CachingWidgetPreviewLoader implements WidgetPreviewLoader {
-
- @NonNull private final WidgetPreviewLoader mDelegate;
- @NonNull private final Map<ComponentKey, Map<Size, CacheResult>> mCache = new ArrayMap<>();
-
- public CachingWidgetPreviewLoader(@NonNull WidgetPreviewLoader delegate) {
- mDelegate = delegate;
- }
-
- /** Returns whether the preview is loaded for the item and size. */
- public boolean isPreviewLoaded(@NonNull WidgetItem item, @NonNull Size previewSize) {
- return getPreview(item, previewSize) != null;
- }
-
- /** Returns the cached preview for the item and size, or null if there is none. */
- @Nullable
- public Bitmap getPreview(@NonNull WidgetItem item, @NonNull Size previewSize) {
- CacheResult cacheResult = getCacheResult(item, previewSize);
- if (cacheResult instanceof CacheResult.Loaded) {
- return ((CacheResult.Loaded) cacheResult).mBitmap;
- } else {
- return null;
- }
- }
-
- @NonNull
- private CacheResult getCacheResult(@NonNull WidgetItem item, @NonNull Size previewSize) {
- synchronized (mCache) {
- Map<Size, CacheResult> cacheResults = mCache.get(toComponentKey(item));
- if (cacheResults == null) {
- return CacheResult.MISS;
- }
-
- return cacheResults.getOrDefault(previewSize, CacheResult.MISS);
- }
- }
-
- /**
- * Puts the result in the cache for the item and size. Returns the value previously in the
- * cache, or null if there was none.
- */
- @Nullable
- private CacheResult putCacheResult(
- @NonNull WidgetItem item,
- @NonNull Size previewSize,
- @Nullable CacheResult cacheResult) {
- ComponentKey key = toComponentKey(item);
- synchronized (mCache) {
- Map<Size, CacheResult> cacheResults = mCache.getOrDefault(key, new ArrayMap<>());
- CacheResult previous;
- if (cacheResult == null) {
- previous = cacheResults.remove(previewSize);
- if (cacheResults.isEmpty()) {
- mCache.remove(key);
- } else {
- previous = cacheResults.put(previewSize, cacheResult);
- mCache.put(key, cacheResults);
- }
- } else {
- previous = cacheResults.put(previewSize, cacheResult);
- mCache.put(key, cacheResults);
- }
- return previous;
- }
- }
-
- private void removeCacheResult(@NonNull WidgetItem item, @NonNull Size previewSize) {
- ComponentKey key = toComponentKey(item);
- synchronized (mCache) {
- Map<Size, CacheResult> cacheResults = mCache.getOrDefault(key, new ArrayMap<>());
- cacheResults.remove(previewSize);
- mCache.put(key, cacheResults);
- }
- }
-
- /**
- * Gets the preview for the widget item and size, using the value in the cache if stored.
- *
- * @return a {@link CancellationSignal}, which can cancel the request before it loads
- */
- @Override
- @UiThread
- @NonNull
- public CancellationSignal loadPreview(
- @NonNull BaseActivity activity, @NonNull WidgetItem item, @NonNull Size previewSize,
- @NonNull WidgetPreviewLoadedCallback callback) {
- CancellationSignal signal = new CancellationSignal();
- signal.setOnCancelListener(() -> {
- synchronized (mCache) {
- CacheResult cacheResult = getCacheResult(item, previewSize);
- if (!(cacheResult instanceof CacheResult.Loading)) {
- // If the key isn't actively loading, then this is a no-op. Cancelling loading
- // shouldn't clear the cache if we've already loaded.
- return;
- }
-
- CacheResult.Loading prev = (CacheResult.Loading) cacheResult;
- CacheResult.Loading updated = prev.withoutCallback(callback);
-
- if (updated.mCallbacks.isEmpty()) {
- // If the last callback was removed, then cancel the underlying request in the
- // delegate.
- prev.mCancellationSignal.cancel();
- removeCacheResult(item, previewSize);
- } else {
- // If there are other callbacks still active, then don't cancel the delegate's
- // request, just remove this callback from the set.
- putCacheResult(item, previewSize, updated);
- }
- }
- });
-
- synchronized (mCache) {
- CacheResult cacheResult = getCacheResult(item, previewSize);
- if (cacheResult instanceof CacheResult.Loaded) {
- // If the bitmap is already present in the cache, invoke the callback immediately.
- callback.onPreviewLoaded(((CacheResult.Loaded) cacheResult).mBitmap);
- return signal;
- }
-
- if (cacheResult instanceof CacheResult.Loading) {
- // If we're already loading the preview for this key, then just add the callback
- // to the set we'll call after it loads.
- CacheResult.Loading prev = (CacheResult.Loading) cacheResult;
- putCacheResult(item, previewSize, prev.withCallback(callback));
- return signal;
- }
-
- CancellationSignal delegateCancellationSignal =
- mDelegate.loadPreview(
- activity,
- item,
- previewSize,
- preview -> {
- CacheResult prev;
- synchronized (mCache) {
- prev = putCacheResult(
- item, previewSize, new CacheResult.Loaded(preview));
- }
- if (prev instanceof CacheResult.Loading) {
- // Notify each stored callback that the preview has loaded.
- ((CacheResult.Loading) prev).mCallbacks
- .forEach(c -> c.onPreviewLoaded(preview));
- } else {
- // If there isn't a loading object in the cache, then we were
- // notified before adding this signal to the cache. Just
- // call back to the provided callback, there can't be others.
- callback.onPreviewLoaded(preview);
- }
- });
- ArraySet<WidgetPreviewLoadedCallback> callbacks = new ArraySet<>();
- callbacks.add(callback);
- putCacheResult(
- item,
- previewSize,
- new CacheResult.Loading(delegateCancellationSignal, callbacks));
- }
-
- return signal;
- }
-
- /** Clears all cached previews for {@code items}, cancelling any in-progress preview loading. */
- public void clearPreviews(Iterable<WidgetItem> items) {
- List<CacheResult> previousCacheResults = new ArrayList<>();
- synchronized (mCache) {
- for (WidgetItem item : items) {
- Map<Size, CacheResult> previousMap = mCache.remove(toComponentKey(item));
- if (previousMap != null) {
- previousCacheResults.addAll(previousMap.values());
- }
- }
- }
-
- for (CacheResult previousCacheResult : previousCacheResults) {
- if (previousCacheResult instanceof CacheResult.Loading) {
- ((CacheResult.Loading) previousCacheResult).mCancellationSignal.cancel();
- }
- }
- }
-
- /** Clears all cached previews, cancelling any in-progress preview loading. */
- public void clearAll() {
- List<CacheResult> previousCacheResults;
- synchronized (mCache) {
- previousCacheResults =
- mCache
- .values()
- .stream()
- .flatMap(sizeToResult -> sizeToResult.values().stream())
- .collect(Collectors.toList());
- mCache.clear();
- }
-
- for (CacheResult previousCacheResult : previousCacheResults) {
- if (previousCacheResult instanceof CacheResult.Loading) {
- ((CacheResult.Loading) previousCacheResult).mCancellationSignal.cancel();
- }
- }
- }
-
- private abstract static class CacheResult {
- static final CacheResult MISS = new CacheResult() {};
-
- static final class Loading extends CacheResult {
- @NonNull final CancellationSignal mCancellationSignal;
- @NonNull final Set<WidgetPreviewLoadedCallback> mCallbacks;
-
- Loading(@NonNull CancellationSignal cancellationSignal,
- @NonNull Set<WidgetPreviewLoadedCallback> callbacks) {
- mCancellationSignal = cancellationSignal;
- mCallbacks = callbacks;
- }
-
- @NonNull
- Loading withCallback(@NonNull WidgetPreviewLoadedCallback callback) {
- if (mCallbacks.contains(callback)) return this;
- Set<WidgetPreviewLoadedCallback> newCallbacks =
- new ArraySet<>(mCallbacks.size() + 1);
- newCallbacks.addAll(mCallbacks);
- newCallbacks.add(callback);
- return new Loading(mCancellationSignal, newCallbacks);
- }
-
- @NonNull
- Loading withoutCallback(@NonNull WidgetPreviewLoadedCallback callback) {
- if (!mCallbacks.contains(callback)) return this;
- Set<WidgetPreviewLoadedCallback> newCallbacks =
- new ArraySet<>(mCallbacks.size() - 1);
- for (WidgetPreviewLoadedCallback existingCallback : mCallbacks) {
- if (!existingCallback.equals(callback)) {
- newCallbacks.add(existingCallback);
- }
- }
- return new Loading(mCancellationSignal, newCallbacks);
- }
- }
-
- static final class Loaded extends CacheResult {
- @NonNull final Bitmap mBitmap;
-
- Loaded(@NonNull Bitmap bitmap) {
- mBitmap = bitmap;
- }
- }
- }
-
- @NonNull
- private static ComponentKey toComponentKey(@NonNull WidgetItem item) {
- return new ComponentKey(item.componentName, item.user);
- }
-}