Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt +16 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,10 @@ object TestShortcuts { key("Shift") key("M") } contentDescription { "${shortcutInfoWithRepeatedLabel.label}, " + "Press key Meta plus H, or Meta plus L, or Shift plus M" } } private val goHomeShortcutInfo = Loading @@ -109,6 +113,7 @@ object TestShortcuts { key(R.drawable.ic_ksh_key_meta) key("N") } contentDescription { "${standardShortcutInfo1.label}, Press key Meta plus N" } } private val customGoHomeShortcut = Loading @@ -119,6 +124,7 @@ object TestShortcuts { key("A") isCustom(true) } contentDescription { "Go to home screen, Press key Ctrl plus Alt plus A" } } private val standardShortcutInfo2 = Loading @@ -135,6 +141,7 @@ object TestShortcuts { key("Shift") key("Z") } contentDescription { "${standardShortcutInfo2.label}, Press key Alt plus Shift plus Z" } } private val standardShortcutInfo3 = Loading @@ -150,6 +157,7 @@ object TestShortcuts { key("Ctrl") key("J") } contentDescription { "${standardShortcutInfo3.label}, Press key Ctrl plus J" } } private val shortcutInfoWithUnsupportedModifiers = Loading Loading @@ -205,6 +213,7 @@ object TestShortcuts { key("Ctrl") key("Space") } contentDescription { "Switch to next language, Press key Ctrl plus Space" } } private val switchToPreviousLanguageShortcut = Loading @@ -214,6 +223,9 @@ object TestShortcuts { key("Shift") key("Space") } contentDescription { "Switch to previous language, Press key Ctrl plus Shift plus Space" } } private val subCategoryForInputLanguageSwitchShortcuts = Loading Loading @@ -292,6 +304,10 @@ object TestShortcuts { key("A") isCustom(true) } contentDescription { "Go to home screen, Press key Ctrl plus Alt plus B, " + "or Ctrl plus Alt plus A" } } ), ) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,42 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() { } } @Test fun categories_addsSameContentDescriptionForShortcutsOfSameType() { testScope.runTest { setCustomInputGestures(listOf(customInputGestureTypeHome)) systemShortcutsSource.setGroups(groupWithGoHomeShortcutInfo) helper.showFromActivity() val categories by collectLastValue(interactor.shortcutCategories) val contentDescriptions = categories?.flatMap { it.subCategories.flatMap { it.shortcuts.map { it.contentDescription } } } assertThat(contentDescriptions) .containsExactly( "Go to home screen, Press key Ctrl plus Alt plus B, or Ctrl plus Alt plus A", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 3, Press key Ctrl plus J", "Switch to next language, Press key Ctrl plus Space", "Switch to previous language, Press key Ctrl plus Shift plus Space", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", ) } } private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) { whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())) .thenReturn(customInputGestures) Loading packages/SystemUI/res/values/strings.xml +8 −0 Original line number Diff line number Diff line Loading @@ -3824,6 +3824,14 @@ [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_or_separator">or</string> <!-- Word that combines different possible key combinations of a shortcut. For example the "Go to home screen" shortcut could be triggered using "ctrl" plus "h". This is only used for accessibility content descriptions of the key combinations. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_and_conjunction">plus</string> <!-- Word that represents the forward slash character "/". To be used only in accessibility content descriptions. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_forward_slash">forward slash</string> <!-- Content description of the drag handle that allows to swipe to dismiss the shortcut helper. The helper is a component that shows the user which keyboard shortcuts they can use. The helper shows shortcuts in categories, which can be collapsed or expanded. Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt +1 −0 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ object ShortcutHelperKeys { mapOf<Int, (Context) -> String>( KEYCODE_HOME to { context -> context.getString(R.string.keyboard_key_home) }, KEYCODE_BACK to { context -> context.getString(R.string.keyboard_key_back) }, KEYCODE_RECENT_APPS to { context -> context.getString(R.string.accessibility_recent) }, KEYCODE_DPAD_UP to { context -> context.getString(R.string.keyboard_key_dpad_up) }, KEYCODE_DPAD_DOWN to { context -> context.getString(R.string.keyboard_key_dpad_down) }, KEYCODE_DPAD_LEFT to { context -> context.getString(R.string.keyboard_key_dpad_left) }, Loading packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt +57 −0 Original line number Diff line number Diff line Loading @@ -16,14 +16,22 @@ 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.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 import javax.inject.Inject import kotlinx.coroutines.flow.Flow Loading @@ -34,6 +42,7 @@ import kotlinx.coroutines.flow.flowOf class ShortcutHelperCategoriesInteractor @Inject constructor( @Application private val context: Context, @DefaultShortcutCategories defaultCategoriesRepository: ShortcutCategoriesRepository, @CustomShortcutCategories customCategoriesRepositoryLazy: Lazy<ShortcutCategoriesRepository>, ) { Loading Loading @@ -87,6 +96,54 @@ constructor( label = commonLabel, icon = groupedShortcuts.firstOrNull()?.icon, commands = groupedShortcuts.flatMap { it.commands }, contentDescription = toContentDescription(commonLabel, groupedShortcuts.flatMap { it.commands }), ) } private fun toContentDescription(label: String, commands: List<ShortcutCommand>): String { val pressKey = context.getString(R.string.shortcut_helper_add_shortcut_dialog_placeholder) val andConjunction = 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 -> if (i > 0) { append(", $orConjunction") } shortcutCommand.keys.forEachIndexed { j, shortcutKey -> 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 } } } } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt +16 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,10 @@ object TestShortcuts { key("Shift") key("M") } contentDescription { "${shortcutInfoWithRepeatedLabel.label}, " + "Press key Meta plus H, or Meta plus L, or Shift plus M" } } private val goHomeShortcutInfo = Loading @@ -109,6 +113,7 @@ object TestShortcuts { key(R.drawable.ic_ksh_key_meta) key("N") } contentDescription { "${standardShortcutInfo1.label}, Press key Meta plus N" } } private val customGoHomeShortcut = Loading @@ -119,6 +124,7 @@ object TestShortcuts { key("A") isCustom(true) } contentDescription { "Go to home screen, Press key Ctrl plus Alt plus A" } } private val standardShortcutInfo2 = Loading @@ -135,6 +141,7 @@ object TestShortcuts { key("Shift") key("Z") } contentDescription { "${standardShortcutInfo2.label}, Press key Alt plus Shift plus Z" } } private val standardShortcutInfo3 = Loading @@ -150,6 +157,7 @@ object TestShortcuts { key("Ctrl") key("J") } contentDescription { "${standardShortcutInfo3.label}, Press key Ctrl plus J" } } private val shortcutInfoWithUnsupportedModifiers = Loading Loading @@ -205,6 +213,7 @@ object TestShortcuts { key("Ctrl") key("Space") } contentDescription { "Switch to next language, Press key Ctrl plus Space" } } private val switchToPreviousLanguageShortcut = Loading @@ -214,6 +223,9 @@ object TestShortcuts { key("Shift") key("Space") } contentDescription { "Switch to previous language, Press key Ctrl plus Shift plus Space" } } private val subCategoryForInputLanguageSwitchShortcuts = Loading Loading @@ -292,6 +304,10 @@ object TestShortcuts { key("A") isCustom(true) } contentDescription { "Go to home screen, Press key Ctrl plus Alt plus B, " + "or Ctrl plus Alt plus A" } } ), ) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -333,6 +333,42 @@ class ShortcutHelperCategoriesInteractorTest : SysuiTestCase() { } } @Test fun categories_addsSameContentDescriptionForShortcutsOfSameType() { testScope.runTest { setCustomInputGestures(listOf(customInputGestureTypeHome)) systemShortcutsSource.setGroups(groupWithGoHomeShortcutInfo) helper.showFromActivity() val categories by collectLastValue(interactor.shortcutCategories) val contentDescriptions = categories?.flatMap { it.subCategories.flatMap { it.shortcuts.map { it.contentDescription } } } assertThat(contentDescriptions) .containsExactly( "Go to home screen, Press key Ctrl plus Alt plus B, or Ctrl plus Alt plus A", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 3, Press key Ctrl plus J", "Switch to next language, Press key Ctrl plus Space", "Switch to previous language, Press key Ctrl plus Shift plus Space", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 3, Press key Ctrl plus J", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", "Standard shortcut 2, Press key Alt plus Shift plus Z", "Standard shortcut 1, Press key Meta plus N", ) } } private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) { whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull())) .thenReturn(customInputGestures) Loading
packages/SystemUI/res/values/strings.xml +8 −0 Original line number Diff line number Diff line Loading @@ -3824,6 +3824,14 @@ [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_or_separator">or</string> <!-- Word that combines different possible key combinations of a shortcut. For example the "Go to home screen" shortcut could be triggered using "ctrl" plus "h". This is only used for accessibility content descriptions of the key combinations. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_and_conjunction">plus</string> <!-- Word that represents the forward slash character "/". To be used only in accessibility content descriptions. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_key_combinations_forward_slash">forward slash</string> <!-- Content description of the drag handle that allows to swipe to dismiss the shortcut helper. The helper is a component that shows the user which keyboard shortcuts they can use. The helper shows shortcuts in categories, which can be collapsed or expanded. Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperKeys.kt +1 −0 Original line number Diff line number Diff line Loading @@ -140,6 +140,7 @@ object ShortcutHelperKeys { mapOf<Int, (Context) -> String>( KEYCODE_HOME to { context -> context.getString(R.string.keyboard_key_home) }, KEYCODE_BACK to { context -> context.getString(R.string.keyboard_key_back) }, KEYCODE_RECENT_APPS to { context -> context.getString(R.string.accessibility_recent) }, KEYCODE_DPAD_UP to { context -> context.getString(R.string.keyboard_key_dpad_up) }, KEYCODE_DPAD_DOWN to { context -> context.getString(R.string.keyboard_key_dpad_down) }, KEYCODE_DPAD_LEFT to { context -> context.getString(R.string.keyboard_key_dpad_left) }, Loading
packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt +57 −0 Original line number Diff line number Diff line Loading @@ -16,14 +16,22 @@ 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.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 import javax.inject.Inject import kotlinx.coroutines.flow.Flow Loading @@ -34,6 +42,7 @@ import kotlinx.coroutines.flow.flowOf class ShortcutHelperCategoriesInteractor @Inject constructor( @Application private val context: Context, @DefaultShortcutCategories defaultCategoriesRepository: ShortcutCategoriesRepository, @CustomShortcutCategories customCategoriesRepositoryLazy: Lazy<ShortcutCategoriesRepository>, ) { Loading Loading @@ -87,6 +96,54 @@ constructor( label = commonLabel, icon = groupedShortcuts.firstOrNull()?.icon, commands = groupedShortcuts.flatMap { it.commands }, contentDescription = toContentDescription(commonLabel, groupedShortcuts.flatMap { it.commands }), ) } private fun toContentDescription(label: String, commands: List<ShortcutCommand>): String { val pressKey = context.getString(R.string.shortcut_helper_add_shortcut_dialog_placeholder) val andConjunction = 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 -> if (i > 0) { append(", $orConjunction") } shortcutCommand.keys.forEachIndexed { j, shortcutKey -> 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 } } } } }