summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
author Andrey Epin <ayepin@google.com> 2024-03-12 17:50:15 -0700
committer Andrey Epin <ayepin@google.com> 2024-03-14 14:02:17 -0700
commite3d2e850f9caeb4df9389ef40d17a650b7bb505a (patch)
tree504f66105bd8d89e2ca3c781ca945eaf7234cd84 /java/src
parent3f1677e45effe9a4b0a3d7c6b83cd6f6cfc00fcf (diff)
Update remaining payload change callback values
Moves ShareouselUpdate out of SelectionChangeCallback into the model package. Receives result intent sender and metadata text from the callback. Propagate chooser requst changes from the callback to the ChooserViewModel; update result sender in ChooserActivity. Bug: 302691505 Test: IntentResolver-tests-unit Test: manual test with the updated CTS-V test Change-Id: I3b05cb35b94cb820c5f4fdc9fbc336dd072c36bd
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/data/repository/ChooserParamsUpdateRepository.kt34
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateTargetIntentInteractor.kt12
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt34
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt31
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java34
-rw-r--r--java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt58
6 files changed, 176 insertions, 27 deletions
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/data/repository/ChooserParamsUpdateRepository.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/data/repository/ChooserParamsUpdateRepository.kt
new file mode 100644
index 00000000..1a4f2b83
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/data/repository/ChooserParamsUpdateRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * 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.payloadtoggle.data.repository
+
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate
+import dagger.hilt.android.scopes.ViewModelScoped
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Chooser parameters Updates received from the sharing application payload change callback */
+// TODO: a scaffolding repository to deliver chooser parameter updates before we developed some
+// other, more thought-through solution.
+@ViewModelScoped
+class ChooserParamsUpdateRepository @Inject constructor() {
+ val updates = MutableStateFlow<ShareouselUpdate?>(null)
+
+ fun setUpdates(update: ShareouselUpdate) {
+ updates.tryEmit(update)
+ }
+}
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateTargetIntentInteractor.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateTargetIntentInteractor.kt
index 4619e478..4cb1f5b6 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateTargetIntentInteractor.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/interactor/UpdateTargetIntentInteractor.kt
@@ -18,6 +18,7 @@
package com.android.intentresolver.contentpreview.payloadtoggle.domain.interactor
+import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.ChooserParamsUpdateRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.PreviewSelectionsRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.TargetIntentRepository
import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.CustomAction
@@ -30,6 +31,7 @@ import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.launch
@@ -38,6 +40,7 @@ class UpdateTargetIntentInteractor
@Inject
constructor(
private val intentRepository: TargetIntentRepository,
+ private val chooserParamsUpdateRepository: ChooserParamsUpdateRepository,
@CustomAction private val pendingIntentSender: PendingIntentSender,
private val selectionCallback: SelectionChangeCallback,
private val selectionRepo: PreviewSelectionsRepository,
@@ -47,12 +50,13 @@ constructor(
suspend fun launch(): Unit = coroutineScope {
launch {
intentRepository.targetIntent
- .mapLatest { targetIntent ->
- selectionCallback.onSelectionChanged(targetIntent)?.customActions ?: emptyList()
- }
- .collect { actions ->
+ .mapLatest { targetIntent -> selectionCallback.onSelectionChanged(targetIntent) }
+ .filterNotNull()
+ .collect { updates ->
+ val actions = updates.customActions ?: emptyList()
intentRepository.customActions.value =
actions.map { it.toCustomActionModel(pendingIntentSender) }
+ chooserParamsUpdateRepository.setUpdates(updates)
}
}
launch {
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt
new file mode 100644
index 00000000..41a34d1a
--- /dev/null
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt
@@ -0,0 +1,34 @@
+/*
+ * 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
+ *
+ * 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.payloadtoggle.domain.model
+
+import android.content.Intent
+import android.content.IntentSender
+import android.service.chooser.ChooserAction
+import android.service.chooser.ChooserTarget
+
+/** Sharing session updates provided by the sharing app from the payload change callback */
+data class ShareouselUpdate(
+ // for all properties, null value means no change
+ val customActions: List<ChooserAction>? = null,
+ val modifyShareAction: ChooserAction? = null,
+ val alternateIntents: List<Intent>? = null,
+ val callerTargets: List<ChooserTarget>? = null,
+ val refinementIntentSender: IntentSender? = null,
+ val resultIntentSender: IntentSender? = null,
+ val metadataText: CharSequence? = null,
+)
diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt
index 03295a31..e7644dc5 100644
--- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt
+++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt
@@ -20,17 +20,20 @@ import android.content.ContentInterface
import android.content.Intent
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_INTENT
+import android.content.Intent.EXTRA_METADATA_TEXT
import android.content.IntentSender
import android.net.Uri
import android.os.Bundle
import android.service.chooser.AdditionalContentContract.MethodNames.ON_SELECTION_CHANGED
import android.service.chooser.ChooserAction
import android.service.chooser.ChooserTarget
-import com.android.intentresolver.contentpreview.payloadtoggle.domain.update.SelectionChangeCallback.ShareouselUpdate
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate
import com.android.intentresolver.inject.AdditionalContent
import com.android.intentresolver.inject.ChooserIntent
+import com.android.intentresolver.inject.ChooserServiceFlags
import com.android.intentresolver.v2.ui.viewmodel.readAlternateIntents
import com.android.intentresolver.v2.ui.viewmodel.readChooserActions
import com.android.intentresolver.v2.validation.Invalid
@@ -56,15 +59,6 @@ private const val TAG = "SelectionChangeCallback"
*/
fun interface SelectionChangeCallback {
suspend fun onSelectionChanged(targetIntent: Intent): ShareouselUpdate?
-
- data class ShareouselUpdate(
- // for all properties, null value means no change
- val customActions: List<ChooserAction>? = null,
- val modifyShareAction: ChooserAction? = null,
- val alternateIntents: List<Intent>? = null,
- val callerTargets: List<ChooserTarget>? = null,
- val refinementIntentSender: IntentSender? = null,
- )
}
class SelectionChangeCallbackImpl
@@ -73,6 +67,7 @@ constructor(
@AdditionalContent private val uri: Uri,
@ChooserIntent private val chooserIntent: Intent,
private val contentResolver: ContentInterface,
+ private val flags: ChooserServiceFlags,
) : SelectionChangeCallback {
private val mutex = Mutex()
@@ -92,7 +87,7 @@ constructor(
)
}
?.let { bundle ->
- return when (val result = readCallbackResponse(bundle)) {
+ return when (val result = readCallbackResponse(bundle, flags)) {
is Valid -> result.value
is Invalid -> {
result.errors.forEach { it.log(TAG) }
@@ -102,7 +97,10 @@ constructor(
}
}
-private fun readCallbackResponse(bundle: Bundle): ValidationResult<ShareouselUpdate> {
+private fun readCallbackResponse(
+ bundle: Bundle,
+ flags: ChooserServiceFlags
+): ValidationResult<ShareouselUpdate> {
return validateFrom(bundle::get) {
val customActions = readChooserActions()
val modifyShareAction = optional(value<ChooserAction>(EXTRA_CHOOSER_MODIFY_SHARE_ACTION))
@@ -110,6 +108,13 @@ private fun readCallbackResponse(bundle: Bundle): ValidationResult<ShareouselUpd
val callerTargets = optional(array<ChooserTarget>(EXTRA_CHOOSER_TARGETS))
val refinementIntentSender =
optional(value<IntentSender>(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER))
+ val resultIntentSender = optional(value<IntentSender>(EXTRA_CHOOSER_RESULT_INTENT_SENDER))
+ val metadataText =
+ if (flags.enableSharesheetMetadataExtra()) {
+ optional(value<CharSequence>(EXTRA_METADATA_TEXT))
+ } else {
+ null
+ }
ShareouselUpdate(
customActions,
@@ -117,6 +122,8 @@ private fun readCallbackResponse(bundle: Bundle): ValidationResult<ShareouselUpd
alternateIntents,
callerTargets,
refinementIntentSender,
+ resultIntentSender,
+ metadataText,
)
}
}
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index bda393b8..110983d0 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -490,11 +490,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mLatencyTracker.onActionStart(ACTION_LOAD_SHARE_SHEET);
mPinnedSharedPrefs = getPinnedSharedPrefs(this);
- IntentSender chosenComponentSender = mRequest.getChosenComponentSender();
- if (chosenComponentSender != null) {
- mShareResultSender = mShareResultSenderFactory.create(
- mViewModel.getActivityModel().getLaunchedFromUid(), chosenComponentSender);
- }
+ updateShareResultSender();
mMaxTargetsPerRow =
getResources().getInteger(R.integer.config_chooser_max_targets_per_row);
@@ -661,11 +657,37 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
}
private void onChooserRequestChanged(ChooserRequest chooserRequest) {
+ // intentional reference comarison
if (mRequest == chooserRequest) {
return;
}
+ boolean recreateAdapters = shouldUpdateAdapters(mRequest, chooserRequest);
mRequest = chooserRequest;
- recreatePagerAdapter();
+ updateShareResultSender();
+ if (recreateAdapters) {
+ recreatePagerAdapter();
+ }
+ }
+
+ private void updateShareResultSender() {
+ IntentSender chosenComponentSender = mRequest.getChosenComponentSender();
+ if (chosenComponentSender != null) {
+ mShareResultSender = mShareResultSenderFactory.create(
+ mViewModel.getActivityModel().getLaunchedFromUid(), chosenComponentSender);
+ } else {
+ mShareResultSender = null;
+ }
+ }
+
+ private boolean shouldUpdateAdapters(
+ ChooserRequest oldChooserRequest, ChooserRequest newChooserRequest) {
+ Intent oldTargetIntent = oldChooserRequest.getTargetIntent();
+ Intent newTargetIntent = newChooserRequest.getTargetIntent();
+
+ // TODO: a workaround for the unnecessary target reloading caused by multiple flow updates -
+ // an artifact of the current implementation; revisit.
+ // reference comparison is intentional
+ return oldTargetIntent != newTargetIntent;
}
private void recreatePagerAdapter() {
diff --git a/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt b/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt
index 99da5c81..534b2be3 100644
--- a/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt
+++ b/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt
@@ -18,7 +18,9 @@ package com.android.intentresolver.v2.domain.interactor
import android.content.Intent
import android.util.Log
+import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.ChooserParamsUpdateRepository
import com.android.intentresolver.contentpreview.payloadtoggle.data.repository.TargetIntentRepository
+import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate
import com.android.intentresolver.inject.ChooserServiceFlags
import com.android.intentresolver.inject.TargetIntent
import com.android.intentresolver.v2.ui.model.ActivityModel
@@ -30,8 +32,12 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.scopes.ViewModelScoped
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
private const val TAG = "ChooserRequestUpdate"
@@ -43,17 +49,27 @@ constructor(
private val activityModel: ActivityModel,
@TargetIntent private val initialIntent: Intent,
private val targetIntentRepository: TargetIntentRepository,
+ private val paramsUpdateRepository: ChooserParamsUpdateRepository,
// TODO: replace with a proper repository, when available
@Assisted private val chooserRequestRepository: MutableStateFlow<ChooserRequest>,
private val flags: ChooserServiceFlags,
) {
suspend fun launch() {
- targetIntentRepository.targetIntent
- // TODO: maybe find a better way to exclude the initial intent (as here it's compared by
- // reference)
- .filter { it !== initialIntent }
- .collect(::updateTargetIntent)
+ coroutineScope {
+ launch {
+ targetIntentRepository.targetIntent
+ // TODO: maybe find a better way to exclude the initial intent (as here it's
+ // compared by
+ // reference)
+ .filter { it !== initialIntent }
+ .collect(::updateTargetIntent)
+ }
+
+ launch {
+ paramsUpdateRepository.updates.filterNotNull().collect(::updateChooserParameters)
+ }
+ }
}
private fun updateTargetIntent(targetIntent: Intent) {
@@ -64,6 +80,38 @@ constructor(
}
}
+ private fun updateChooserParameters(update: ShareouselUpdate) {
+ chooserRequestRepository.update { current ->
+ ChooserRequest(
+ current.targetIntent,
+ current.targetAction,
+ current.isSendActionTarget,
+ current.targetType,
+ current.launchedFromPackage,
+ current.title,
+ current.defaultTitleResource,
+ current.referrer,
+ current.filteredComponentNames,
+ update.callerTargets ?: current.callerChooserTargets,
+ // chooser actions are handled separately
+ current.chooserActions,
+ update.modifyShareAction ?: current.modifyShareAction,
+ current.shouldRetainInOnStop,
+ update.alternateIntents ?: current.additionalTargets,
+ current.replacementExtras,
+ current.initialIntents,
+ update.resultIntentSender ?: current.chosenComponentSender,
+ update.refinementIntentSender ?: current.refinementIntentSender,
+ current.sharedText,
+ current.shareTargetFilter,
+ current.additionalContentUri,
+ current.focusedItemPosition,
+ current.contentTypeHint,
+ update.metadataText ?: current.metadataText,
+ )
+ }
+ }
+
private fun ActivityModel.updateWithTargetIntent(targetIntent: Intent) =
ActivityModel(
Intent(intent).apply { putExtra(Intent.EXTRA_INTENT, targetIntent) },