summaryrefslogtreecommitdiff
path: root/java/src/com
diff options
context:
space:
mode:
author Andrey Yepin <ayepin@google.com> 2024-08-26 21:16:57 -0700
committer Andrey Yepin <ayepin@google.com> 2024-10-16 13:10:09 -0700
commit971b4d127f288ee179f1f35f9e7d200ba961797a (patch)
treea007e7f020553ec7eb15d7d207fe772becf713b8 /java/src/com
parent66c6c352139fbfcf89951ea4d8e93b92d07609ca (diff)
Save Shareousel state.
Fix: 362347212 Test: manual testing with injected debug logging Flag: com.android.intentresolver.save_shareousel_state Change-Id: Ibe393e84c0d7884fb1b7611e72df0c7779afce34
Diffstat (limited to 'java/src/com')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateChooserRequestInteractor.kt26
-rw-r--r--java/src/com/android/intentresolver/domain/ChooserRequestExt.kt70
-rw-r--r--java/src/com/android/intentresolver/inject/ActivityModelModule.kt26
-rw-r--r--java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt4
-rw-r--r--java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt26
5 files changed, 123 insertions, 29 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateChooserRequestInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateChooserRequestInteractor.kt
index 4fe5e8d5..fc193eca 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateChooserRequestInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateChooserRequestInteractor.kt
@@ -17,14 +17,13 @@
package com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor
import android.content.Intent
-import com.android.intentresolver.Flags.shareouselUpdateExcludeComponentsExtra
import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.CustomAction
import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.PendingIntentSender
import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.toCustomActionModel
import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate
-import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.getOrDefault
import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.onValue
import com.android.intentresolver.data.repository.ChooserRequestRepository
+import com.android.intentresolver.domain.updateWith
import javax.inject.Inject
import kotlinx.coroutines.flow.update
@@ -36,28 +35,7 @@ constructor(
@CustomAction private val pendingIntentSender: PendingIntentSender,
) {
fun applyUpdate(targetIntent: Intent, update: ShareouselUpdate) {
- repository.chooserRequest.update { current ->
- current.copy(
- targetIntent = targetIntent,
- callerChooserTargets =
- update.callerTargets.getOrDefault(current.callerChooserTargets),
- modifyShareAction =
- update.modifyShareAction.getOrDefault(current.modifyShareAction),
- additionalTargets = update.alternateIntents.getOrDefault(current.additionalTargets),
- chosenComponentSender =
- update.resultIntentSender.getOrDefault(current.chosenComponentSender),
- refinementIntentSender =
- update.refinementIntentSender.getOrDefault(current.refinementIntentSender),
- metadataText = update.metadataText.getOrDefault(current.metadataText),
- chooserActions = update.customActions.getOrDefault(current.chooserActions),
- filteredComponentNames =
- if (shareouselUpdateExcludeComponentsExtra()) {
- update.excludeComponents.getOrDefault(current.filteredComponentNames)
- } else {
- current.filteredComponentNames
- }
- )
- }
+ repository.chooserRequest.update { it.updateWith(targetIntent, update) }
update.customActions.onValue { actions ->
repository.customActions.value =
actions.map { it.toCustomActionModel(pendingIntentSender) }
diff --git a/java/src/com/android/intentresolver/domain/ChooserRequestExt.kt b/java/src/com/android/intentresolver/domain/ChooserRequestExt.kt
new file mode 100644
index 00000000..5ca3ad20
--- /dev/null
+++ b/java/src/com/android/intentresolver/domain/ChooserRequestExt.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 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
+ *
+ * https://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.domain
+
+import android.content.Intent
+import android.content.Intent.EXTRA_ALTERNATE_INTENTS
+import android.content.Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS
+import android.content.Intent.EXTRA_CHOOSER_MODIFY_SHARE_ACTION
+import android.content.Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER
+import android.content.Intent.EXTRA_CHOOSER_RESULT_INTENT_SENDER
+import android.content.Intent.EXTRA_CHOOSER_TARGETS
+import android.content.Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER
+import android.content.Intent.EXTRA_EXCLUDE_COMPONENTS
+import android.content.Intent.EXTRA_INTENT
+import android.content.Intent.EXTRA_METADATA_TEXT
+import android.os.Bundle
+import com.android.intentresolver.Flags.shareouselUpdateExcludeComponentsExtra
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.getOrDefault
+import com.android.intentresolver.data.model.ChooserRequest
+
+/** Creates a new ChooserRequest with the target intent and updates from a Shareousel callback */
+fun ChooserRequest.updateWith(targetIntent: Intent, update: ShareouselUpdate): ChooserRequest =
+ copy(
+ targetIntent = targetIntent,
+ callerChooserTargets = update.callerTargets.getOrDefault(callerChooserTargets),
+ modifyShareAction = update.modifyShareAction.getOrDefault(modifyShareAction),
+ additionalTargets = update.alternateIntents.getOrDefault(additionalTargets),
+ chosenComponentSender = update.resultIntentSender.getOrDefault(chosenComponentSender),
+ refinementIntentSender = update.refinementIntentSender.getOrDefault(refinementIntentSender),
+ metadataText = update.metadataText.getOrDefault(metadataText),
+ chooserActions = update.customActions.getOrDefault(chooserActions),
+ filteredComponentNames =
+ if (shareouselUpdateExcludeComponentsExtra()) {
+ update.excludeComponents.getOrDefault(filteredComponentNames)
+ } else {
+ filteredComponentNames
+ },
+ )
+
+/** Save ChooserRequest values that can be updated by the Shareousel into a Bundle */
+fun ChooserRequest.saveUpdates(bundle: Bundle): Bundle {
+ bundle.putParcelable(EXTRA_INTENT, targetIntent)
+ bundle.putParcelableArray(EXTRA_CHOOSER_TARGETS, callerChooserTargets.toTypedArray())
+ bundle.putParcelable(EXTRA_CHOOSER_MODIFY_SHARE_ACTION, modifyShareAction)
+ bundle.putParcelableArray(EXTRA_ALTERNATE_INTENTS, additionalTargets.toTypedArray())
+ bundle.putParcelable(EXTRA_CHOOSER_RESULT_INTENT_SENDER, chosenComponentSender)
+ bundle.putParcelable(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, chosenComponentSender)
+ bundle.putParcelable(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER, refinementIntentSender)
+ bundle.putCharSequence(EXTRA_METADATA_TEXT, metadataText)
+ bundle.putParcelableArray(EXTRA_CHOOSER_CUSTOM_ACTIONS, chooserActions.toTypedArray())
+ if (shareouselUpdateExcludeComponentsExtra()) {
+ bundle.putParcelableArray(EXTRA_EXCLUDE_COMPONENTS, filteredComponentNames.toTypedArray())
+ }
+ return bundle
+}
diff --git a/java/src/com/android/intentresolver/inject/ActivityModelModule.kt b/java/src/com/android/intentresolver/inject/ActivityModelModule.kt
index 7201bd2b..5b92c05b 100644
--- a/java/src/com/android/intentresolver/inject/ActivityModelModule.kt
+++ b/java/src/com/android/intentresolver/inject/ActivityModelModule.kt
@@ -18,9 +18,13 @@ package com.android.intentresolver.inject
import android.content.Intent
import android.net.Uri
+import android.os.Bundle
import android.service.chooser.ChooserAction
+import androidx.lifecycle.SavedStateHandle
+import com.android.intentresolver.Flags.saveShareouselState
import com.android.intentresolver.data.model.ChooserRequest
import com.android.intentresolver.data.repository.ActivityModelRepository
+import com.android.intentresolver.ui.viewmodel.CHOOSER_REQUEST_KEY
import com.android.intentresolver.ui.viewmodel.readChooserRequest
import com.android.intentresolver.util.ownedByCurrentUser
import com.android.intentresolver.validation.Valid
@@ -44,8 +48,13 @@ object ActivityModelModule {
@ViewModelScoped
fun provideInitialRequest(
activityModelRepo: ActivityModelRepository,
+ savedStateHandle: SavedStateHandle,
flags: ChooserServiceFlags,
- ): ValidationResult<ChooserRequest> = readChooserRequest(activityModelRepo.value, flags)
+ ): ValidationResult<ChooserRequest> {
+ val activityModel = activityModelRepo.value
+ val extras = restoreChooserRequestExtras(activityModel.intent.extras, savedStateHandle)
+ return readChooserRequest(activityModel, flags, extras)
+ }
@Provides
fun provideChooserRequest(initialRequest: ValidationResult<ChooserRequest>): ChooserRequest =
@@ -117,3 +126,18 @@ private val Intent.contentUris: Sequence<Uri>
}
}
}
+
+private fun restoreChooserRequestExtras(
+ initialExtras: Bundle?,
+ savedStateHandle: SavedStateHandle,
+): Bundle =
+ if (saveShareouselState()) {
+ savedStateHandle.get<Bundle>(CHOOSER_REQUEST_KEY)?.let { savedSateBundle ->
+ Bundle().apply {
+ initialExtras?.let { putAll(it) }
+ putAll(savedSateBundle)
+ }
+ } ?: initialExtras
+ } else {
+ initialExtras
+ } ?: Bundle()
diff --git a/java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt b/java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt
index 13cadf37..846cae9e 100644
--- a/java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt
+++ b/java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt
@@ -70,10 +70,10 @@ internal fun Intent.maybeAddSendActionFlags() =
fun readChooserRequest(
model: ActivityModel,
flags: ChooserServiceFlags,
+ savedState: Bundle = model.intent.extras ?: Bundle(),
): ValidationResult<ChooserRequest> {
- val extras = model.intent.extras ?: Bundle()
@Suppress("DEPRECATION")
- return validateFrom(extras::get) {
+ return validateFrom(savedState::get) {
val targetIntent = required(IntentOrUri(EXTRA_INTENT)).maybeAddSendActionFlags()
val isSendAction = targetIntent.hasSendAction()
diff --git a/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt b/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt
index fe7e9109..2292a63c 100644
--- a/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt
+++ b/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt
@@ -16,9 +16,12 @@
package com.android.intentresolver.ui.viewmodel
import android.content.ContentInterface
+import android.os.Bundle
import android.util.Log
+import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.android.intentresolver.Flags.saveShareouselState
import com.android.intentresolver.contentpreview.ImageLoader
import com.android.intentresolver.contentpreview.PreviewDataProvider
import com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor.FetchPreviewsInteractor
@@ -27,6 +30,7 @@ import com.android.intentresolver.contentpreview.payloadtoggle.ui.viewmodel.Shar
import com.android.intentresolver.data.model.ChooserRequest
import com.android.intentresolver.data.repository.ActivityModelRepository
import com.android.intentresolver.data.repository.ChooserRequestRepository
+import com.android.intentresolver.domain.saveUpdates
import com.android.intentresolver.inject.Background
import com.android.intentresolver.inject.ChooserServiceFlags
import com.android.intentresolver.shared.model.ActivityModel
@@ -43,11 +47,13 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
private const val TAG = "ChooserViewModel"
+const val CHOOSER_REQUEST_KEY = "chooser-request"
@HiltViewModel
class ChooserViewModel
@Inject
constructor(
+ savedStateHandle: SavedStateHandle,
activityModelRepository: ActivityModelRepository,
private val shareouselViewModelProvider: Lazy<ShareouselViewModel>,
private val processUpdatesInteractor: Lazy<ProcessTargetIntentUpdatesInteractor>,
@@ -99,8 +105,24 @@ constructor(
}
init {
- if (initialRequest is Invalid) {
- Log.w(TAG, "initialRequest is Invalid, initialization failed")
+ when (initialRequest) {
+ is Invalid -> {
+ Log.w(TAG, "initialRequest is Invalid, initialization failed")
+ }
+ is Valid<ChooserRequest> -> {
+ if (saveShareouselState()) {
+ val isRestored =
+ savedStateHandle.get<Bundle>(CHOOSER_REQUEST_KEY)?.takeIf { !it.isEmpty } !=
+ null
+ savedStateHandle.setSavedStateProvider(CHOOSER_REQUEST_KEY) {
+ Bundle().also { result ->
+ request.value
+ .takeIf { isRestored || it != initialRequest.value }
+ ?.saveUpdates(result)
+ }
+ }
+ }
+ }
}
}
}