From 03a778d6df2c57a74eed90c659e6c6893bd29170 Mon Sep 17 00:00:00 2001 From: Andrey Epin Date: Wed, 10 May 2023 20:39:45 -0700 Subject: Kepp PreviewDataProvider instace over a configuration change Add a view model, PreviewViewModel, to retain a PreviewDataProvider instance. Tangentally, move ChooserActivity#isImageType method into MimeTypeClassifier (to avoid keep a link to the activity). Fix: 281929002 Test: manual testing, vierify through injected debug logging that the object is not re-created. Change-Id: I7be397089ca33e589a3ecbd6012929bfe3c5433a --- .../android/intentresolver/ChooserActivity.java | 19 ++------ .../contentpreview/ChooserContentPreviewUi.java | 3 +- .../contentpreview/DefaultMimeTypeClassifier.kt | 19 ++++++++ .../contentpreview/MimeTypeClassifier.java | 8 ++-- .../contentpreview/PreviewDataProvider.kt | 3 +- .../contentpreview/PreviewViewModel.kt | 51 ++++++++++++++++++++++ 6 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt create mode 100644 java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt (limited to 'java/src/com') diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index 84e14d72..bc3b63f5 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -86,7 +86,7 @@ import com.android.intentresolver.chooser.TargetInfo; import com.android.intentresolver.contentpreview.ChooserContentPreviewUi; import com.android.intentresolver.contentpreview.HeadlineGeneratorImpl; import com.android.intentresolver.contentpreview.ImageLoader; -import com.android.intentresolver.contentpreview.PreviewDataProvider; +import com.android.intentresolver.contentpreview.PreviewViewModel; import com.android.intentresolver.flags.FeatureFlagRepository; import com.android.intentresolver.flags.FeatureFlagRepositoryFactory; import com.android.intentresolver.grid.ChooserGridAdapter; @@ -274,9 +274,10 @@ public class ChooserActivity extends ResolverActivity implements mChooserContentPreviewUi = new ChooserContentPreviewUi( getLifecycle(), - createPreviewDataProvider(), + new ViewModelProvider(this, PreviewViewModel.Companion.getFactory()) + .get(PreviewViewModel.class) + .createOrReuseProvider(mChooserRequest), mChooserRequest.getTargetIntent(), - this::isImageType, createPreviewImageLoader(), createChooserActionFactory(), mEnterTransitionAnimationDelegate, @@ -538,14 +539,6 @@ public class ChooserActivity extends ResolverActivity implements mMaxTargetsPerRow); } - private PreviewDataProvider createPreviewDataProvider() { - // TODO: move this into a ViewModel so it could survive orientation change - return new PreviewDataProvider( - mChooserRequest.getTargetIntent(), - getContentResolver(), - this::isImageType); - } - private int findSelectedProfile() { int selectedProfile = getSelectedProfileExtra(); if (selectedProfile == -1) { @@ -722,10 +715,6 @@ public class ChooserActivity extends ResolverActivity implements return resolver.query(uri, null, null, null, null); } - private boolean isImageType(@Nullable String mimeType) { - return mimeType != null && mimeType.startsWith("image/"); - } - private int getNumSheetExpansions() { return getPreferences(Context.MODE_PRIVATE).getInt(PREF_NUM_SHEET_EXPANSIONS, 0); } diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java index 55131de2..787af95f 100644 --- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java @@ -88,7 +88,6 @@ public final class ChooserContentPreviewUi { Lifecycle lifecycle, PreviewDataProvider previewData, Intent targetIntent, - MimeTypeClassifier imageClassifier, ImageLoader imageLoader, ActionFactory actionFactory, TransitionElementStatusCallback transitionElementStatusCallback, @@ -97,7 +96,7 @@ public final class ChooserContentPreviewUi { mContentPreviewUi = createContentPreview( previewData, targetIntent, - imageClassifier, + DefaultMimeTypeClassifier.INSTANCE, imageLoader, actionFactory, transitionElementStatusCallback, diff --git a/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt new file mode 100644 index 00000000..b9215709 --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/DefaultMimeTypeClassifier.kt @@ -0,0 +1,19 @@ +/* + * 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 + +object DefaultMimeTypeClassifier : MimeTypeClassifier diff --git a/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java index 2de60c5b..c86b0fe2 100644 --- a/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java +++ b/java/src/com/android/intentresolver/contentpreview/MimeTypeClassifier.java @@ -22,14 +22,12 @@ import androidx.annotation.Nullable; /** * Testing shim to specify whether a given mime type is considered to be an "image." - * - * TODO: move away from {@link ChooserActivityOverrideData} as a model to configure our tests, - * then migrate {@link com.android.intentresolver.ChooserActivity#isImageType(String)} into this - * class. */ public interface MimeTypeClassifier { /** @return whether the specified {@code mimeType} is classified as an "image" type. */ - boolean isImageType(@Nullable String mimeType); + default boolean isImageType(@Nullable String mimeType) { + return (mimeType != null) && ClipDescription.compareMimeTypes(mimeType, "image/*"); + } /** @return whether the specified {@code mimeType} is classified as an "video" type */ default boolean isVideoType(@Nullable String mimeType) { diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt index 94db7a63..ae705369 100644 --- a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt +++ b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt @@ -78,11 +78,10 @@ constructor( constructor( targetIntent: Intent, contentResolver: ContentInterface, - typeClassifier: MimeTypeClassifier, ) : this( targetIntent, contentResolver, - typeClassifier, + DefaultMimeTypeClassifier, Dispatchers.IO, ) diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt new file mode 100644 index 00000000..2f4b0211 --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/PreviewViewModel.kt @@ -0,0 +1,51 @@ +/* + * 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.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY +import androidx.lifecycle.viewmodel.CreationExtras +import com.android.intentresolver.ChooserRequestParameters + +/** A trivial view model to keep a [PreviewDataProvider] instance over a configuration change */ +class PreviewViewModel(private val contentResolver: ContentResolver) : ViewModel() { + private var previewDataProvider: PreviewDataProvider? = null + + fun createOrReuseProvider(chooserRequest: ChooserRequestParameters): PreviewDataProvider { + return previewDataProvider + ?: PreviewDataProvider(chooserRequest.targetIntent, contentResolver).also { + previewDataProvider = it + } + } + + companion object { + val Factory: ViewModelProvider.Factory = + object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras + ): T = + PreviewViewModel( + (checkNotNull(extras[APPLICATION_KEY]) as Context).contentResolver + ) as T + } + } +} -- cgit v1.2.3-59-g8ed1b