Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61ef498a authored by Amanda Lin Dietz's avatar Amanda Lin Dietz
Browse files

[A11y][Keyboard shortcuts] Update Voice Access dialog strings

* Update the Voice Access dialog strings to accurately reflect the
  behavior of the dialog.
* Refactor the Voice Access dialog logic.

Bug: 438518742
Flag: com.android.hardware.input.enable_voice_access_key_gestures
Test: AccessibilityShortcutsRepositoryImplTest, manually tested
Change-Id: I7b8c30cc122187189bc0d422b375a7e742610afe
parent 5f726610
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -115,8 +115,8 @@ class AccessibilityShortcutsRepositoryImplTest : SysuiTestCase() {
            // compare its value here.
            assertThat(contentText?.toString())
                .isEqualTo(
                    "Action icon + Alt + M is the keyboard shortcut to use Magnification." +
                        " This allows you to quickly zoom in on the screen to make content larger." +
                    "Action icon + Alt + M is the keyboard shortcut to use Magnification. This" +
                            " allows you to quickly zoom in on the screen to make content larger." +
                            " Press Action icon + Alt and \"+\" or \"-\" to adjust zoom."
                )
        }
@@ -148,8 +148,7 @@ class AccessibilityShortcutsRepositoryImplTest : SysuiTestCase() {
            val metaState = KeyEvent.META_META_ON or KeyEvent.META_ALT_ON
            val type = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS

            val a11yServiceInfo = spy(getMockAccessibilityServiceInfo("Voice access"))
            whenever(a11yServiceInfo.loadIntro(any())).thenReturn("Voice access default Intro.")
            val a11yServiceInfo = spy(getMockAccessibilityServiceInfo("Voice Access"))
            whenever(
                    accessibilityManager.getInstalledServiceInfoWithComponentName(
                        ComponentName.unflattenFromString(getTargetNameByType(type))
@@ -166,15 +165,15 @@ class AccessibilityShortcutsRepositoryImplTest : SysuiTestCase() {
                )

            assertThat(titleToContent).isNotNull()
            assertThat(titleToContent?.first).isEqualTo("Turn on Voice access?")
            assertThat(titleToContent?.first).isEqualTo("Turn on Voice Access keyboard shortcut?")
            val contentText = titleToContent?.second
            assertThat(hasExpectedAnnotation(contentText)).isTrue()
            // The intro should be the string below instead of the intro from
            // AccessibilityServiceInfo.
            assertThat(contentText?.toString())
                .isEqualTo(
                    "Action icon + Alt + V is the keyboard shortcut to use Voice access." +
                        " Voice access lets you control your device hands-free."
                    "Pressing Action icon + Alt + V turns on Voice Access, an accessibility" +
                            " feature. This lets you control your device hands-free."
                )
        }
    }
+10 −3
Original line number Diff line number Diff line
@@ -2920,11 +2920,9 @@
    <!-- Text for the dialog title. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_dialog_title">Turn on <xliff:g name="feature_name" example="Magnification">%1$s</xliff:g>?</string>
    <!-- Text for showing inside the dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_dialog_content">Action <annotation id="action_key_icon">icon</annotation> + <xliff:g name="secondary_key" example="Alt">^1</xliff:g> + <xliff:g name="key_code" example="M">^2</xliff:g> is the keyboard shortcut to use <xliff:g name="feature_name" example="Voice Access">^3</xliff:g>. <xliff:g name="feature_intro" example="Voice Access intro">^4</xliff:g></string>
    <string name="accessibility_key_gesture_dialog_content">Action <annotation id="action_key_icon">icon</annotation> + <xliff:g name="secondary_key" example="Alt">^1</xliff:g> + <xliff:g name="key_code" example="M">^2</xliff:g> is the keyboard shortcut to use <xliff:g name="feature_name" example="TalkBack">^3</xliff:g>. <xliff:g name="feature_intro" example="TalkBack intro">^4</xliff:g></string>
    <!-- The text for the TalkBack introduction. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_dialog_talkback_intro"><xliff:g name="feature_name" example="TalkBack">%1$s</xliff:g> is a screen reader that allows you to hear items spoken aloud. It can be helpful for people who have difficulty seeing the screen.</string>
    <!-- The text for the Voice Access introduction. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_dialog_va_intro"><xliff:g name="feature_name" example="Voice Access">%1$s</xliff:g> lets you control your device hands-free.</string>
    <!-- Positive button text for the dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_dialog_positive_button_text">Turn on</string>

@@ -2937,6 +2935,15 @@
    <!-- Positive button text for the Magnification dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_magnification_dialog_positive_button_text">Keep on</string>

    <!-- Text for the Voice Access dialog title. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_voice_access_dialog_title">Turn on <xliff:g name="feature_name" example="Voice Access">%1$s</xliff:g> keyboard shortcut?</string>
    <!-- Text for showing inside the Voice Access dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_voice_access_dialog_content">Pressing Action <annotation id="action_key_icon">icon</annotation> + <xliff:g name="secondary_key" example="Alt">^1</xliff:g> + <xliff:g name="key_code" example="M">^2</xliff:g> turns on <xliff:g name="feature_name" example="Voice Access">^3</xliff:g>, an accessibility feature. This lets you control your device hands-free.</string>
    <!-- Negative button text for the Voice Access dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_voice_access_dialog_negative_button_text">Don\'t turn on</string>
    <!-- Positive button text for the Voice Access dialog. [CHAR LIMIT=NONE] -->
    <string name="accessibility_key_gesture_voice_access_dialog_positive_button_text">Turn on shortcut</string>

    <!-- Plugin control section of the tuner. Non-translatable since it should
         not appear on production builds ever. -->
    <string name="plugins" translatable="false">Plugins</string>
+111 −65
Original line number Diff line number Diff line
@@ -80,39 +80,28 @@ constructor(
        targetName: String,
    ): Pair<String, CharSequence>? {
        // TODO: b/419026315 - Update the secondary modifier key label.
        val secondaryModifierLabel = ShortcutHelperKeys.modifierLabels[MODIFIER_KEY xor metaState]
        val keyCodeLabel = keyCodeMap[keyCode]
        val secondaryModifierLabel =
            ShortcutHelperKeys.modifierLabels[MODIFIER_KEY xor metaState] ?: return null
        val keyCodeLabel = keyCodeMap[keyCode] ?: return null

        if (secondaryModifierLabel == null || keyCodeLabel == null) {
            return null
        }

        if (keyGestureType == KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION) {
            val featureName =
                resources.getString(
                    com.android.settingslib.R.string.accessibility_screen_magnification_title
                )
            val title =
                resources.getString(
                    R.string.accessibility_key_gesture_magnification_dialog_title,
                    featureName,
                )
        when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION,
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS -> {
                val featureName = getFeatureName(keyGestureType, targetName) ?: return null
                val title = getFeatureTitle(keyGestureType, featureName) ?: return null
                val content =
                TextUtils.expandTemplate(
                    resources.getText(
                        R.string.accessibility_key_gesture_magnification_dialog_content
                    ),
                    getFeatureContent(
                        keyGestureType,
                        secondaryModifierLabel.invoke(context),
                        keyCodeLabel,
                        featureName,
                )
                    ) ?: return null

                return Pair(title, content)
        } else {
            val featureNameToIntro = getFeatureNameToIntro(keyGestureType, targetName)
            if (featureNameToIntro == null) {
                return null
            }

            else -> {
                val featureNameToIntro =
                    getFeatureNameToIntro(keyGestureType, targetName) ?: return null
                val title =
                    resources.getString(
                        R.string.accessibility_key_gesture_dialog_title,
@@ -130,6 +119,7 @@ constructor(
                return Pair(title, content)
            }
        }
    }

    override fun getActionKeyIconResId(): Int {
        // TODO: b/419026315 - Update the modifier key icon res id based on keyboard device.
@@ -146,12 +136,75 @@ constructor(
        )
    }

    private suspend fun getFeatureName(keyGestureType: Int, targetName: String): CharSequence? {
        return when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION ->
                resources.getString(
                    com.android.settingslib.R.string.accessibility_screen_magnification_title
                )
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS -> {
                val componentName = ComponentName.unflattenFromString(targetName)
                withContext(backgroundDispatcher) {
                    accessibilityManager
                        .getInstalledServiceInfoWithComponentName(componentName)
                        ?.resolveInfo
                        ?.loadLabel(packageManager)
                        ?.let { formatFeatureName(it) }
                }
            }
            else -> null
        }
    }

    private suspend fun getFeatureTitle(keyGestureType: Int, featureName: CharSequence): String? {
        return when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION -> {
                resources.getString(
                    R.string.accessibility_key_gesture_magnification_dialog_title,
                    featureName,
                )
            }
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS -> {
                resources.getString(
                    R.string.accessibility_key_gesture_voice_access_dialog_title,
                    featureName,
                )
            }
            else -> null
        }
    }

    private fun getFeatureContent(
        keyGestureType: Int,
        secondaryModifierLabel: String,
        keyCodeLabel: String,
        featureName: CharSequence,
    ): CharSequence? {
        val contentTemplateResId: Int? =
            when (keyGestureType) {
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION ->
                    R.string.accessibility_key_gesture_magnification_dialog_content
                KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS ->
                    R.string.accessibility_key_gesture_voice_access_dialog_content
                else -> null
            }

        return contentTemplateResId?.let { resId ->
            val contentTemplate = resources.getText(resId)
            TextUtils.expandTemplate(
                contentTemplate,
                secondaryModifierLabel,
                keyCodeLabel,
                featureName,
            )
        }
    }

    private suspend fun getFeatureNameToIntro(
        keyGestureType: Int,
        targetName: String,
    ): Pair<CharSequence, CharSequence>? {
        return when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS,
            KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK,
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SCREEN_READER -> {
                val accessibilityServiceInfo =
@@ -159,11 +212,8 @@ constructor(
                        accessibilityManager.getInstalledServiceInfoWithComponentName(
                            ComponentName.unflattenFromString(targetName)
                        )
                    }
                    } ?: return null

                if (accessibilityServiceInfo == null) {
                    null
                } else {
                val featureName =
                    formatFeatureName(
                        accessibilityServiceInfo.resolveInfo.loadLabel(packageManager)
@@ -178,7 +228,6 @@ constructor(

                Pair(featureName, intro)
            }
            }
            else -> null
        }
    }
@@ -205,9 +254,6 @@ constructor(
                    featureName,
                )

            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS ->
                resources.getString(R.string.accessibility_key_gesture_dialog_va_intro, featureName)

            else -> defaultIntro ?: ""
        }
    }
