Skip to content

Restore previous accessibility focus when going Back - #151

Open
willbilec wants to merge 2 commits into
trypsynth:masterfrom
willbilec:codex/restore-focus-on-back
Open

willbilec wants to merge 2 commits into
trypsynth:masterfrom
willbilec:codex/restore-focus-on-back

Conversation

@willbilec

@willbilec willbilec commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Returning with Back can lose accessibility focus when an app rebuilds its list or a browser reconstructs a page. Backtalk now remembers the last focused item on up to 20 screens during the current service session and restores a strong identity/content match when returning, including after opening another app.

Restoration is Back-only and phone-only. User input cancels it; weak or missing matches fall back to existing initial focus. Visible-item restoration is always active. The Advanced Settings option Scroll to restore previous focus is disabled by default and permits at most ten supported scroll actions within a three-second restoration deadline. Ordinary TalkBack window restoration remains unchanged on Wear and TV.

Addresses the maintainer review: ordinary focus tracking caches a lightweight identity, detailed bookmarks are captured at activation or Back, idle content changes and hover cancellation perform no window-root reads, and each restore attempt reads context once. Ancestor/sibling work is bounded. Departing focus uses its own window for split-screen support; Back controls use resource IDs and localized Navigate-up descriptions. The setting is hidden on Wear/TV, Czech translations are included, and documentation is under Navigation. Rebased onto master to preserve the direct-touch fix and restored build/test workflow.

Validation:

  • testPhoneDebugUnitTest: 667 tests passed.
  • :talkback:testWearDebugUnitTest: 479 tests passed.
  • 120 focus tests cover matching, reconstruction, cancellation, scrolling, and counted window access with real accessibility trees.
  • :lintPhoneDebug, assemblePhoneDebug, assembleWearDebug, and git diff --check passed.
  • The user previously confirmed RedReader, Edge, Chrome, and Firefox behavior and confirmed the installed revised isolated debug APK still works. Individual app cases were not separately reported for this latest revision.

Debug configuration, APKs, local guidance, and unrelated session work are excluded. The separate suppressed-speech PR is untouched.

@trypsynth trypsynth left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a nice idea, and matching the item by its content when an app rebuilds the screen does something TalkBack's own restore can't. Before it can merge, the cost needs to come down a lot, because it runs all the time rather than only around a Back.

Must fix: main-thread work (ScreenFocusRestorer.kt)

  • Every TYPE_WINDOW_CONTENT_CHANGED calls schedule() (around :266), and each run calls observeScreen(context()) before checking whether a restore is pending (:379-380). context() reads rootInActiveWindow and walks up to 100 nodes. During any animation, progress bar or chat that's several walks a second, in every app, with no Back pending.
  • onUserInteraction() calls context() whenever a retry is queued, and it runs on every hover enter, so touch exploration pays for it.
  • Each swipe walks the tree two or three times, and describe() loops through up to 100 siblings per level. rememberBeforeActivation does this before every click, which delays activation.
  • None of this is turned off on watches, where these calls are slowest (see #152).

Suggestions: do nothing on content changes unless a Back is pending; keep the focused node and only describe it when Back or an activation actually happens; skip context() in onUserInteraction and on hover; and turn the feature off on watches.

Should fix

  • isBackControl matches the English labels "Back" and "Navigate up" (around :171), so app Back buttons aren't recognised in other languages. Matching by resource ID, or by the framework's localized "Navigate up" string, would work everywhere.
  • In split screen, focus outside rootInActiveWindow cancels the attempt and is never saved.
  • The tests replace readContext with a stub, so the tree walking and the app calls, which are the costly and risky part, aren't covered.
  • The differences.md section sits above the intro paragraph; it belongs under Navigation. The summary string's "Off by default." and "allow Backtalk to" don't follow Google style, and the Czech strings are missing from values-cs/strings_backtalk.xml.
  • CI on this PR ran while master's workflow was broken (lint only), so it was never built or unit tested there. A rebase onto current master will run the full workflow.

@willbilec
willbilec force-pushed the codex/restore-focus-on-back branch from 7eeb5e6 to 644aa99 Compare October 11, 2026 21:42
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