Skip to content

TalkBack, 5 of 10: Improve Settings item accessibility - #6161

Open
eliotcougar wants to merge 6 commits into
2dust:masterfrom
eliotcougar:fix/accessibility-settings-rows
Open

eliotcougar wants to merge 6 commits into
2dust:masterfrom
eliotcougar:fix/accessibility-settings-rows

Conversation

@eliotcougar

@eliotcougar eliotcougar commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Part 5 of the TalkBack series improves the existing shared Settings row primitives. Edit, list, menu, and switch rows expose one logical accessibility control, including when disabled. Persistence, screen-specific actions, and visible preference text remain unchanged.

Accessibility model

  • The existing clickable and toggleable modifiers merge the title and supporting text into the row that owns the action.
  • Switch rows use toggleable(value = checked, enabled = enabled, role = Role.Switch). The row owns the observable checked state and the single activation callback.
  • The visible Switch(onCheckedChange = null) is decoration, not a second action target. Touching the row or its trailing switch, accessibility activation, Enter, Space, and D-pad center use the row action.
  • An app-localized On/Off stateDescription changes with the checked state, providing native state-change feedback without a custom announcement or moving accessibility focus.
  • Disabled rows keep the same semantic structure with enabled = false; their label and supporting text stay grouped and the action cannot execute.
  • Collapsible groups keep their native Button role. Their localized label includes the group name followed by the expanded/collapsed wording, for example “Core settings. Group is expanded”. The child title's semantics are cleared because the parent label already contains it. This is a combined group label, not a separate stateDescription.

The language chooser retains its existing native selectable radio rows. This PR does not change its selection behavior.

No direct accessibility announcements, live-region layer, focus manipulation, custom action menus, or native role suppression are introduced here. Android/TalkBack still controls role and disabled-state wording and the final spoken order.

Relevant official guidance: Compose API defaults, semantics, and merging and clearing semantics.

Known announcement-order limitation

TalkBack may read a switch row's long supporting description before its on/off state. That delays discovery of the setting's most important current information.

Traversal ordering controls the order of separate nodes, not the order of text, state, and role within a merged node. This PR does not put the description into stateDescription or replace the switch's native semantics with a forced spoken sentence.

A possible separately reviewed follow-up is to keep the primary switch row concise and move genuinely long explanations behind a named Info action opening a readable modal. Short descriptions could remain inline. That UI change is not implemented here.

Localization and scope

The four resources—group expanded/collapsed labels and On/Off state descriptions—are present in all nine maintained catalogs: English, Arabic, Bengali, Bakhtiari, Persian, Russian, Vietnamese, Simplified Chinese, and Traditional Chinese. App-provided labels use the app locale; native role and disabled wording are supplied by Android/TalkBack.

Production changes are confined to SettingsItem.kt and these resource entries. All existing callers benefit without screen-specific callbacks, business-logic changes, or additional state holders. Notification/live-region work and the other focused list PRs remain independent.

Review refinements

Commit 39637fafc adds the following refinements:

  • Restore the Material minimum-size layout padding lost when the enabled child Switch became non-interactive. This preserves the former switch footprint; the row remains the only toggle. Disabled switches retain their existing footprint.
  • Mark collapsible group buttons as headings without duplicating their name or removing the native Button action.
  • Replace the version-specific feedback comment with a concise explanation of the observable state description.
  • Remove the obsolete three-file Android-only probe harness. Temporary emulator instrumentation stays outside the repository; the resulting PR diff is one production file and nine string catalogs.

Validation at 39637fafc

  • :app:testPlaystoreDebugUnitTest: 57 tests passed, zero failures, errors, or skips.
  • :app:compilePlaystoreDebugKotlin and :app:assemblePlaystoreDebug: passed.
  • All nine catalogs passed key-presence, uniqueness, and group-name placeholder checks; resource compilation and git diff --check passed.
  • Android API 37.1 x86_64 emulator with TalkBack enabled: the real Settings switch row exposed one checkable node and one activation target. Native accessibility click, touch on the row and trailing switch, Enter, Space, and D-pad center each toggled and restored its state.
  • Native state-description change events were observed for On and Off; accessibility-click activation retained focus on the row.
  • Collapsible groups retained one heading and native Button semantics through an expand/collapse round trip.
  • The short “Check pre-release versions” row measured 80 dp and retained one toggle target with immediate native state-change events.
  • Disabled “VPN DNS” and “Add HTTP proxy to VPN” rows exposed their disabled state and rejected accessibility activation.
  • Pairwise git merge-tree checks against all nine companion branches passed in both orders and produced identical trees. This commit also merges cleanly with fetched upstream/master.

