summaryrefslogtreecommitdiff
path: root/java/src/com
diff options
context:
space:
mode:
author Andrey Yepin <ayepin@google.com> 2024-12-13 09:27:57 -0800
committer Andrey Yepin <ayepin@google.com> 2024-12-13 13:54:14 -0800
commit5fa1762976176a585bb963e9033713c705513577 (patch)
tree27dd8b836dbed4a828728f70b08d090947d4b87c /java/src/com
parentba74cdad9bb6fe8a824f787e776b0a414e8fd495 (diff)
Remove released preview_image_loader feature flag.
The flag was released with 24Q4. Unused ImageLoader implementations, CachingImagePreviewImageLoader and ImagePreviewImageLoader, are deleted. Bug: 348665058 Bug: 343819590 Test: atest IntentResolver-tests-unit Test: atest IntentResolver-tests-activity Flag: EXEMPT flag removal Change-Id: Ie6a090b724bfae9355f6c2dace5d6952140c92f3
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt110
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImageLoaderModule.kt15
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt178
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PreviewImageLoader.kt17
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt19
5 files changed, 18 insertions, 321 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt
deleted file mode 100644
index 847fcc82..00000000
--- a/java/src/com/android/intentresolver/contentpreview/CachingImagePreviewImageLoader.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2024 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.intentresolver.contentpreview
-
-import android.graphics.Bitmap
-import android.net.Uri
-import android.util.Log
-import android.util.Size
-import androidx.core.util.lruCache
-import com.android.intentresolver.inject.Background
-import com.android.intentresolver.inject.ViewModelOwned
-import javax.inject.Inject
-import javax.inject.Qualifier
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.async
-import kotlinx.coroutines.ensureActive
-import kotlinx.coroutines.sync.Semaphore
-import kotlinx.coroutines.sync.withPermit
-import kotlinx.coroutines.withContext
-
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.BINARY)
-annotation class PreviewMaxConcurrency
-
-/**
- * Implementation of [ImageLoader].
- *
- * Allows for cached or uncached loading of images and limits the number of concurrent requests.
- * Requests are automatically cancelled when they are evicted from the cache. If image loading fails
- * or the request is cancelled (e.g. by eviction), the returned [Bitmap] will be null.
- */
-class CachingImagePreviewImageLoader
-@Inject
-constructor(
- @ViewModelOwned private val scope: CoroutineScope,
- @Background private val bgDispatcher: CoroutineDispatcher,
- private val thumbnailLoader: ThumbnailLoader,
- @PreviewCacheSize cacheSize: Int,
- @PreviewMaxConcurrency maxConcurrency: Int,
-) : ImageLoader {
-
- private val semaphore = Semaphore(maxConcurrency)
-
- private val cache =
- lruCache(
- maxSize = cacheSize,
- create = { uri: Uri -> scope.async { loadUncachedImage(uri) } },
- onEntryRemoved = { evicted: Boolean, _, oldValue: Deferred<Bitmap?>, _ ->
- // If removed due to eviction, cancel the coroutine, otherwise it is the
- // responsibility
- // of the caller of [cache.remove] to cancel the removed entry when done with it.
- if (evicted) {
- oldValue.cancel()
- }
- }
- )
-
- override fun prePopulate(uriSizePairs: List<Pair<Uri, Size>>) {
- uriSizePairs.take(cache.maxSize()).map { cache[it.first] }
- }
-
- override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap? {
- return if (caching) {
- loadCachedImage(uri)
- } else {
- loadUncachedImage(uri)
- }
- }
-
- private suspend fun loadUncachedImage(uri: Uri): Bitmap? =
- withContext(bgDispatcher) {
- runCatching { semaphore.withPermit { thumbnailLoader.loadThumbnail(uri) } }
- .onFailure {
- ensureActive()
- Log.d(TAG, "Failed to load preview for $uri", it)
- }
- .getOrNull()
- }
-
- private suspend fun loadCachedImage(uri: Uri): Bitmap? =
- // [Deferred#await] is called in a [runCatching] block to catch
- // [CancellationExceptions]s so that they don't cancel the calling coroutine/scope.
- runCatching { cache[uri].await() }.getOrNull()
-
- @OptIn(ExperimentalCoroutinesApi::class)
- override fun getCachedBitmap(uri: Uri): Bitmap? =
- kotlin.runCatching { cache[uri].getCompleted() }.getOrNull()
-
- companion object {
- private const val TAG = "CachingImgPrevLoader"
- }
-}
diff --git a/java/src/com/android/intentresolver/contentpreview/ImageLoaderModule.kt b/java/src/com/android/intentresolver/contentpreview/ImageLoaderModule.kt
index 7df98cd2..7cc4458f 100644
--- a/java/src/com/android/intentresolver/contentpreview/ImageLoaderModule.kt
+++ b/java/src/com/android/intentresolver/contentpreview/ImageLoaderModule.kt
@@ -17,7 +17,6 @@
package com.android.intentresolver.contentpreview
import android.content.res.Resources
-import com.android.intentresolver.Flags.previewImageLoader
import com.android.intentresolver.R
import com.android.intentresolver.inject.ApplicationOwned
import dagger.Binds
@@ -25,25 +24,15 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
-import javax.inject.Provider
@Module
@InstallIn(ViewModelComponent::class)
interface ImageLoaderModule {
@Binds fun thumbnailLoader(thumbnailLoader: ThumbnailLoaderImpl): ThumbnailLoader
- companion object {
- @Provides
- fun imageLoader(
- imagePreviewImageLoader: Provider<ImagePreviewImageLoader>,
- previewImageLoader: Provider<PreviewImageLoader>,
- ): ImageLoader =
- if (previewImageLoader()) {
- previewImageLoader.get()
- } else {
- imagePreviewImageLoader.get()
- }
+ @Binds fun imageLoader(previewImageLoader: PreviewImageLoader): ImageLoader
+ companion object {
@Provides
@ThumbnailSize
fun thumbnailSize(@ApplicationOwned resources: Resources): Int =
diff --git a/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
deleted file mode 100644
index 379bdb37..00000000
--- a/java/src/com/android/intentresolver/contentpreview/ImagePreviewImageLoader.kt
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2023 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.intentresolver.contentpreview
-
-import android.content.ContentResolver
-import android.graphics.Bitmap
-import android.net.Uri
-import android.util.Log
-import android.util.Size
-import androidx.annotation.GuardedBy
-import androidx.annotation.VisibleForTesting
-import androidx.collection.LruCache
-import com.android.intentresolver.inject.Background
-import javax.inject.Inject
-import javax.inject.Qualifier
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CompletableDeferred
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineExceptionHandler
-import kotlinx.coroutines.CoroutineName
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Deferred
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.Semaphore
-
-private const val TAG = "ImagePreviewImageLoader"
-
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.BINARY) annotation class ThumbnailSize
-
-@Qualifier
-@MustBeDocumented
-@Retention(AnnotationRetention.BINARY)
-annotation class PreviewCacheSize
-
-/**
- * Implements preview image loading for the content preview UI. Provides requests deduplication,
- * image caching, and a limit on the number of parallel loadings.
- */
-@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
-class ImagePreviewImageLoader
-@VisibleForTesting
-constructor(
- private val scope: CoroutineScope,
- thumbnailSize: Int,
- private val contentResolver: ContentResolver,
- cacheSize: Int,
- // TODO: consider providing a scope with the dispatcher configured with
- // [CoroutineDispatcher#limitedParallelism] instead
- private val contentResolverSemaphore: Semaphore,
-) : ImageLoader {
-
- @Inject
- constructor(
- @Background dispatcher: CoroutineDispatcher,
- @ThumbnailSize thumbnailSize: Int,
- contentResolver: ContentResolver,
- @PreviewCacheSize cacheSize: Int,
- ) : this(
- CoroutineScope(
- SupervisorJob() +
- dispatcher +
- CoroutineExceptionHandler { _, exception ->
- Log.w(TAG, "Uncaught exception in ImageLoader", exception)
- } +
- CoroutineName("ImageLoader")
- ),
- thumbnailSize,
- contentResolver,
- cacheSize,
- )
-
- constructor(
- scope: CoroutineScope,
- thumbnailSize: Int,
- contentResolver: ContentResolver,
- cacheSize: Int,
- maxSimultaneousRequests: Int = 4
- ) : this(scope, thumbnailSize, contentResolver, cacheSize, Semaphore(maxSimultaneousRequests))
-
- private val thumbnailSize: Size = Size(thumbnailSize, thumbnailSize)
-
- private val lock = Any()
- @GuardedBy("lock") private val cache = LruCache<Uri, RequestRecord>(cacheSize)
- @GuardedBy("lock") private val runningRequests = HashMap<Uri, RequestRecord>()
-
- override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap? =
- loadImageAsync(uri, caching)
-
- override fun prePopulate(uriSizePairs: List<Pair<Uri, Size>>) {
- uriSizePairs.asSequence().take(cache.maxSize()).forEach { (uri, _) ->
- scope.launch { loadImageAsync(uri, caching = true) }
- }
- }
-
- private suspend fun loadImageAsync(uri: Uri, caching: Boolean): Bitmap? {
- return getRequestDeferred(uri, caching).await()
- }
-
- private fun getRequestDeferred(uri: Uri, caching: Boolean): Deferred<Bitmap?> {
- var shouldLaunchImageLoading = false
- val request =
- synchronized(lock) {
- cache[uri]
- ?: runningRequests
- .getOrPut(uri) {
- shouldLaunchImageLoading = true
- RequestRecord(uri, CompletableDeferred(), caching)
- }
- .apply { this.caching = this.caching || caching }
- }
- if (shouldLaunchImageLoading) {
- request.loadBitmapAsync()
- }
- return request.deferred
- }
-
- private fun RequestRecord.loadBitmapAsync() {
- scope
- .launch { loadBitmap() }
- .invokeOnCompletion { cause ->
- if (cause is CancellationException) {
- cancel()
- }
- }
- }
-
- private suspend fun RequestRecord.loadBitmap() {
- contentResolverSemaphore.acquire()
- val bitmap =
- try {
- contentResolver.loadThumbnail(uri, thumbnailSize, null)
- } catch (t: Throwable) {
- Log.d(TAG, "failed to load $uri preview", t)
- null
- } finally {
- contentResolverSemaphore.release()
- }
- complete(bitmap)
- }
-
- private fun RequestRecord.cancel() {
- synchronized(lock) {
- runningRequests.remove(uri)
- deferred.cancel()
- }
- }
-
- private fun RequestRecord.complete(bitmap: Bitmap?) {
- deferred.complete(bitmap)
- synchronized(lock) {
- runningRequests.remove(uri)
- if (bitmap != null && caching) {
- cache.put(uri, this)
- }
- }
- }
-
- private class RequestRecord(
- val uri: Uri,
- val deferred: CompletableDeferred<Bitmap?>,
- @GuardedBy("lock") var caching: Boolean
- )
-}
diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewImageLoader.kt b/java/src/com/android/intentresolver/contentpreview/PreviewImageLoader.kt
index b10f7ef9..1dc497b3 100644
--- a/java/src/com/android/intentresolver/contentpreview/PreviewImageLoader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/PreviewImageLoader.kt
@@ -25,6 +25,7 @@ import com.android.intentresolver.inject.Background
import com.android.intentresolver.inject.ViewModelOwned
import javax.annotation.concurrent.GuardedBy
import javax.inject.Inject
+import javax.inject.Qualifier
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -41,6 +42,18 @@ import kotlinx.coroutines.sync.withPermit
private const val TAG = "PayloadSelImageLoader"
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.BINARY) annotation class ThumbnailSize
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.BINARY)
+annotation class PreviewCacheSize
+
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.BINARY)
+annotation class PreviewMaxConcurrency
+
/**
* Implements preview image loading for the payload selection UI. Cancels preview loading for items
* that has been evicted from the cache at the expense of a possible request duplication (deemed
@@ -69,7 +82,7 @@ constructor(
if (oldRec !== newRec) {
onRecordEvictedFromCache(oldRec)
}
- }
+ },
)
override suspend fun invoke(uri: Uri, size: Size, caching: Boolean): Bitmap? =
@@ -104,7 +117,7 @@ constructor(
private suspend fun withRequestRecord(
uri: Uri,
caching: Boolean,
- block: suspend (RequestRecord) -> Bitmap?
+ block: suspend (RequestRecord) -> Bitmap?,
): Bitmap? {
val record = trackRecordRunning(uri, caching)
return try {
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
index 7f363949..6baf5935 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/viewmodel/ShareouselViewModel.kt
@@ -16,14 +16,10 @@
package com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel
import android.util.Size
-import com.android.intentresolver.Flags.previewImageLoader
import com.android.intentresolver.Flags.unselectFinalItem
-import com.android.intentresolver.contentpreview.CachingImagePreviewImageLoader
import com.android.intentresolver.contentpreview.HeadlineGenerator
import com.android.intentresolver.contentpreview.ImageLoader
import com.android.intentresolver.contentpreview.MimeTypeClassifier
-import com.android.intentresolver.contentpreview.PreviewImageLoader
-import com.android.intentresolver.contentpreview.payloadtoggle.domain.cursor.PayloadToggle
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.ChooserRequestInteractor
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.CustomActionsInteractor
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.SelectablePreviewsInteractor
@@ -37,7 +33,6 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
-import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
@@ -74,21 +69,9 @@ data class ShareouselViewModel(
object ShareouselViewModelModule {
@Provides
- @PayloadToggle
- fun imageLoader(
- cachingImageLoader: Provider<CachingImagePreviewImageLoader>,
- previewImageLoader: Provider<PreviewImageLoader>,
- ): ImageLoader =
- if (previewImageLoader()) {
- previewImageLoader.get()
- } else {
- cachingImageLoader.get()
- }
-
- @Provides
fun create(
interactor: SelectablePreviewsInteractor,
- @PayloadToggle imageLoader: ImageLoader,
+ imageLoader: ImageLoader,
actionsInteractor: CustomActionsInteractor,
headlineGenerator: HeadlineGenerator,
selectionInteractor: SelectionInteractor,