summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Josh <jmokut@google.com> 2025-02-13 15:29:55 +0000
committer Josh <jmokut@google.com> 2025-02-14 13:09:58 +0000
commite3483d469e70ffbdf37dc439b2bc055c54836487 (patch)
treea266fe8c588e0412dc5d5aa28aee31b6e6474356
parent04a85b1091ddfe3b267e01fcaa73e898da314ddf (diff)
Add logic for building content description for pressed keys
added logic to build custom content description when user is customizing shortcut. This allows us to pass content description to our custom text/icon box composable. Also this re-uses logic for building content description in shortcut helper ensuring consistency across shortcut helper. Fix: 394480347 Flag: com.android.systemui.keyboard_shortcut_helper_shortcut_customizer Test: ShortcutCustomizationViewModelTest Change-Id: I409923ed219b878e62c5ccf94771ed379e89e946
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt25
6 files changed, 134 insertions, 35 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
index 6eef5eb09812..b91e259003a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -337,6 +337,43 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() {
}
}
+ @Test
+ fun uiState_pressedKeysDescription_emptyByDefault() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+
+ assertThat((uiState as AddShortcutDialog).pressedKeysDescription).isEmpty()
+ }
+ }
+
+ @Test
+ fun uiState_pressedKeysDescription_updatesToNonEmptyDescriptionWhenKeyCombinationIsPressed() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onShortcutKeyCombinationSelected(keyDownEventWithActionKeyPressed)
+ viewModel.onShortcutKeyCombinationSelected(keyUpEventWithActionKeyPressed)
+
+ // Note that Action Key is excluded as it's already displayed on the UI
+ assertThat((uiState as AddShortcutDialog).pressedKeysDescription)
+ .isEqualTo("Ctrl, plus A")
+ }
+ }
+
+ @Test
+ fun uiState_pressedKeysDescription_resetsToEmpty_onClearSelectedShortcutKeyCombination() {
+ testScope.runTest {
+ val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
+ viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
+ viewModel.onShortcutKeyCombinationSelected(keyDownEventWithActionKeyPressed)
+ viewModel.onShortcutKeyCombinationSelected(keyUpEventWithActionKeyPressed)
+ viewModel.clearSelectedKeyCombination()
+
+ assertThat((uiState as AddShortcutDialog).pressedKeysDescription).isEmpty()
+ }
+ }
+
private suspend fun openAddShortcutDialogAndSetShortcut() {
openAddShortcutDialogAndPressKeyCombination()
viewModel.onSetShortcut()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index 61d11f4df5e0..f89421f9b73e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -17,19 +17,16 @@
package com.android.systemui.keyboard.shortcut.domain.interactor
import android.content.Context
-import android.view.KeyEvent.META_META_ON
import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository
-import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
-import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys.metaModifierIconResId
+import com.android.systemui.keyboard.shortcut.extensions.toContentDescription
import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories
import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.res.R
import dagger.Lazy
@@ -105,8 +102,6 @@ constructor(
context.getString(R.string.shortcut_helper_key_combinations_and_conjunction)
val orConjunction =
context.getString(R.string.shortcut_helper_key_combinations_or_separator)
- val forwardSlash =
- context.getString(R.string.shortcut_helper_key_combinations_forward_slash)
return buildString {
append("$label, $pressKey")
commands.forEachIndexed { i, shortcutCommand ->
@@ -117,29 +112,7 @@ constructor(
if (j > 0) {
append(" $andConjunction")
}
- if (shortcutKey is ShortcutKey.Text) {
- // Special handling for "/" as TalkBack will not read punctuation by
- // default.
- if (shortcutKey.value.equals("/")) {
- append(" $forwardSlash")
- } else {
- append(" ${shortcutKey.value}")
- }
- } else if (shortcutKey is ShortcutKey.Icon.ResIdIcon) {
- val keyLabel =
- if (shortcutKey.drawableResId == metaModifierIconResId) {
- ShortcutHelperKeys.modifierLabels[META_META_ON]
- } else {
- val keyCode =
- ShortcutHelperKeys.keyIcons.entries
- .firstOrNull { it.value == shortcutKey.drawableResId }
- ?.key
- ShortcutHelperKeys.specialKeyLabels[keyCode]
- }
- if (keyLabel != null) {
- append(" ${keyLabel.invoke(context)}")
- }
- } // No-Op when shortcutKey is ShortcutKey.Icon.DrawableIcon
+ shortcutKey.toContentDescription(context)?.let { append(" $it") }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt
new file mode 100644
index 000000000000..5637747d5aba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 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.keyboard.shortcut.extensions
+
+import android.content.Context
+import android.view.KeyEvent.META_META_ON
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys
+import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys.metaModifierIconResId
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
+import com.android.systemui.res.R
+
+fun ShortcutKey.toContentDescription(context: Context): String? {
+ val forwardSlash = context.getString(R.string.shortcut_helper_key_combinations_forward_slash)
+ when (this) {
+ is ShortcutKey.Text -> {
+ // Special handling for "/" as TalkBack will not read punctuation by
+ // default.
+ return if (this.value == "/") {
+ forwardSlash
+ } else {
+ this.value
+ }
+ }
+
+ is ShortcutKey.Icon.ResIdIcon -> {
+ val keyLabel =
+ if (this.drawableResId == metaModifierIconResId) {
+ ShortcutHelperKeys.modifierLabels[META_META_ON]
+ } else {
+ val keyCode =
+ ShortcutHelperKeys.keyIcons.entries
+ .firstOrNull { it.value == this.drawableResId }
+ ?.key
+ ShortcutHelperKeys.specialKeyLabels[keyCode]
+ }
+
+ if (keyLabel != null) {
+ return keyLabel.invoke(context)
+ }
+ }
+
+ is ShortcutKey.Icon.DrawableIcon -> {
+ // No-Op when shortcutKey is ShortcutKey.Icon.DrawableIcon
+ }
+ }
+
+ return null
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index 66e45056989d..7e0fa2f125b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -60,6 +60,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.LiveRegionMode
import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.hideFromAccessibility
import androidx.compose.ui.semantics.liveRegion
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.font.FontWeight
@@ -127,6 +128,7 @@ private fun AddShortcutDialog(
shouldShowError = uiState.errorMessage.isNotEmpty(),
onShortcutKeyCombinationSelected = onShortcutKeyCombinationSelected,
pressedKeys = uiState.pressedKeys,
+ contentDescription = uiState.pressedKeysDescription,
onConfirmSetShortcut = onConfirmSetShortcut,
onClearSelectedKeyCombination = onClearSelectedKeyCombination,
)
@@ -267,6 +269,7 @@ private fun SelectedKeyCombinationContainer(
shouldShowError: Boolean,
onShortcutKeyCombinationSelected: (KeyEvent) -> Boolean,
pressedKeys: List<ShortcutKey>,
+ contentDescription: String,
onConfirmSetShortcut: () -> Unit,
onClearSelectedKeyCombination: () -> Unit,
) {
@@ -313,6 +316,7 @@ private fun SelectedKeyCombinationContainer(
} else {
null
},
+ contentDescription = contentDescription,
)
}
@@ -331,8 +335,7 @@ private fun ErrorIcon(shouldShowError: Boolean) {
@Composable
private fun PressedKeysTextContainer(pressedKeys: List<ShortcutKey>) {
Row(
- modifier =
- Modifier.semantics(mergeDescendants = true) { liveRegion = LiveRegionMode.Polite },
+ modifier = Modifier.semantics { hideFromAccessibility() },
verticalAlignment = Alignment.CenterVertically,
) {
pressedKeys.forEachIndexed { keyIndex, key ->
@@ -495,6 +498,7 @@ private fun OutlinedInputField(
trailingIcon: @Composable () -> Unit,
isError: Boolean,
modifier: Modifier = Modifier,
+ contentDescription: String,
) {
OutlinedTextField(
value = "",
@@ -502,7 +506,10 @@ private fun OutlinedInputField(
placeholder = if (content == null) placeholder else null,
prefix = content,
singleLine = true,
- modifier = modifier,
+ modifier =
+ modifier.semantics(mergeDescendants = true) {
+ this.contentDescription = contentDescription
+ },
trailingIcon = trailingIcon,
colors =
OutlinedTextFieldDefaults.colors()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index 36c5ae0717be..688573df9ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -24,6 +24,7 @@ sealed interface ShortcutCustomizationUiState {
val errorMessage: String = "",
val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon,
val pressedKeys: List<ShortcutKey> = emptyList(),
+ val pressedKeysDescription: String = "",
) : ShortcutCustomizationUiState
data object DeleteShortcutDialog : ShortcutCustomizationUiState
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index f4ba99c6a394..aeedc4b7d618 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -26,6 +26,7 @@ import androidx.compose.ui.input.key.nativeKeyCode
import androidx.compose.ui.input.key.type
import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor
+import com.android.systemui.keyboard.shortcut.extensions.toContentDescription
import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
@@ -185,7 +186,11 @@ constructor(
_shortcutCustomizationUiState.update { uiState ->
if (uiState is AddShortcutDialog) {
- uiState.copy(pressedKeys = keys, errorMessage = errorMessage)
+ uiState.copy(
+ pressedKeys = keys,
+ errorMessage = errorMessage,
+ pressedKeysDescription = getAccessibilityDescForPressedKeys(keys),
+ )
} else {
uiState
}
@@ -193,11 +198,25 @@ constructor(
}
}
+ private fun getAccessibilityDescForPressedKeys(keys: List<ShortcutKey>): String {
+ val andConjunction =
+ context.getString(R.string.shortcut_helper_key_combinations_and_conjunction)
+ return buildString {
+ keys.forEach { key ->
+ key.toContentDescription(context)?.let {
+ if (isNotEmpty()) {
+ append(", $andConjunction ")
+ }
+ append(it)
+ }
+ }
+ }
+ }
+
private suspend fun getErrorMessageForPressedKeys(keys: List<ShortcutKey>): String {
return if (keys.isEmpty() or isSelectedKeyCombinationAvailable()) {
""
- }
- else {
+ } else {
context.getString(R.string.shortcut_customizer_key_combination_in_use_error_message)
}
}