+33 −19
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.accessibility.keygesture.ui

import android.annotation.StringRes
import android.hardware.input.KeyGestureEvent
import android.text.Annotation
import android.text.Spanned
@@ -90,25 +91,8 @@ constructor(
            return
        }

        val negativeButtonTextId =
            if (
                keyGestureConfirmInfo.keyGestureType ==
                    KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION
            ) {
                R.string.accessibility_key_gesture_magnification_dialog_negative_button_text
            } else {
                android.R.string.cancel
            }

        val positiveButtonTextId =
            if (
                keyGestureConfirmInfo.keyGestureType ==
                    KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION
            ) {
                R.string.accessibility_key_gesture_magnification_dialog_positive_button_text
            } else {
                R.string.accessibility_key_gesture_dialog_positive_button_text
            }
        val negativeButtonTextId = getNegativeButtonTextId(keyGestureConfirmInfo.keyGestureType)
        val positiveButtonTextId = getPositiveButtonTextId(keyGestureConfirmInfo.keyGestureType)

        currentDialog =
            dialogFactory.create { dialog ->
@@ -159,6 +143,36 @@ constructor(
        }
    }

    @StringRes
    private fun getNegativeButtonTextId(keyGestureType: Int): Int {
        return when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION -> {
                R.string.accessibility_key_gesture_magnification_dialog_negative_button_text
            }
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS -> {
                R.string.accessibility_key_gesture_voice_access_dialog_negative_button_text
            }
            else -> {
                android.R.string.cancel
            }
        }
    }

    @StringRes
    private fun getPositiveButtonTextId(keyGestureType: Int): Int {
        return when (keyGestureType) {
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION -> {
                R.string.accessibility_key_gesture_magnification_dialog_positive_button_text
            }
            KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_VOICE_ACCESS -> {
                R.string.accessibility_key_gesture_voice_access_dialog_positive_button_text
            }
            else -> {
                R.string.accessibility_key_gesture_dialog_positive_button_text
            }
        }
    }

    private fun buildAnnotatedStringFromResource(resourceText: CharSequence): AnnotatedString {
        // `resourceText` is an instance of SpannableStringBuilder, so we can cast it to a Spanned.
        val spanned = resourceText as? Spanned ?: return AnnotatedString(resourceText.toString())