Reduce linear-navigation latency around list scrolling - #42
Open
devinprater wants to merge 5 commits into
Open
devinprater wants to merge 5 commits into
devinprater wants to merge 5 commits into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
…ogress Linear navigation waits out the full SCROLL_TIMEOUT (500/1000ms) whenever an app never performs the requested scroll action and never reports progress (e.g. Reddit's feed). Arm a watchdog alongside the full timeout; the first scroll-progress event disarms it via cancelTimeout(). On fire, route through the normal timeout path so assume-success retry, focus and speech proceed immediately.
The fixed 150ms watchdog false-positived on rapid swipes: overlapping scrolls mean the newest record can see no matching events while the list is still moving from a previous swipe, and focus then lands on a moving tree (observed: focus escaping to search/edge panels). The interpreter now reports every scroll event to the actor; the watchdog stands down to stock timeout behavior whenever any scroll activity postdates the action. Dead scrolls (total silence, e.g. Reddit's feed) still fail fast.
When a swipe triggers a scroll, focus the already-computed target immediately (~90ms) instead of waiting out settle + re-search (~160ms). Scroll bookkeeping untouched; post-scroll pass skips re-focus when focus is already on the target (no double speech), corrects otherwise.
Fast swiping discarded the in-flight item silently: the next swipe reset the scroll records before the delayed success handler fired, so the swiped-to item never spoke and the user perceived a stall. Each new directional navigation now completes any pending scroll-success first; it speaks immediately and is interrupted by the new item as usual.
devinprater
force-pushed
the
scroll-latency-fixes
branch
from
September 20, 2026 00:18
2fd0917 to
0034e24
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Swiping through scrollable lists (e.g. a social-media feed, but also Settings) can take ~250-560ms per item before speech starts. Measured on a Galaxy S25 (Android 16, TalkBack 17.0.1) using TalkBack's own debug logging with millisecond timestamps. Three distinct stalls, all in the swipe -> focus -> speak path:
SCROLL_TIMEOUT_SHORT(500ms): gesture at 16:40:44.366,onAutoScrollFailedat 16:40:44.870, speech at 16:40:44.924. The timeout exists for slow lists, but a scroll with zero sign of life is never going to complete.TIMEOUT_MS_HANDLE_SCROLL_BY_GESTURE), ~48ms post-scroll focus re-search, ~23ms speech queue. Speech waits for all of it although the target is already known.Changes (4 commits)
AutoScrollActor): arm a 150ms watchdog alongside the full scroll timeout. Fires only under complete scroll silence (see next commit); routes through the normal timeout path, so assume-success retry, focus and speech proceed immediately.AutoScrollActor,AutoScrollInterpreter,TalkBackServicewiring): the interpreter reports every scroll event to the actor. Any scroll activity since the action - even unmatched (e.g. the user's own finger on a settling list) - stands the watchdog down to stock timeout behavior. A fixed 150ms watchdog false-positived on rapid swipes during testing (focus escaped the list); the silence gate fixed it.FocusProcessorForLogicalNavigation, behindSPEAK_AHEAD_OF_SCROLL): when a swipe triggers a scroll for an already-computed target, focus and speak it immediately instead of waiting out settle + re-search. Scroll bookkeeping is untouched (no record reset, no forced refocus); the post-scroll pass skips re-focus when focus is already on the target (no double speech) and corrects otherwise.AutoScrollInterpreter,DirectionNavigationActor): each new directional navigation first completes any pending delayed scroll-success, so every swipe is heard (briefly, then interrupted as usual) instead of silently dropped.Testing
assembleDebug, AGP 8.11 / Gradle 8.13 / JDK 17) and side-loaded alongside stock TalkBack.Happy to split these into separate PRs per fix if preferred, and to sign the Google CLA - just point me at it.