diff options
author | 2023-03-04 08:39:34 +0000 | |
---|---|---|
committer | 2023-03-04 08:39:34 +0000 | |
commit | 2866bb56d976e47b730a1d0e3b8501657c8f87ed (patch) | |
tree | b66125c4e9b8a546932154a9164e75c46aa272da /java/src | |
parent | 73dccff21b1a2d48f74eafdfe827db617a8651f6 (diff) | |
parent | f07b271dede54d16407aa14dc111acba9beaab52 (diff) |
Merge "Add image caching to ImagePreviewImageLoader" into tm-qpr-dev am: d9a9fbb834 am: d2cb6ac684 am: f8bc5e7fd1 am: f07b271ded
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/IntentResolver/+/21487231
Change-Id: I9e12d1c8251b61bdff8d3d8fe2ae5ee62d18c482
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'java/src')
4 files changed, 50 insertions, 9 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 4cfda0a9..3a7c892e 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -85,6 +85,7 @@ import com.android.intentresolver.chooser.MultiDisplayResolveInfo; import com.android.intentresolver.chooser.TargetInfo; import com.android.intentresolver.flags.FeatureFlagRepository; import com.android.intentresolver.flags.FeatureFlagRepositoryFactory; +import com.android.intentresolver.flags.Flags; import com.android.intentresolver.grid.ChooserGridAdapter; import com.android.intentresolver.grid.DirectShareViewHolder; import com.android.intentresolver.model.AbstractResolverComparator; @@ -1338,7 +1339,15 @@ public class ChooserActivity extends ResolverActivity implements @VisibleForTesting protected ImageLoader createPreviewImageLoader() { - return new ImagePreviewImageLoader(this, getLifecycle()); + final int cacheSize; + if (mFeatureFlagRepository.isEnabled(Flags.SHARESHEET_SCROLLABLE_IMAGE_PREVIEW)) { + float chooserWidth = getResources().getDimension(R.dimen.chooser_width); + float imageWidth = getResources().getDimension(R.dimen.chooser_preview_image_width); + cacheSize = (int) (Math.ceil(chooserWidth / imageWidth) + 2); + } else { + cacheSize = 3; + } + return new ImagePreviewImageLoader(this, getLifecycle(), cacheSize); } private void handleScroll(View view, int x, int y, int oldx, int oldy) { diff --git a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java index 61affdf3..60ea0122 100644 --- a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java @@ -414,6 +414,7 @@ public final class ChooserContentPreviewUi { actionFactory); imagePreview.setTransitionElementStatusCallback(transitionElementStatusCallback); imagePreview.setImages(imageUris, imageLoader); + imageLoader.prePopulate(imageUris); return contentPreviewLayout; } diff --git a/java/src/com/android/intentresolver/ImageLoader.kt b/java/src/com/android/intentresolver/ImageLoader.kt index 13b1dd9c..0ed8b122 100644 --- a/java/src/com/android/intentresolver/ImageLoader.kt +++ b/java/src/com/android/intentresolver/ImageLoader.kt @@ -22,4 +22,5 @@ import java.util.function.Consumer interface ImageLoader : suspend (Uri) -> Bitmap? { fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) + fun prePopulate(uris: List<Uri>) } diff --git a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt index 40081c87..7b6651a2 100644 --- a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt +++ b/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt @@ -20,21 +20,34 @@ import android.content.Context import android.graphics.Bitmap import android.net.Uri import android.util.Size +import androidx.annotation.GuardedBy +import androidx.annotation.VisibleForTesting +import androidx.collection.LruCache import androidx.lifecycle.Lifecycle import androidx.lifecycle.coroutineScope +import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import java.util.function.Consumer -internal class ImagePreviewImageLoader @JvmOverloads constructor( +@VisibleForTesting +class ImagePreviewImageLoader @JvmOverloads constructor( private val context: Context, private val lifecycle: Lifecycle, + cacheSize: Int, private val dispatcher: CoroutineDispatcher = Dispatchers.IO ) : ImageLoader { + private val thumbnailSize: Size = + context.resources.getDimensionPixelSize(R.dimen.chooser_preview_image_max_dimen).let { + Size(it, it) + } + + @GuardedBy("self") + private val cache = LruCache<Uri, CompletableDeferred<Bitmap?>>(cacheSize) + override suspend fun invoke(uri: Uri): Bitmap? = loadImageAsync(uri) override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) { @@ -46,12 +59,29 @@ internal class ImagePreviewImageLoader @JvmOverloads constructor( } } - private suspend fun loadImageAsync(uri: Uri): Bitmap? { - val size = context.resources.getDimensionPixelSize(R.dimen.chooser_preview_image_max_dimen) - return withContext(dispatcher) { - runCatching { - context.contentResolver.loadThumbnail(uri, Size(size, size), null) - }.getOrNull() + override fun prePopulate(uris: List<Uri>) { + uris.asSequence().take(cache.maxSize()).forEach { uri -> + lifecycle.coroutineScope.launch { + loadImageAsync(uri) + } } } + + private suspend fun loadImageAsync(uri: Uri): Bitmap? { + return synchronized(cache) { + cache.get(uri) ?: CompletableDeferred<Bitmap?>().also { result -> + cache.put(uri, result) + lifecycle.coroutineScope.launch(dispatcher) { + result.loadBitmap(uri) + } + } + }.await() + } + + private fun CompletableDeferred<Bitmap?>.loadBitmap(uri: Uri) { + val bitmap = runCatching { + context.contentResolver.loadThumbnail(uri, thumbnailSize, null) + }.getOrNull() + complete(bitmap) + } } |