TalkBack, 6 of 10: Improve per-app proxy accessibility - #6164
eliotcougar wants to merge 6 commits into
Conversation
Expose the header options and each app row as one native control, add localized routing context without package IDs, and replace the transient information toast with a readable dialog.
…essibility Retain the original button call site and name the existing modal-opening callback locally. This avoids an adjacent-hunk conflict between the independent modal replacement in 2dust#6157 and the switch semantics in this PR, without changing behavior or importing notification code.
|
I tested PR #6164 on a real device with TalkBack enabled. The two Switch controls in the per-app proxy screen expose their current state correctly when TalkBack navigates to them. However, after toggling either Switch, TalkBack does not immediately announce the new On/Off state. To hear the updated state, I have to navigate away from the Switch and then return to it. I observed the same behavior with the Switch controls in PR #6161, so this may be a shared issue with the toggle semantics rather than something specific to the per-app proxy screen. Could you please check whether the native Compose/Material Switch semantics can expose the updated state after the toggle while preserving the native Switch role, state, and action? I am not suggesting a custom announcement or manual accessibility-focus manipulation; the goal is simply for the semantic state change to be exposed correctly to the accessibility service. Apart from this, I did not observe any other accessibility problems with the two per-app proxy Switches. |
Retain one native toggleable row with a passive child switch or checkbox. Expose the two switches' observed checked state through stateDescription so Compose sends the STATE_DESCRIPTION event required for immediate feedback on the tested TalkBack 17 / Compose UI 1.11.4 combination. Keep app names stable and move checked state plus routing context into stateDescription instead of changing the accessible label after a toggle. Preserve native roles, package-ID hiding and every enabled/bypass routing combination. Update all nine locale catalogs without splitting resources. No custom announcements or focus manipulation are added. Add native-event tests for both switch directions, app checkbox feedback in all four enabled/bypass combinations, one action target and pointer, Enter, Space and D-pad input. Validation: 60 Play Store debug unit tests passed; app and androidTest APKs assembled; both PerAppToggleFeedbackTest cases passed on the Android 37.1 Pixel 9 Pro emulator with TalkBack 17 enabled. Checked/routing feedback was observed in TalkBack output. Physical-device gestures and pronunciation in every locale were not tested.
|
One small usability observation about the Per-App Proxy checkboxes: TalkBack currently announces an item like: "Checked. routed through the app. WhatsApp Business. Tick box." From a real-world TalkBack navigation perspective, I find this order less natural because the app name is announced only after the state and description. Would it be possible for the checkbox semantics to expose the app name as the primary label, so TalkBack can naturally announce it more like: "WhatsApp Business. Checked. routed through the app. Tick box." |
I was thinking about it too. I don't really know why Android does it like that, but there is no real control over it. It is always "State - Name - Role", in this order only. Changing it requires rebuilding everything manually and removing the semantics. TalkBack will see a list of some items, but it will not be aware that they are checkboxes, or whether they are checked or unchecked. They will be just clickable items that say something when selected and do something when double-tapped. |
In this example it's like this. The only way I see here is to attach "routed through the app" to the name. Which goes against intended meaning of State and Name. |
Adopt the overlapping terminology corrections from PR 2dust#6169 and carry them into branch-only plural and accessibility resources. This keeps later merge resolution from restoring stale Bakhtiari wording.
Derive accessibility routing context from the service mode, complete installed-app snapshot, and resolved UIDs instead of checkbox state alone. Preserve the different VPN and root empty-selection rules, own-package exclusions, shared UIDs, and missing-package behavior without changing routing policy. Keep one native toggle target per row, merge the app-name Text naturally, and retain the Material control footprint after making the child controls inert. Remove the synthetic Android test harness and keep focused JVM coverage for the routing decision table. Validation: 70 JVM tests, including 13 per-app routing tests; Play Store debug compilation and x86_64 assembly; native accessibility-tree and state-change checks with TalkBack enabled on API 37.1, including touch, Enter, Space, and D-pad activation. Exact TalkBack audio and root traffic forwarding were not recorded.
Summary
Make the Per-app Proxy screen and shared app picker easier to operate with accessibility services, using genuine Compose toggle semantics. Keep routing context distinct from checkbox membership and leave service routing behavior unchanged.
Accessibility approach
toggleablerow withRole.Switch; its visible Material switch hasonCheckedChange = null.toggleablerow withRole.Checkbox. Tapping the row or visible checkbox area invokes the same selection operation; the checkbox is not a second action target.stateDescriptionprovides state-change feedback without moving focus or posting unconditional announcements.ConfirmDialog: the localized explanation, no title, and one OK button. ItsrememberSaveablevisibility survives activity recreation.Example semantic content is Firefox as the label and Checked. routed through the app as the state description, with the native Checkbox role. This is not a promise of a fixed spoken order: TalkBack controls role wording, ordering, and interaction hints. State text is app-localized; role text belongs to the accessibility service.
Accurate routing context
Routing context cannot be inferred from the checkbox alone: service mode, empty selections, shared UIDs, and own-package exclusions affect configured inclusion.
PerAppRoutingdescribes configured app inclusion, not a live connection, successful forwarding, or the outcome of individual destination/DNS rules. It uses the complete installed-app snapshot, saved package selection, UID, and service mode:Checkbox membership stays package-based. Routing context is UID-based, so an unchecked package can share the routing outcome of a checked sibling. The helper preserves the different self-package handling of VPN and root mode. Missing UID metadata omits the routing sentence instead of guessing.
The existing background package enumeration now retains
ApplicationInfo.uidinAppInfo; no second package query is introduced. Filtering the displayed list does not change the routing decision. The ViewModel owns the observable full snapshot and refreshes service mode on resume, using the same root-before-VPN priority as service selection.No VPN/root policy, selection persistence, import/export behavior, or traffic handling is changed.
Row structure and layout
Textmerge naturally into the toggleable row instead of hiding it and reconstructing it as a content description.toggleablealready merges its content.Localization and independence
The PR has eight accessibility resource keys in each of the nine maintained catalogs: English, Arabic, Bengali, Bakhtiari, Persian, Russian, Vietnamese, Simplified Chinese, and Traditional Chinese. Key uniqueness and routing-state placeholders were checked. Routing and state descriptions use the app locale. Russian retains “маршрутизируется через приложение”.
The shared app picker gains the same one-checkbox row, app-name label, and package-ID suppression, without Per-app Proxy routing text. The OK-only modal and named callback remain aligned with #6157. This branch does not include its notification/live-region layer or the other screen-specific accessibility changes.
At commit
bfbac0b16, pairwisegit merge-treechecks on September 5 against fetchedupstream/masterand all nine companion accessibility branches passed in both orders with identical result trees. This is a conflict check, not a complete combined-build test.Validation at
bfbac0b16PerAppAccessibilityTest: 13 tests covering disabled/proxy-only mode, allow/bypass lists, VPN/root empty selections, self and shared UIDs, installed/removed selections, and missing UID metadata.:app:testPlaystoreDebugUnitTest: 70 tests, no failures/errors/skips.:app:compilePlaystoreDebugKotlinand:app:assemblePlaystoreDebug -PABI_FILTERS=x86_64: passed.CONTENT_CHANGE_TYPE_STATE_DESCRIPTIONevents. Native accessibility clicks retain focus and update state. Touch on row/control, Enter, Space, and D-pad center each toggle the same controls.git diff --check: passed.Android guidance