diff options
author | 2024-04-08 17:10:29 +0000 | |
---|---|---|
committer | 2024-04-08 17:10:29 +0000 | |
commit | efc35f89fd67ad7a66a42df7ddef51f3d44d48c8 (patch) | |
tree | 57abdbb1600df02f923b78eb61d82a058e73a7a6 | |
parent | fb35a600df1991ac7ea685b1f365baf16b56a20d (diff) | |
parent | 79de0412b6dca6dd2401684575ba507683aa0775 (diff) |
Merge "Make actions editable" into main
6 files changed, 202 insertions, 68 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt index f69021f34ebb..0ccb19cd9d31 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt @@ -29,7 +29,7 @@ import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED -import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel +import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -81,65 +81,67 @@ constructor( } } viewModel.addAction( - ActionButtonViewModel( + ActionButtonAppearance( AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit), context.resources.getString(R.string.screenshot_edit_label), context.resources.getString(R.string.screenshot_edit_description), - ) { - debugLog(LogConfig.DEBUG_ACTIONS) { "Edit tapped" } - uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString) - onDeferrableActionTapped { result -> - actionExecutor.startSharedTransition( - createEdit(result.uri, context), - result.user, - true - ) - } + ) + ) { + debugLog(LogConfig.DEBUG_ACTIONS) { "Edit tapped" } + uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString) + onDeferrableActionTapped { result -> + actionExecutor.startSharedTransition( + createEdit(result.uri, context), + result.user, + true + ) } - ) + } + viewModel.addAction( - ActionButtonViewModel( + ActionButtonAppearance( AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share), context.resources.getString(R.string.screenshot_share_label), context.resources.getString(R.string.screenshot_share_description), - ) { - debugLog(LogConfig.DEBUG_ACTIONS) { "Share tapped" } - uiEventLogger.log(SCREENSHOT_SHARE_TAPPED, 0, request.packageNameString) - onDeferrableActionTapped { result -> - actionExecutor.startSharedTransition( - createShareWithSubject(result.uri, result.subject), - result.user, - false - ) - } + ) + ) { + debugLog(LogConfig.DEBUG_ACTIONS) { "Share tapped" } + uiEventLogger.log(SCREENSHOT_SHARE_TAPPED, 0, request.packageNameString) + onDeferrableActionTapped { result -> + actionExecutor.startSharedTransition( + createShareWithSubject(result.uri, result.subject), + result.user, + false + ) } - ) + } + smartActionsProvider.requestQuickShare(request, requestId) { quickShare -> if (!quickShare.actionIntent.isImmutable) { viewModel.addAction( - ActionButtonViewModel( + ActionButtonAppearance( quickShare.getIcon().loadDrawable(context), quickShare.title, quickShare.title - ) { - debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" } - onDeferrableActionTapped { result -> - uiEventLogger.log( - SCREENSHOT_SMART_ACTION_TAPPED, - 0, - request.packageNameString + ) + ) { + debugLog(LogConfig.DEBUG_ACTIONS) { "Quickshare tapped" } + onDeferrableActionTapped { result -> + uiEventLogger.log( + SCREENSHOT_SMART_ACTION_TAPPED, + 0, + request.packageNameString + ) + val pendingIntentWithUri = + smartActionsProvider.wrapIntent( + quickShare, + result.uri, + result.subject, + requestId ) - val pendingIntentWithUri = - smartActionsProvider.wrapIntent( - quickShare, - result.uri, - result.subject, - requestId - ) - actionExecutor.sendPendingIntent(pendingIntentWithUri) - } + actionExecutor.sendPendingIntent(pendingIntentWithUri) } - ) + } } else { Log.w(TAG, "Received immutable quick share pending intent; ignoring") } @@ -148,14 +150,14 @@ constructor( override fun onScrollChipReady(onClick: Runnable) { viewModel.addAction( - ActionButtonViewModel( + ActionButtonAppearance( AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll), context.resources.getString(R.string.screenshot_scroll_label), context.resources.getString(R.string.screenshot_scroll_label), - ) { - onClick.run() - } - ) + ) + ) { + onClick.run() + } } override fun setCompletedScreenshot(result: ScreenshotSavedResult) { @@ -166,13 +168,19 @@ constructor( this.result = result pendingAction?.invoke(result) smartActionsProvider.requestSmartActions(request, requestId, result) { smartActions -> - viewModel.addActions( - smartActions.map { - ActionButtonViewModel(it.getIcon().loadDrawable(context), it.title, it.title) { - actionExecutor.sendPendingIntent(it.actionIntent) + smartActions.forEach { + smartActions.forEach { action -> + viewModel.addAction( + ActionButtonAppearance( + action.getIcon().loadDrawable(context), + action.title, + action.title, + ) + ) { + actionExecutor.sendPendingIntent(action.actionIntent) } } - ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt index a6374ae3304d..3c5a0ec107f8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt @@ -28,16 +28,16 @@ object ActionButtonViewBinder { fun bind(view: View, viewModel: ActionButtonViewModel) { val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon) val textView = view.requireViewById<TextView>(R.id.overlay_action_chip_text) - iconView.setImageDrawable(viewModel.icon) - textView.text = viewModel.name - setMargins(iconView, textView, viewModel.name?.isNotEmpty() ?: false) + iconView.setImageDrawable(viewModel.appearance.icon) + textView.text = viewModel.appearance.label + setMargins(iconView, textView, viewModel.appearance.label?.isNotEmpty() ?: false) if (viewModel.onClicked != null) { view.setOnClickListener { viewModel.onClicked.invoke() } } else { view.setOnClickListener(null) } view.tag = viewModel.id - view.contentDescription = viewModel.description + view.contentDescription = viewModel.appearance.description view.visibility = View.VISIBLE view.alpha = 1f } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt new file mode 100644 index 000000000000..55a2ad21e292 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 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.systemui.screenshot.ui.viewmodel + +import android.graphics.drawable.Drawable + +/** Data describing how an action should be shown to the user. */ +data class ActionButtonAppearance( + val icon: Drawable?, + val label: CharSequence?, + val description: CharSequence, +) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt index 97b24c1b7df7..64b0105a98a0 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt @@ -16,19 +16,19 @@ package com.android.systemui.screenshot.ui.viewmodel -import android.graphics.drawable.Drawable - data class ActionButtonViewModel( - val icon: Drawable?, - val name: CharSequence?, - val description: CharSequence, + val appearance: ActionButtonAppearance, + val id: Int, val onClicked: (() -> Unit)?, ) { - val id: Int = getId() - companion object { private var nextId = 0 private fun getId() = nextId.also { nextId += 1 } + + fun withNextId( + appearance: ActionButtonAppearance, + onClicked: (() -> Unit)? + ): ActionButtonViewModel = ActionButtonViewModel(appearance, getId(), onClicked) } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt index ddfa69b687eb..fa3480343ea0 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.screenshot.ui.viewmodel import android.graphics.Bitmap +import android.util.Log import android.view.accessibility.AccessibilityManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -39,16 +40,34 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager _previewAction.value = onClick } - fun addAction(action: ActionButtonViewModel) { + fun addAction(actionAppearance: ActionButtonAppearance, onClicked: (() -> Unit)): Int { val actionList = _actions.value.toMutableList() + val action = ActionButtonViewModel.withNextId(actionAppearance, onClicked) actionList.add(action) _actions.value = actionList + return action.id } - fun addActions(actions: List<ActionButtonViewModel>) { + fun updateActionAppearance(actionId: Int, appearance: ActionButtonAppearance) { val actionList = _actions.value.toMutableList() - actionList.addAll(actions) - _actions.value = actionList + val index = actionList.indexOfFirst { it.id == actionId } + if (index >= 0) { + actionList[index] = + ActionButtonViewModel(appearance, actionId, actionList[index].onClicked) + _actions.value = actionList + } else { + Log.w(TAG, "Attempted to update unknown action id $actionId") + } + } + + fun removeAction(actionId: Int) { + val actionList = _actions.value.toMutableList() + if (actionList.removeIf { it.id == actionId }) { + // Update if something was removed. + _actions.value = actionList + } else { + Log.w(TAG, "Attempted to remove unknown action id $actionId") + } } fun reset() { @@ -56,4 +75,8 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager _previewAction.value = null _actions.value = listOf() } + + companion object { + const val TAG = "ScreenshotViewModel" + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt new file mode 100644 index 000000000000..d44e26c266fc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModelTest.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 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.systemui.screenshot.ui.viewmodel + +import android.view.accessibility.AccessibilityManager +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.mockito.Mockito.mock + +@SmallTest +class ScreenshotViewModelTest { + private val accessibilityManager: AccessibilityManager = mock(AccessibilityManager::class.java) + private val appearance = ActionButtonAppearance(null, "Label", "Description") + private val onclick = {} + + @Test + fun testAddAction() { + val viewModel = ScreenshotViewModel(accessibilityManager) + + assertThat(viewModel.actions.value).isEmpty() + + viewModel.addAction(appearance, onclick) + + assertThat(viewModel.actions.value).hasSize(1) + + val added = viewModel.actions.value[0] + assertThat(added.appearance).isEqualTo(appearance) + assertThat(added.onClicked).isEqualTo(onclick) + } + + @Test + fun testRemoveAction() { + val viewModel = ScreenshotViewModel(accessibilityManager) + val firstId = viewModel.addAction(ActionButtonAppearance(null, "", ""), {}) + val secondId = viewModel.addAction(appearance, onclick) + + assertThat(viewModel.actions.value).hasSize(2) + assertThat(firstId).isNotEqualTo(secondId) + + viewModel.removeAction(firstId) + + assertThat(viewModel.actions.value).hasSize(1) + + val remaining = viewModel.actions.value[0] + assertThat(remaining.appearance).isEqualTo(appearance) + assertThat(remaining.onClicked).isEqualTo(onclick) + } + + @Test + fun testUpdateActionAppearance() { + val viewModel = ScreenshotViewModel(accessibilityManager) + val id = viewModel.addAction(appearance, onclick) + val otherAppearance = ActionButtonAppearance(null, "Other", "Other") + + viewModel.updateActionAppearance(id, otherAppearance) + + assertThat(viewModel.actions.value).hasSize(1) + val updated = viewModel.actions.value[0] + assertThat(updated.appearance).isEqualTo(otherAppearance) + assertThat(updated.onClicked).isEqualTo(onclick) + } +} |