diff options
| author | 2024-03-25 19:13:47 +0000 | |
|---|---|---|
| committer | 2024-03-25 19:13:47 +0000 | |
| commit | ea25dfeeea40464a63b2d43f73041c408b949a04 (patch) | |
| tree | 0b0aa2003059e2ac71f5cfac953a1dddb3f844d8 /java/src | |
| parent | c2d8c7f7a9fad0151e67b467f64b54b4b13d9c9d (diff) | |
| parent | d6649924bfd84aebf506f5662a387dc0fb1572f3 (diff) | |
Merge "Payload selection callback: explicitely encode absent property values." into main
Diffstat (limited to 'java/src')
5 files changed, 109 insertions, 68 deletions
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 3ce9aaff..06e28cba 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 @@ -26,6 +26,7 @@ import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.Cus import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.PendingIntentSender import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.TargetIntentModifier import com.android.intentresolver.contentpreview.payloadtoggle.domain.intent.toCustomActionModel +import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.onValue import com.android.intentresolver.contentpreview.payloadtoggle.domain.update.SelectionChangeCallback import com.android.intentresolver.contentpreview.payloadtoggle.shared.model.PreviewModel import javax.inject.Inject @@ -56,9 +57,10 @@ constructor( .mapLatest { record -> selectionCallback.onSelectionChanged(record.intent) } .filterNotNull() .collect { updates -> - val actions = updates.customActions ?: emptyList() - intentRepository.customActions.value = - actions.map { it.toCustomActionModel(pendingIntentSender) } + updates.customActions.onValue { actions -> + intentRepository.customActions.value = + actions.map { it.toCustomActionModel(pendingIntentSender) } + } chooserParamsUpdateRepository.setUpdates(updates) } } 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 index 41a34d1a..821e88a5 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ShareouselUpdate.kt @@ -24,11 +24,11 @@ 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, + val customActions: ValueUpdate<List<ChooserAction>> = ValueUpdate.Absent, + val modifyShareAction: ValueUpdate<ChooserAction?> = ValueUpdate.Absent, + val alternateIntents: ValueUpdate<List<Intent>> = ValueUpdate.Absent, + val callerTargets: ValueUpdate<List<ChooserTarget>> = ValueUpdate.Absent, + val refinementIntentSender: ValueUpdate<IntentSender?> = ValueUpdate.Absent, + val resultIntentSender: ValueUpdate<IntentSender?> = ValueUpdate.Absent, + val metadataText: ValueUpdate<CharSequence?> = ValueUpdate.Absent, ) diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ValueUpdate.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ValueUpdate.kt new file mode 100644 index 00000000..bad4eebe --- /dev/null +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/model/ValueUpdate.kt @@ -0,0 +1,37 @@ +/* + * 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 + +/** Represents an either updated value or the absence of it */ +sealed interface ValueUpdate<out T> { + data class Value<T>(val value: T) : ValueUpdate<T> + data object Absent : ValueUpdate<Nothing> +} + +/** Return encapsulated value if this instance represent Value or `default` if Absent */ +fun <T> ValueUpdate<T>.getOrDefault(default: T): T = + when (this) { + is ValueUpdate.Value -> value + is ValueUpdate.Absent -> default + } + +/** Executes the `block` with encapsulated value if this instance represents Value */ +inline fun <T> ValueUpdate<T>.onValue(block: (T) -> Unit) { + if (this is ValueUpdate.Value) { + block(value) + } +} 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 e7644dc5..20af264a 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 @@ -18,6 +18,8 @@ package com.android.intentresolver.contentpreview.payloadtoggle.domain.update import android.content.ContentInterface 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 @@ -31,6 +33,7 @@ import android.service.chooser.AdditionalContentContract.MethodNames.ON_SELECTIO import android.service.chooser.ChooserAction import android.service.chooser.ChooserTarget import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ShareouselUpdate +import com.android.intentresolver.contentpreview.payloadtoggle.domain.model.ValueUpdate import com.android.intentresolver.inject.AdditionalContent import com.android.intentresolver.inject.ChooserIntent import com.android.intentresolver.inject.ChooserServiceFlags @@ -88,7 +91,10 @@ constructor( } ?.let { bundle -> return when (val result = readCallbackResponse(bundle, flags)) { - is Valid -> result.value + is Valid -> { + result.warnings.forEach { it.log(TAG) } + result.value + } is Invalid -> { result.errors.forEach { it.log(TAG) } null @@ -102,18 +108,40 @@ private fun readCallbackResponse( flags: ChooserServiceFlags ): ValidationResult<ShareouselUpdate> { return validateFrom(bundle::get) { - val customActions = readChooserActions() - val modifyShareAction = optional(value<ChooserAction>(EXTRA_CHOOSER_MODIFY_SHARE_ACTION)) - val alternateIntents = readAlternateIntents() - val callerTargets = optional(array<ChooserTarget>(EXTRA_CHOOSER_TARGETS)) + // An error is treated as an empty collection or null as the presence of a value indicates + // an intention to change the old value implying that the old value is obsolete (and should + // not be used). + val customActions = + bundle.readValueUpdate(EXTRA_CHOOSER_CUSTOM_ACTIONS) { + readChooserActions() ?: emptyList() + } + val modifyShareAction = + bundle.readValueUpdate(EXTRA_CHOOSER_MODIFY_SHARE_ACTION) { key -> + optional(value<ChooserAction>(key)) + } + val alternateIntents = + bundle.readValueUpdate(EXTRA_ALTERNATE_INTENTS) { + readAlternateIntents() ?: emptyList() + } + val callerTargets = + bundle.readValueUpdate(EXTRA_CHOOSER_TARGETS) { key -> + optional(array<ChooserTarget>(key)) ?: emptyList() + } val refinementIntentSender = - optional(value<IntentSender>(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER)) - val resultIntentSender = optional(value<IntentSender>(EXTRA_CHOOSER_RESULT_INTENT_SENDER)) + bundle.readValueUpdate(EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER) { key -> + optional(value<IntentSender>(key)) + } + val resultIntentSender = + bundle.readValueUpdate(EXTRA_CHOOSER_RESULT_INTENT_SENDER) { key -> + optional(value<IntentSender>(key)) + } val metadataText = if (flags.enableSharesheetMetadataExtra()) { - optional(value<CharSequence>(EXTRA_METADATA_TEXT)) + bundle.readValueUpdate(EXTRA_METADATA_TEXT) { key -> + optional(value<CharSequence>(key)) + } } else { - null + ValueUpdate.Absent } ShareouselUpdate( @@ -128,6 +156,16 @@ private fun readCallbackResponse( } } +private inline fun <reified T> Bundle.readValueUpdate( + key: String, + block: (String) -> T +): ValueUpdate<T> = + if (containsKey(key)) { + ValueUpdate.Value(block(key)) + } else { + ValueUpdate.Absent + } + @Module @InstallIn(ViewModelComponent::class) interface SelectionChangeCallbackModule { 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 4afe46b0..37213403 100644 --- a/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt +++ b/java/src/com/android/intentresolver/v2/domain/interactor/ChooserRequestUpdateInteractor.kt @@ -17,12 +17,10 @@ package com.android.intentresolver.v2.domain.interactor import android.content.Intent -import android.content.IntentSender -import android.service.chooser.ChooserAction -import android.service.chooser.ChooserTarget 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.contentpreview.payloadtoggle.domain.model.getOrDefault import com.android.intentresolver.v2.ui.model.ChooserRequest import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -63,61 +61,27 @@ constructor( } private fun updateTargetIntent(targetIntent: Intent) { - chooserRequestRepository.update { current -> - current.updatedWith(targetIntent = targetIntent) - } + chooserRequestRepository.update { current -> current.copy(targetIntent = targetIntent) } } private fun updateChooserParameters(update: ShareouselUpdate) { chooserRequestRepository.update { current -> - current.updatedWith( - callerChooserTargets = update.callerTargets, - modifyShareAction = update.modifyShareAction, - additionalTargets = update.alternateIntents, - chosenComponentSender = update.resultIntentSender, - refinementIntentSender = update.refinementIntentSender, - metadataText = update.metadataText, + current.copy( + 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), ) } } } -private fun ChooserRequest.updatedWith( - targetIntent: Intent? = null, - callerChooserTargets: List<ChooserTarget>? = null, - modifyShareAction: ChooserAction? = null, - additionalTargets: List<Intent>? = null, - chosenComponentSender: IntentSender? = null, - refinementIntentSender: IntentSender? = null, - metadataText: CharSequence? = null, -) = - ChooserRequest( - targetIntent ?: this.targetIntent, - this.targetAction, - this.isSendActionTarget, - this.targetType, - this.launchedFromPackage, - this.title, - this.defaultTitleResource, - this.referrer, - this.filteredComponentNames, - callerChooserTargets ?: this.callerChooserTargets, - this.chooserActions, - modifyShareAction ?: this.modifyShareAction, - this.shouldRetainInOnStop, - additionalTargets ?: this.additionalTargets, - this.replacementExtras, - this.initialIntents, - chosenComponentSender ?: this.chosenComponentSender, - refinementIntentSender ?: this.refinementIntentSender, - this.sharedText, - this.shareTargetFilter, - this.additionalContentUri, - this.focusedItemPosition, - this.contentTypeHint, - metadataText ?: this.metadataText, - ) - @AssistedFactory @ViewModelScoped interface ChooserRequestUpdateInteractorFactory { |