From c437295066d573028542b4df5a173da50f69cacf Mon Sep 17 00:00:00 2001 From: Aaron Hewitt Date: Fri, 9 Oct 2026 13:18:29 +0100 Subject: [PATCH] Name the reading control actions in the reading control hints The hints for reading controls such as Brightness or Speech rate said "swipe up or swipe down to adjust the setting" on selecting one, and "swipe up with 3 fingers or swipe down with 3 fingers to select a different setting" after changing it, so after a change the hint said how to leave the reading control rather than how to change it. Once any hint for adjusting a reading control had been spoken, the second hint named the adjust gestures instead, as "swipe up or swipe down to select a different setting", because both used the same cache. Both hints now name the actions and their gestures, with the action titles from the gesture settings, which are translated: "Move reading control up or backward: Swipe up" and "Move reading control down or forward: Swipe down", on selecting and after changing a reading control. "No action available" on the Actions reading control, and "Spoken language unavailable while using a voice profile", name "Previous reading control" and "Next reading control" with their gestures. An action with no gesture names Backtalk settings > Gestures. Limitations: the hint doesn't name the reading control. --- .../talkback/selector/SelectorController.java | 110 +++++++----------- 1 file changed, 41 insertions(+), 69 deletions(-) diff --git a/talkback/src/main/java/com/google/android/accessibility/talkback/selector/SelectorController.java b/talkback/src/main/java/com/google/android/accessibility/talkback/selector/SelectorController.java index e08de34e..cd09839f 100644 --- a/talkback/src/main/java/com/google/android/accessibility/talkback/selector/SelectorController.java +++ b/talkback/src/main/java/com/google/android/accessibility/talkback/selector/SelectorController.java @@ -97,6 +97,7 @@ import com.google.android.accessibility.talkback.focusmanagement.LiftToActivateMode; import com.google.android.accessibility.talkback.focusmanagement.action.NavigationAction; import com.google.android.accessibility.talkback.focusmanagement.record.FocusActionInfo; +import com.google.android.accessibility.talkback.gesture.GestureHints; import com.google.android.accessibility.talkback.gesture.GestureShortcutMapping; import com.google.android.accessibility.talkback.menurules.NodeMenuRuleCreator; import com.google.android.accessibility.talkback.monitor.VolumeMonitor; @@ -575,11 +576,6 @@ static boolean isValid(Granularity granularity, ActorState actorState) { private final GestureShortcutMapping gestureMapping; @NonNull private final Compositor.TextComposer compositor; - /** - * Keeps gestures to announce the usage hint for how to select setting (change quick menu item). - */ - private @Nullable String cachedSelectSettingGestureNames; - /** * Keeps gestures to announce the usage hint for how to adjust selected setting (change quick menu * item action). @@ -661,7 +657,6 @@ static boolean isValid(Granularity granularity, ActorState actorState) { (prefs, key) -> { // Clears selector gestures but doesn't update them now because GestureShortcutMapping // hasn't finished reloading yet. - cachedSelectSettingGestureNames = null; cachedAdjustSelectedSettingGestureNames = null; }; @@ -1592,58 +1587,35 @@ private void announceSetting( } /** - * Returns the usage hint when adjusting the selected setting, like "three-finger swipe left or - * three-finger swipe right to select a different setting." + * Returns the usage hint for choosing another reading control, for when the selected one can't + * be used: a line for each action with its gesture, such as "Next reading control: Swipe down + * then up". */ @NonNull private String getSelectSettingGestures() { - String selectSettingGestureNames = getSelectSettingGestureNames(); - if (selectSettingGestureNames.isEmpty()) { - // There is no gesture to select setting. - return context.getString( - R.string.no_adjust_setting_gesture, - Ascii.toLowerCase(context.getString(R.string.shortcut_select_next_setting))); - } - return context.getString(R.string.select_setting_hint, selectSettingGestureNames); + return actionLines( + R.string.shortcut_value_select_previous_setting, + R.string.shortcut_value_select_next_setting); } - @NonNull - private String getSelectSettingGestureNames() { - String selectSettingGestureNames = cachedSelectSettingGestureNames; - if (selectSettingGestureNames == null) { - List rawNames = - gestureMapping.getGestureTextsFromActionKeys( - context.getString(R.string.shortcut_value_select_previous_setting), - context.getString(R.string.shortcut_value_select_next_setting)); - if (rawNames.isEmpty()) { - selectSettingGestureNames = ""; - } else if (rawNames.size() == 1) { - selectSettingGestureNames = Ascii.toLowerCase(rawNames.get(0)); - } else { - selectSettingGestureNames = - context.getString( - R.string.gesture_1_or_2, - Ascii.toLowerCase(rawNames.get(0)), - Ascii.toLowerCase(rawNames.get(1))); - } - cachedSelectSettingGestureNames = selectSettingGestureNames; - } - return selectSettingGestureNames; + /** + * Returns the usage hint when selecting or changing a setting: a line for each action with its + * gesture, such as "Move reading control down or forward: Swipe down". + */ + private String getAdjustSelectedSettingGestures() { + return actionLines( + R.string.shortcut_value_selected_setting_previous_action, + R.string.shortcut_value_selected_setting_next_action); } /** - * Returns the usage hint when selecting a setting, like "swipe up or swipe down to to adjust the - * setting." + * Returns a line for each of two gesture actions, named from translated action titles and + * gesture names, or the gesture settings for an action with no gesture. */ - private String getAdjustSelectedSettingGestures() { - String adjustSelectedSettingsGestureNames = getAdjustSelectedSettingGestureNames(); - if (adjustSelectedSettingsGestureNames.isEmpty()) { - // There is no gesture to adjust setting. - return context.getString( - R.string.no_adjust_setting_gesture, - Ascii.toLowerCase(context.getString(R.string.shortcut_selected_setting_next_action))); - } - return context.getString(R.string.adjust_setting_hint, adjustSelectedSettingsGestureNames); + private String actionLines(@StringRes int firstAction, @StringRes int secondAction) { + return GestureHints.actionLine(context, gestureMapping, firstAction) + + "\n" + + GestureHints.actionLine(context, gestureMapping, secondAction); } /** @@ -1718,7 +1690,7 @@ private String getAdjustSelectedSettingGestureNames() { Ascii.toLowerCase(rawNames.get(0)), Ascii.toLowerCase(rawNames.get(1))); } - cachedSelectSettingGestureNames = adjustSelectedSettingGestureNames; + cachedAdjustSelectedSettingGestureNames = adjustSelectedSettingGestureNames; } return adjustSelectedSettingGestureNames; } @@ -1813,7 +1785,7 @@ public void adjustSelectedSetting(EventId eventId, boolean isNext) { return; } case SWITCH_VOICE_PROFILE -> { - changeVoiceProfile(eventId, isNext, getSelectSettingGestures()); + changeVoiceProfile(eventId, isNext, getAdjustSelectedSettingGestures()); return; } case GRANULARITY -> { @@ -2031,7 +2003,7 @@ public void changeSpeechRate(EventId eventId, boolean isIncrease) { context.getString( R.string.template_speech_rate_change, actorState.getSpeechRateState().getSpeechRatePercentage()); - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, displayText); } @@ -2076,7 +2048,7 @@ private void changeLanguage(EventId eventId, boolean isNext) { announceSetting( eventId, actorState.getLanguageState().getCurrentLanguageString(), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, actorState.getLanguageState().getCurrentLanguageString()); } @@ -2120,7 +2092,7 @@ private void changeVerbosity(EventId eventId, boolean isNext) { announceSetting( eventId, VerbosityPreferences.getVerbosityChangeAnnouncement(newVerbosity, context), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, VerbosityPreferences.verbosityValueToName(newVerbosity, context)); } @@ -2142,7 +2114,7 @@ private void cycleEmojiSpeech(EventId eventId, boolean isNext) { announceSetting( eventId, context.getString(R.string.emoji_speech_state, entries[index]), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, entries[index]); } @@ -2169,7 +2141,7 @@ public void cycleSpeakPunctuationVerbosity(EventId eventId, int triggerAction) { announceSetting( eventId, context.getString(R.string.punctuation_state, punctuationEntries[punctuationLevel]), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, punctuationEntries[punctuationLevel]); } @@ -2194,7 +2166,7 @@ public void changeVerbosity(EventId eventId, int newIndex) { announceSetting( eventId, VerbosityPreferences.getVerbosityChangeAnnouncement(newVerbosity, context), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); } private void toggleTextFormatting(EventId eventId) { @@ -2214,7 +2186,7 @@ private void toggleTextFormatting(EventId eventId) { toggleTextFormatting ? context.getString(R.string.value_on) : context.getString(R.string.value_off)), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, context.getString(toggleTextFormatting ? R.string.value_on : R.string.value_off)); } @@ -2227,7 +2199,7 @@ private void showOrHideScreen(EventId eventId) { announceSetting( eventId, context.getString(R.string.screen_brightness_restored), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, context.getString(R.string.shortcut_disable_dimming)); } else { // Dims the screen. @@ -2254,7 +2226,7 @@ private void switchOnOrOffAudioDucking(EventId eventId) { !audioFocusOn ? context.getString(R.string.value_on) : context.getString(R.string.value_off)), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, context.getString(!audioFocusOn ? R.string.value_on : R.string.value_off)); } @@ -2281,7 +2253,7 @@ public void onVolumeChanged(int type, int value, int prevValue, int percent) { ? R.string.template_accessibility_volume_change_decrease : R.string.template_accessibility_volume_change_increase, percent); - announceSetting(lastChangeAccessibilityEventId, displayText, getSelectSettingGestures()); + announceSetting(lastChangeAccessibilityEventId, displayText, getAdjustSelectedSettingGestures()); TalkBackUI.Item item = value < prevValue ? Item.ITEM_ACCESSIBILITY_VOLUME_DECREASE @@ -2309,7 +2281,7 @@ public void changeAccessibilityVolume(EventId eventId, boolean decreaseVolume) { : R.string.template_volume_change_maximum, context.getString( R.string.tb_template_percent, String.valueOf(accessibilityVolumePercent()))); - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); TalkBackUI.Item item = decreaseVolume ? Item.ITEM_ACCESSIBILITY_VOLUME_MINIMUM @@ -2338,7 +2310,7 @@ private void changeBrightness(EventId eventId, boolean increase) { context.getString( R.string.template_brightness_changed, ScreenBrightness.getPercent(context))); } - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, displayText); } @@ -2358,7 +2330,7 @@ private void changeTouchFocusLatency(EventId eventId, boolean decreaseLatency) { ? R.string.template_touch_latency_reach_minimum : R.string.template_touch_latency_reach_maximum, focusDelayText()); - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, displayText); } } @@ -2379,7 +2351,7 @@ private void changeTypingFocusLatency(EventId eventId, boolean decreaseLatency) ? R.string.template_touch_latency_reach_minimum : R.string.template_touch_latency_reach_maximum, typingFocusDelayText()); - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, displayText); } } @@ -2398,7 +2370,7 @@ private void changeLiftToActivate(EventId eventId, boolean isNext) { context.getResources().getStringArray(R.array.pref_lift_to_activate_entries)[ updated.ordinal()]; String displayText = context.getString(R.string.template_lift_to_activate_changed, modeName); - announceSetting(eventId, displayText, getSelectSettingGestures()); + announceSetting(eventId, displayText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay(eventId, displayText); } @@ -2522,7 +2494,7 @@ private void switchWrapAroundOnOrOff(EventId eventId) { announceSetting( eventId, context.getString(switchedValue ? R.string.wrap_around_on : R.string.wrap_around_off), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, context.getString(switchedValue ? R.string.value_on : R.string.value_off)); } @@ -2536,7 +2508,7 @@ private void switchTabletHeldUpFacesAwayOnOrOff(EventId eventId) { switchedValue ? R.string.tablet_held_up_faces_away_on : R.string.tablet_held_up_faces_away_off), - getSelectSettingGestures()); + getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, context.getString(switchedValue ? R.string.value_on : R.string.value_off)); } @@ -2559,7 +2531,7 @@ private void switchTellingTimeOnOrOff(EventId eventId) { } else { announcementText = context.getString(R.string.speak_time_off); } - announceSetting(eventId, announcementText, getSelectSettingGestures()); + announceSetting(eventId, announcementText, getAdjustSelectedSettingGestures()); showQuickMenuActionOverlay( eventId, context.getString(switchedValue ? R.string.value_on : R.string.value_off)); }