Repository navigation
Let apps mark the views that take direct touch - #185
masonasons wants to merge 3 commits into
Conversation
Direct touch was all or nothing: the whole screen of a chosen app passed through. Some apps want raw touch in one area only, such as a player with a gesture pad, while lists and buttons stay with explore by touch. An app now declares dev.nvgt.capability.DIRECT_TOUCH_REGIONS in its manifest and marks views by putting the boolean dev.nvgt.DIRECT_TOUCH_REGION in their AccessibilityNodeInfo extras. For such an app, the passthrough region is the screen bounds of its visible marked views, clipped to their windows, minus every window on top of them and the system windows, overlays and keyboard that whole-screen mode already leaves out. Direct touch is on, with the usual announcement and vibration, only while that region isn't empty. The app's own dialogs and popups are cut out of the region instead of turning direct touch off; another app, the shade, a focused text field or the screen turning off still turn it off. The region follows content changes and scrolls in the app's windows. Those are looked at most once every 150 ms, and straight away for the first change while direct touch is on, so that a marked view going away hands touch back at once. Only region apps' trees are searched, and at most 500 views, 40 levels deep. The manifest is read once while an app stays in front rather than on every look. Apps with the plain DIRECT_TOUCH capability, or turned on by the user, keep the whole-screen behavior.
|
Thanks, this is a nice extension, and the trust model is fine: region apps are turned on at first sight just like
|
Master's direct touch controller and policy changed in trypsynth#164, so the change is made again on top of them, with what the review asked for: - Marked views are found by asking each of the app's windows for the views with the ID dev_nvgt_direct_touch_region, which the app answers by searching its own views, instead of Backtalk walking up to 500 of them. A look is one call per window, and the window's root is fetched once while it stays. Only an app that declares regions and is turned on is asked, at most once every 150 ms for its content changes. The ID replaces the dev.nvgt.DIRECT_TOUCH_REGION extra. - Direct touch on and off are announced when the app may have it and when it no longer may, not as the region goes empty and back. - The controller tests cover the throttle, the announcements, the dialog cut-out, apps that are never asked, and what each look costs. - The manifest is read at an app's first sight, as master does, and otherwise only for an app in front that is turned on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iUrBiG422jeRdCb9hkkS9
|
Thanks for the review. I've pushed changes for each point:
The PR description is updated to match. |
|
Thanks, this addresses everything I asked: one lookup per window instead of the tree walk, announcements only when direct touch really starts or ends, tests for the throttle and the controller, and it's merged with master after #164. I've approved CI. Before merging, could you try it on a phone yourself, with an app that marks views, and say what you tried and what happened? I'll test it too, but I'd like to know the code I'm running has been tried by a person, not only by the tests. A watch would be a bonus if you can get hold of one, but a phone is what I'm asking for and a watch is not at all a merge requirement |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019iUrBiG422jeRdCb9hkkS9
|
Tried it on a phone: a Galaxy S23+ on Android 16, running a debug build of this branch (b59baff, with today's master merged in) as the screen reader, and FastPlay's Android app, which declares It worked as intended:
I haven't tried a watch. |
Direct touch today is all or nothing for an app: when it's on, the whole screen goes to the app. That suits a game, but not an app where only part of a screen wants raw touch. FastPlay, an audio player, has a touch pad in its player (swipes seek, two-finger swipes adjust effects, a two-finger tap plays and pauses), while the rest of the app (its lists, buttons and settings) needs explore by touch. On iOS, VoiceOver handles this per view with "allows direct interaction"; Android has nothing an app can use, since only an accessibility service can set the passthrough region.
This lets an app mark the views that take touches directly, and Backtalk passes through only those.
What an app does
Declare the capability on
<application>or the launch<activity>:declare the marking ID in its resources:
and give it to each view that should take raw touch:
Several views can share it. Backtalk turns a region app on the first time it sees it, as it does for
DIRECT_TOUCHapps, and the user can still turn it off in the Apps list. The constants are inDirectTouchSettingsnext toCAPABILITY_KEY.How it behaves
findAccessibilityNodeInfosByViewId("<package>:id/dev_nvgt_direct_touch_region")on each of the app's application windows. The app searches its own views to answer, so a look is one call per window however big the app's tree is, and there's no walk and no node limit. Each window's root is fetched once while the window stays.DirectTouchPolicythis is one new input,regionMode.DIRECT_TOUCH, or turned on by the user, keep whole-screen behaviour exactly as before. An app that declares both gets region mode.differences.mdhas a new section, "Direct touch on part of the screen", for users and app developers.Testing
gradlew :talkback:testPhoneDebugUnitTest --tests 'com.google.android.accessibility.talkback.directtouch.*': 53 tests pass.DirectTouchControllerTesthas eight new tests on top of the ones from Look up windows less often when the screen changes #164, which pass unchanged: the region for a marked view, the region coming and going without announcements, the throttle under a stream of content changes (8 looks for 100 changes over a second), the first change being looked at at once, other apps and a region app that's turned off never being asked, the app's dialog being cut out, and the screen turning off. They count the asks for marked views, root fetches and manifest reads.assemblePhoneDebugand:lintPhoneDebugpass.android/) declares the capability and marks its touch pad with the ID, so it can serve as a test app.🤖 Generated with Claude Code
https://claude.ai/code/session_019iUrBiG422jeRdCb9hkkS9