Not run: audio-level verification of the exact spoken phrase/order, a physical-device repeat, older Android versions, and the full light/dark, dynamic-color, single/two-column shared-consumer rendering matrix. The emulator evidence above verifies native nodes, events, focus, and activation; it is not a claim about every TalkBack voice or device.

Make shared Settings rows expose one native interaction node, including disabled preferences. Use a genuine row-level switch toggle, keep the visual switch non-interactive, and localize collapsible group state in every maintained catalog.
@eliotcougar eliotcougar changed the title TalkBack, 5 of N: Improve Settings item accessibility TalkBack, 5 of 10: Improve Settings item accessibility Aug 30, 2026
@eliotcougar
eliotcougar marked this pull request as ready for review August 30, 2026 18:00
Use one localized name-first disclosure label and clear only the redundant visible title semantics. Keep the native button role and expand/collapse action, without a separate state prefix.

Update all nine locales and add device regression tests covering label uniqueness, state changes, the button role, and accessibility activation. Unit tests and Play Store debug assembly pass; both instrumentation tests pass on API 30. TalkBack audio was not tested because TalkBack is not installed on the emulator.
Keep the settings row as the sole native switch target, with observable
checked state and a passive child Switch. Add localized stateDescription
values in all nine supported locales; disabled controls remain disabled.

With Compose UI 1.11.4, implicit toggle changes emit the CHECKED content
change but not STATE_DESCRIPTION. On the tested TalkBack 17 build this
updates the node without speaking its new state. Deriving stateDescription
from checked state makes Compose emit the native event TalkBack expects.
No custom announcement, role suppression or focus request is introduced.

Add a native-event regression test for both directions on the same
accessibility-focused row, disabled controls, row/child-area pointer input,
Enter, Space and D-pad activation. The shared probe keeps TalkBack enabled.

Validation: 57 Play Store debug unit tests passed; app and androidTest APKs
assembled; SettingsToggleFeedbackTest passed on the Android 37.1 Pixel 9 Pro
emulator with TalkBack 17. Speech-controller logs confirmed On and Off from
state-change events without refocusing. Physical-device gestures and the
full supported Android-version matrix were not tested.
@aliRahimi1997

Copy link
Copy Markdown
Contributor

The switch state feedback issue is still present in #6161.

I tested the updated switch implementation in #6164 (Per-App Proxy), and the two switches there now behave correctly: after turning a switch on or off, TalkBack immediately reports the new state without requiring the user to leave the control and return to it.

Could #6161 use the same approach/pattern as the updated #6164 implementation for its Settings switches?

There is also another affected switch in the "Check for update" section:
"Off. Check pre-release versions. Switch"

When I toggle this switch, TalkBack does not announce the new state at all. I have to move away from the switch and come back to it to hear whether it is on or off.

So the desired behavior is the same as in the updated #6164 implementation: after toggling a switch, TalkBack should immediately report its new on/off state, while keeping the native switch semantics and without adding custom announcements.

@aliRahimi1997

Copy link
Copy Markdown
Contributor

I retested #6161 from a clean branch based on upstream/master, including the latest commit bdfe08b.

I can confirm that the Settings switches now provide immediate On/Off feedback with TalkBack, without requiring focus to leave and return to the control.

I also retested the "Check pre-release versions" switch, which now behaves correctly as well.

This matches the improved switch behavior I observed in #6164. My earlier report about the missing immediate state feedback was based on my previous test result and can be considered resolved.

@eliotcougar
eliotcougar marked this pull request as draft September 5, 2026 11:12
Keep Material minimum-size layout padding for enabled decorative switches while the parent row remains the sole toggle. Leave disabled rows and the tested localized state-description feedback unchanged.

Expose collapsible Settings groups as headings without changing their name-first label or native button action. Replace the version-specific feedback comment with its semantic purpose and remove the obsolete Android-only probe harness from this focused PR.
Keep upstream resource corrections while retaining the focused Settings row semantics. The remaining feature diff is limited to the shared row component and its four localized accessibility labels.
@eliotcougar
eliotcougar marked this pull request as ready for review September 21, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants