diff options
| author | 2023-01-10 22:18:22 +0000 | |
|---|---|---|
| committer | 2023-01-10 22:18:22 +0000 | |
| commit | 9839aa762eb456254e55cf9f1852452a5c841112 (patch) | |
| tree | 345483302a9f06a278f91cd9d200ed1dba1abd2f /java/src/com | |
| parent | 49b65f54be53ec48d53a550e783759100e8812dc (diff) | |
| parent | a9a6a1c4494529fe2a8e1672d7f6c56aca978743 (diff) | |
Merge "EnterTransitionAnimationDelegate to track animation hold timeout" into tm-qpr-dev
Diffstat (limited to 'java/src/com')
7 files changed, 157 insertions, 242 deletions
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 55904fc1..7da0b96b 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -55,7 +55,6 @@ import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.database.Cursor; -import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -75,7 +74,6 @@ import android.service.chooser.ChooserAction; import android.service.chooser.ChooserTarget; import android.text.TextUtils; import android.util.Log; -import android.util.Size; import android.util.Slog; import android.util.SparseArray; import android.view.View; @@ -117,7 +115,6 @@ import com.android.internal.util.FrameworkStatsLog; import com.google.common.collect.ImmutableList; import java.io.File; -import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.Collator; @@ -246,7 +243,7 @@ public class ChooserActivity extends ResolverActivity implements private final ExecutorService mBackgroundThreadPoolExecutor = Executors.newFixedThreadPool(5); @Nullable - private ChooserContentPreviewCoordinator mPreviewCoordinator; + private ImageLoader mPreviewImageLoader; private int mScrollStatus = SCROLL_STATUS_IDLE; @@ -296,10 +293,7 @@ public class ChooserActivity extends ResolverActivity implements mChooserRequest.getTargetIntentFilter()), mChooserRequest.getTargetIntentFilter()); - mPreviewCoordinator = new ChooserContentPreviewCoordinator( - mBackgroundThreadPoolExecutor, - this, - () -> mEnterTransitionAnimationDelegate.markImagePreviewReady(false)); + mPreviewImageLoader = createPreviewImageLoader(); super.onCreate( savedInstanceState, @@ -712,9 +706,7 @@ public class ChooserActivity extends ResolverActivity implements * @param parent reference to the parent container where the view should be attached to * @return content preview view */ - protected ViewGroup createContentPreviewView( - ViewGroup parent, - ChooserContentPreviewUi.ContentPreviewCoordinator previewCoordinator) { + protected ViewGroup createContentPreviewView(ViewGroup parent, ImageLoader imageLoader) { Intent targetIntent = getTargetIntent(); int previewType = ChooserContentPreviewUi.findPreferredContentPreview( targetIntent, getContentResolver(), this::isImageType); @@ -763,7 +755,7 @@ public class ChooserActivity extends ResolverActivity implements ? R.layout.scrollable_chooser_action_row : R.layout.chooser_action_row, parent, - previewCoordinator, + imageLoader, mEnterTransitionAnimationDelegate::markImagePreviewReady, getContentResolver(), this::isImageType); @@ -1528,7 +1520,7 @@ public class ChooserActivity extends ResolverActivity implements @Override public View buildContentPreview(ViewGroup parent) { - return createContentPreviewView(parent, mPreviewCoordinator); + return createContentPreviewView(parent, mPreviewImageLoader); } @Override @@ -1643,17 +1635,8 @@ public class ChooserActivity extends ResolverActivity implements } @VisibleForTesting - protected Bitmap loadThumbnail(Uri uri, Size size) { - if (uri == null || size == null) { - return null; - } - - try { - return getContentResolver().loadThumbnail(uri, size, null); - } catch (IOException | NullPointerException | SecurityException ex) { - getChooserActivityLogger().logContentPreviewWarning(uri); - } - return null; + protected ImageLoader createPreviewImageLoader() { + return new ImagePreviewImageLoader(this, getLifecycle()); } private void handleScroll(View view, int x, int y, int oldx, int oldy) { @@ -2010,7 +1993,7 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup contentPreviewContainer = findViewById(com.android.internal.R.id.content_preview_container); if (contentPreviewContainer.getChildCount() == 0) { ViewGroup contentPreviewView = - createContentPreviewView(contentPreviewContainer, mPreviewCoordinator); + createContentPreviewView(contentPreviewContainer, mPreviewImageLoader); contentPreviewContainer.addView(contentPreviewView); } } diff --git a/java/src/com/android/intentresolver/ChooserContentPreviewCoordinator.java b/java/src/com/android/intentresolver/ChooserContentPreviewCoordinator.java deleted file mode 100644 index 0b8dbe35..00000000 --- a/java/src/com/android/intentresolver/ChooserContentPreviewCoordinator.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Handler; -import android.util.Size; - -import androidx.annotation.MainThread; -import androidx.annotation.Nullable; - -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; - -import java.util.concurrent.ExecutorService; -import java.util.function.Consumer; - -/** - * Delegate to manage deferred resource loads for content preview assets, while - * implementing Chooser's application logic for determining timeout/success/failure conditions. - */ -public class ChooserContentPreviewCoordinator implements - ChooserContentPreviewUi.ContentPreviewCoordinator { - public ChooserContentPreviewCoordinator( - ExecutorService backgroundExecutor, - ChooserActivity chooserActivity, - Runnable onFailCallback) { - this.mBackgroundExecutor = MoreExecutors.listeningDecorator(backgroundExecutor); - this.mChooserActivity = chooserActivity; - this.mOnFailCallback = onFailCallback; - - this.mImageLoadTimeoutMillis = - chooserActivity.getResources().getInteger(R.integer.config_shortAnimTime); - } - - @Override - public void loadImage(final Uri imageUri, final Consumer<Bitmap> callback) { - final int size = mChooserActivity.getResources().getDimensionPixelSize( - R.dimen.chooser_preview_image_max_dimen); - - // TODO: apparently this timeout is only used for not holding shared element transition - // animation for too long. If so, we already have a better place for it - // EnterTransitionAnimationDelegate. - mHandler.postDelayed(this::onWatchdogTimeout, mImageLoadTimeoutMillis); - - ListenableFuture<Bitmap> bitmapFuture = mBackgroundExecutor.submit( - () -> mChooserActivity.loadThumbnail(imageUri, new Size(size, size))); - - Futures.addCallback( - bitmapFuture, - new FutureCallback<Bitmap>() { - @Override - public void onSuccess(Bitmap loadedBitmap) { - try { - callback.accept(loadedBitmap); - onLoadCompleted(loadedBitmap); - } catch (Exception e) { /* unimportant */ } - } - - @Override - public void onFailure(Throwable t) { - callback.accept(null); - } - }, - mHandler::post); - } - - private final ChooserActivity mChooserActivity; - private final ListeningExecutorService mBackgroundExecutor; - private final Runnable mOnFailCallback; - private final int mImageLoadTimeoutMillis; - - // TODO: this uses a `Handler` because there doesn't seem to be a straightforward way to get a - // `ScheduledExecutorService` that posts to the UI thread unless we use Dagger. Eventually we'll - // use Dagger and can inject this as a `@UiThread ScheduledExecutorService`. - private final Handler mHandler = new Handler(); - - private boolean mAtLeastOneLoaded = false; - - @MainThread - private void onWatchdogTimeout() { - if (mChooserActivity.isFinishing()) { - return; - } - - // If at least one image loads within the timeout period, allow other loads to continue. - if (!mAtLeastOneLoaded) { - mOnFailCallback.run(); - } - } - - @MainThread - private void onLoadCompleted(@Nullable Bitmap loadedBitmap) { - if (mChooserActivity.isFinishing()) { - return; - } - - // TODO: the following logic can be described as "invoke the fail callback when the first - // image loading has failed". Historically, before we had switched from a single-threaded - // pool to a multi-threaded pool, we first loaded the transition element's image (the image - // preview is the only case when those callbacks matter) and aborting the animation on it's - // failure was reasonable. With the multi-thread pool, the first result may belong to any - // image and thus we can falsely abort the animation. - // Now, when we track the transition view state directly and after the timeout logic will - // be moved into ChooserActivity$EnterTransitionAnimationDelegate, we can just get rid of - // the fail callback and the following logic altogether. - mAtLeastOneLoaded |= loadedBitmap != null; - boolean wholeBatchFailed = !mAtLeastOneLoaded; - - if (wholeBatchFailed) { - mOnFailCallback.run(); - } - } -} diff --git a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java index daded28b..88f9006f 100644 --- a/java/src/com/android/intentresolver/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/ChooserContentPreviewUi.java @@ -72,21 +72,6 @@ public final class ChooserContentPreviewUi { private static final int IMAGE_FADE_IN_MILLIS = 150; /** - * Delegate to handle background resource loads that are dependencies of content previews. - */ - public interface ContentPreviewCoordinator { - /** - * Request that an image be loaded in the background and set into a view. - * - * @param imageUri The {@link Uri} of the image to load. - * - * TODO: it looks like clients are probably capable of passing the view directly, but the - * deferred computation here is a closer match to the legacy model for now. - */ - void loadImage(Uri imageUri, Consumer<Bitmap> callback); - } - - /** * Delegate to build the default system action buttons to display in the preview layout, if/when * they're determined to be appropriate for the particular preview we display. * TODO: clarify why action buttons are part of preview logic. @@ -184,7 +169,7 @@ public final class ChooserContentPreviewUi { ActionFactory actionFactory, @LayoutRes int actionRowLayout, ViewGroup parent, - ContentPreviewCoordinator previewCoord, + ImageLoader previewImageLoader, Consumer<Boolean> onTransitionTargetReady, ContentResolver contentResolver, ImageMimeTypeClassifier imageClassifier) { @@ -200,7 +185,7 @@ public final class ChooserContentPreviewUi { createTextPreviewActions(actionFactory), customActions), parent, - previewCoord, + previewImageLoader, actionRowLayout); break; case CONTENT_PREVIEW_IMAGE: @@ -211,7 +196,7 @@ public final class ChooserContentPreviewUi { createImagePreviewActions(actionFactory), customActions), parent, - previewCoord, + previewImageLoader, onTransitionTargetReady, contentResolver, imageClassifier, @@ -226,7 +211,7 @@ public final class ChooserContentPreviewUi { createFilePreviewActions(actionFactory), customActions), parent, - previewCoord, + previewImageLoader, contentResolver, actionRowLayout); break; @@ -268,7 +253,7 @@ public final class ChooserContentPreviewUi { LayoutInflater layoutInflater, List<ActionRow.Action> actions, ViewGroup parent, - ContentPreviewCoordinator previewCoord, + ImageLoader previewImageLoader, @LayoutRes int actionRowLayout) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_text, parent, false); @@ -313,7 +298,7 @@ public final class ChooserContentPreviewUi { if (previewThumbnail == null) { previewThumbnailView.setVisibility(View.GONE); } else { - previewCoord.loadImage( + previewImageLoader.loadImage( previewThumbnail, (bitmap) -> updateViewWithImage( contentPreviewLayout.findViewById( @@ -340,7 +325,7 @@ public final class ChooserContentPreviewUi { LayoutInflater layoutInflater, List<ActionRow.Action> actions, ViewGroup parent, - ContentPreviewCoordinator previewCoord, + ImageLoader imageLoader, Consumer<Boolean> onTransitionTargetReady, ContentResolver contentResolver, ImageMimeTypeClassifier imageClassifier, @@ -355,7 +340,6 @@ public final class ChooserContentPreviewUi { actionRow.setActions(actions); } - final ImagePreviewImageLoader imageLoader = new ImagePreviewImageLoader(previewCoord); final ArrayList<Uri> imageUris = new ArrayList<>(); String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -408,59 +392,74 @@ public final class ChooserContentPreviewUi { LayoutInflater layoutInflater, List<ActionRow.Action> actions, ViewGroup parent, - ContentPreviewCoordinator previewCoord, + ImageLoader imageLoader, ContentResolver contentResolver, @LayoutRes int actionRowLayout) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_file, parent, false); + List<Uri> uris = extractFileUris(targetIntent); + final int uriCount = uris.size(); + + if (uriCount == 0) { + contentPreviewLayout.setVisibility(View.GONE); + Log.i(TAG, + "Appears to be no uris available in EXTRA_STREAM, removing " + + "preview area"); + return contentPreviewLayout; + } + + if (uriCount == 1) { + loadFileUriIntoView(uris.get(0), contentPreviewLayout, imageLoader, contentResolver); + } else { + FileInfo fileInfo = extractFileInfo(uris.get(0), contentResolver); + int remUriCount = uriCount - 1; + Map<String, Object> arguments = new HashMap<>(); + arguments.put(PLURALS_COUNT, remUriCount); + arguments.put(PLURALS_FILE_NAME, fileInfo.name); + String fileName = + PluralsMessageFormatter.format(resources, arguments, R.string.file_count); + + TextView fileNameView = contentPreviewLayout.findViewById( + com.android.internal.R.id.content_preview_filename); + fileNameView.setText(fileName); + + View thumbnailView = contentPreviewLayout.findViewById( + com.android.internal.R.id.content_preview_file_thumbnail); + thumbnailView.setVisibility(View.GONE); + + ImageView fileIconView = contentPreviewLayout.findViewById( + com.android.internal.R.id.content_preview_file_icon); + fileIconView.setVisibility(View.VISIBLE); + fileIconView.setImageResource(R.drawable.ic_file_copy); + } + final ActionRow actionRow = inflateActionRow(contentPreviewLayout, actionRowLayout); if (actionRow != null) { actionRow.setActions(actions); } - String action = targetIntent.getAction(); - if (Intent.ACTION_SEND.equals(action)) { + return contentPreviewLayout; + } + + private static List<Uri> extractFileUris(Intent targetIntent) { + List<Uri> uris = new ArrayList<>(); + if (Intent.ACTION_SEND.equals(targetIntent.getAction())) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); - loadFileUriIntoView(uri, contentPreviewLayout, previewCoord, contentResolver); + if (uri != null) { + uris.add(uri); + } } else { - List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); - int uriCount = uris.size(); - - if (uriCount == 0) { - contentPreviewLayout.setVisibility(View.GONE); - Log.i(TAG, - "Appears to be no uris available in EXTRA_STREAM, removing " - + "preview area"); - return contentPreviewLayout; - } else if (uriCount == 1) { - loadFileUriIntoView( - uris.get(0), contentPreviewLayout, previewCoord, contentResolver); - } else { - FileInfo fileInfo = extractFileInfo(uris.get(0), contentResolver); - int remUriCount = uriCount - 1; - Map<String, Object> arguments = new HashMap<>(); - arguments.put(PLURALS_COUNT, remUriCount); - arguments.put(PLURALS_FILE_NAME, fileInfo.name); - String fileName = - PluralsMessageFormatter.format(resources, arguments, R.string.file_count); - - TextView fileNameView = contentPreviewLayout.findViewById( - com.android.internal.R.id.content_preview_filename); - fileNameView.setText(fileName); - - View thumbnailView = contentPreviewLayout.findViewById( - com.android.internal.R.id.content_preview_file_thumbnail); - thumbnailView.setVisibility(View.GONE); - - ImageView fileIconView = contentPreviewLayout.findViewById( - com.android.internal.R.id.content_preview_file_icon); - fileIconView.setVisibility(View.VISIBLE); - fileIconView.setImageResource(R.drawable.ic_file_copy); + List<Uri> receivedUris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + if (receivedUris != null) { + for (Uri uri : receivedUris) { + if (uri != null) { + uris.add(uri); + } + } } } - - return contentPreviewLayout; + return uris; } private static List<ActionRow.Action> createFilePreviewActions(ActionFactory actionFactory) { @@ -494,7 +493,7 @@ public final class ChooserContentPreviewUi { private static void loadFileUriIntoView( final Uri uri, final View parent, - final ContentPreviewCoordinator previewCoord, + final ImageLoader imageLoader, final ContentResolver contentResolver) { FileInfo fileInfo = extractFileInfo(uri, contentResolver); @@ -503,7 +502,7 @@ public final class ChooserContentPreviewUi { fileNameView.setText(fileInfo.name); if (fileInfo.hasThumbnail) { - previewCoord.loadImage( + imageLoader.loadImage( uri, (bitmap) -> updateViewWithImage( parent.findViewById( diff --git a/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt b/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt index a0bf61b6..31aeea44 100644 --- a/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt +++ b/java/src/com/android/intentresolver/EnterTransitionAnimationDelegate.kt @@ -15,23 +15,30 @@ */ package com.android.intentresolver -import android.app.Activity import android.app.SharedElementCallback import android.view.View -import com.android.intentresolver.widget.ResolverDrawerLayout +import androidx.activity.ComponentActivity +import androidx.lifecycle.lifecycleScope +import com.android.internal.annotations.VisibleForTesting +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import java.util.function.Supplier /** * A helper class to track app's readiness for the scene transition animation. * The app is ready when both the image is laid out and the drawer offset is calculated. */ -internal class EnterTransitionAnimationDelegate( - private val activity: Activity, - private val resolverDrawerLayoutSupplier: Supplier<ResolverDrawerLayout?> +@VisibleForTesting +class EnterTransitionAnimationDelegate( + private val activity: ComponentActivity, + private val transitionTargetSupplier: Supplier<View?>, ) : View.OnLayoutChangeListener { + private var removeSharedElements = false private var previewReady = false private var offsetCalculated = false + private var timeoutJob: Job? = null init { activity.setEnterSharedElementCallback( @@ -46,9 +53,23 @@ internal class EnterTransitionAnimationDelegate( }) } - fun postponeTransition() = activity.postponeEnterTransition() + fun postponeTransition() { + activity.postponeEnterTransition() + timeoutJob = activity.lifecycleScope.launch { + delay(activity.resources.getInteger(R.integer.config_shortAnimTime).toLong()) + onTimeout() + } + } + + private fun onTimeout() { + // We only mark the preview readiness and not the offset readiness + // (see [#markOffsetCalculated()]) as this is what legacy logic, effectively, did. We might + // want to review that aspect separately. + markImagePreviewReady(runTransitionAnimation = false) + } fun markImagePreviewReady(runTransitionAnimation: Boolean) { + timeoutJob?.cancel() if (!runTransitionAnimation) { removeSharedElements = true } @@ -77,7 +98,7 @@ internal class EnterTransitionAnimationDelegate( } private fun maybeStartListenForLayout() { - val drawer = resolverDrawerLayoutSupplier.get() + val drawer = transitionTargetSupplier.get() if (previewReady && offsetCalculated && drawer != null) { if (drawer.isInLayout) { startPostponedEnterTransition() diff --git a/java/src/com/android/intentresolver/ImageLoader.kt b/java/src/com/android/intentresolver/ImageLoader.kt new file mode 100644 index 00000000..13b1dd9c --- /dev/null +++ b/java/src/com/android/intentresolver/ImageLoader.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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 + +import android.graphics.Bitmap +import android.net.Uri +import java.util.function.Consumer + +interface ImageLoader : suspend (Uri) -> Bitmap? { + fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) +} diff --git a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt b/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt index e68eb66a..40081c87 100644 --- a/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt +++ b/java/src/com/android/intentresolver/ImagePreviewImageLoader.kt @@ -16,23 +16,42 @@ package com.android.intentresolver +import android.content.Context import android.graphics.Bitmap import android.net.Uri -import kotlinx.coroutines.suspendCancellableCoroutine +import android.util.Size +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.coroutineScope +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 -// TODO: convert ChooserContentPreviewCoordinator to Kotlin and merge this class into it. -internal class ImagePreviewImageLoader( - private val previewCoordinator: ChooserContentPreviewUi.ContentPreviewCoordinator -) : suspend (Uri) -> Bitmap? { +internal class ImagePreviewImageLoader @JvmOverloads constructor( + private val context: Context, + private val lifecycle: Lifecycle, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) : ImageLoader { - override suspend fun invoke(uri: Uri): Bitmap? = - suspendCancellableCoroutine { continuation -> - val callback = java.util.function.Consumer<Bitmap?> { bitmap -> - try { - continuation.resumeWith(Result.success(bitmap)) - } catch (ignored: Exception) { - } + override suspend fun invoke(uri: Uri): Bitmap? = loadImageAsync(uri) + + override fun loadImage(uri: Uri, callback: Consumer<Bitmap?>) { + lifecycle.coroutineScope.launch { + val image = loadImageAsync(uri) + if (isActive) { + callback.accept(image) } - previewCoordinator.loadImage(uri, callback) } + } + + 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() + } + } } diff --git a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt index a37ef954..c61c7c72 100644 --- a/java/src/com/android/intentresolver/widget/ImagePreviewView.kt +++ b/java/src/com/android/intentresolver/widget/ImagePreviewView.kt @@ -35,7 +35,7 @@ import kotlinx.coroutines.launch import java.util.function.Consumer import com.android.internal.R as IntR -typealias ImageLoader = suspend (Uri) -> Bitmap? +private typealias ImageLoader = suspend (Uri) -> Bitmap? private const val IMAGE_FADE_IN_MILLIS = 150L |