Repository navigation
Conversation
WindowEventInterpreterTest feeds the window interpreter the window events of common screen changes, with the windows Android would list at each moment, and records everything a listener can read from each interpretation, and when it came. The screen changes are a new screen named by its state change, one without such a name, the shorter wait when animations are off, a window that closes before the system reports it, split screen, the keyboard, picture-in-picture, a window without a title, a pane, the screen turning off and on, and the volume panel. The tests pin down what the interpreter reports today, so that changes to how it looks up windows can show that the rest of Backtalk is told the same. The main looper is paused, so each 10 ms check runs at a known time, and the service counts how often it is asked for the window list. A screen change that waits the full 550 ms asks for it 913 times.
zywek123
force-pushed
the
window-changes
branch
from
October 12, 2026 09:09
f0a8a71 to
489a755
Compare
At a window event, and at each 10 ms check while it waits for the windows to settle, the window interpreter looks up the title of the window in each of its six roles, and the app of each window without a title. A role without a window, such as the second app when the screen isn't split, has the id -1, which no window has. Looking up its title missed the kept windows, so the interpreter fetched them again, and looking up its app fetched them once more. On a screen with one app, and no split screen, dialog, picture-in-picture window or keyboard, each check asked Android for the windows 13 times. These lookups now return at once, with the same result, so such a check asks once, to map the windows to roles. The failed lookups also refreshed the kept windows at each check. The titles now come from the windows kept since the last window event, which Android sends for every change to the windows, and a window missing from them still makes the interpreter fetch them again. A later commit gives each check a list of its own. In the tests, a screen change that waits the full 550 ms asks for the window list 229 times instead of 913, and one that waits 200 ms with animations off asks 23 times instead of 275. What the interpreter reports is unchanged.
At a window event, the window interpreter asked Android for the windows up to three times: to note their titles, to map them to roles, and for the titles of the windows in those roles. Each check while it waited for the windows to settle asked again to map them to roles. The window an event names is often gone, as when the event reports that it closed. It was missing from the kept windows at each lookup, so each check fetched them twice more for its title, and once more for its app, since looking up a window's app always fetched the windows anew. Now each window event and each check fetches the windows once, and all its lookups use that list: titles, roles and apps. A window missing from it isn't looked for in a list fetched a moment later. Each check still fetches its own list, so windows that change before their windows event are noticed as before, and the titles now come from the same list as the roles. Lookups from the rest of Backtalk use the list of the last event or check, and fetch the windows again for a window missing from it, as title lookups did. Looking up a window's app now works that way too. The focus history names the window at every focus change, and in a window without a title that looked up its app, fetching the windows each time. In the tests, each event and each check asks for the window list once. A screen change that waits the full 550 ms asks 57 times, against 229 after the previous commit and 913 before it, and one that waits 200 ms asks 21 times. What the interpreter reports is unchanged.
A window without a title is named after its app, which the window interpreter found by fetching the window's root and reading its package. Fetching a root waits for the app's main thread, which is busy drawing while the screen changes, and the interpreter fetched it at every check while it waited for the windows to settle, and again whenever the rest of Backtalk asked for the window's title. The focus history asks at every focus change. The package of each window's root is now kept by window id, since a window keeps its id until it closes and no other window gets it. It is used only while the window is listed, so a window that has closed is untitled as before, and the packages of windows that are gone are dropped at each windows event. A root that can't be fetched, as before its app has drawn it, isn't kept, so it is asked for again at the next lookup. In the tests, a window without a title has its root fetched once while the screen changes to it and back, instead of 59 times. A window whose root can't be fetched at first is named after its app at the first check after it can be, with one fetch instead of one at every check. What the interpreter reports is unchanged.
…e manager Direct touch looks at the screen 150 ms after every window change and every window interpretation, even when it isn't turned on for any app. Each look fetched the root of the app window in front, of every other application window and of every system window, which waits for each window's app, and read the app's manifest with up to three package manager queries, before it checked a single switch. The main thread stalls on a watch in trypsynth#152 included this look, run then by screen changes, which 299eab3 dealt with. Window changes still ran it in full. Now each look asks only for what it needs: - The package of a window's root comes from the window interpreter, which keeps it by window id, so the app in front is asked once per window. - The manifest is read only the first time an app is seen, the only time it is used. - The checks that need other windows' roots run only when the switches, the window types and the focus leave the answer open. Another app's window can only be found when an application window other than the game is open, and that already turns direct touch off as a dialog, so those roots aren't fetched at all now. A system window is asked whether it belongs to System UI only when it is active and covers half the screen, as the notification shade does. What direct touch decides, says and sends as the passthrough region is unchanged. A new test feeds window changes through the window interpreter to direct touch, as the service does. Three window changes over a game that isn't turned on fetched 23 window roots and read the manifest 7 times, and now fetch one root and read the manifest once. With the game turned on, and the notification shade opening and closing over it, 30 roots and 9 manifest reads became 2 and 1. DirectTouchPolicyTest goes through all 128 combinations of inputs: the answer is the same as before, and the checks that need roots run only when they can change it.
When the screen changes, Backtalk first tries to restore the focus the user last had in the window that is now active. restoreLastFocusedNode fetched that window's root before it looked in the focus history, so a new screen, which has no focus to restore, had its root fetched for nothing, and a later step that focuses the first item fetches it again. The fetch waits for the window's app, which is busy drawing the new screen, and on a watch in trypsynth#152 it was among the main thread stalls after the screen turned on. The root is now fetched only once the history has a focus for the window, and after the check that keeps a focus from an app out of a System UI window. Restoring a focus also fetched the root a second time, to check that the node is still in the window. That check now uses the root fetched already. What gets focused is unchanged. In a new test, a screen without a focus to restore fetches no root instead of one, and so does a System UI window whose last focus came from an app, while a focus that is restored fetches the root once instead of twice.
…ents FocusActorForScreenStateChangeTest checked that a focus from an app isn't restored into a System UI window by seeing the restore fail without fetching the root. The node it recorded wasn't in the shade's tree, though, so without that rule the restore would have failed anyway, only later. Both windows now share one root that holds the node, and the test checks that the history has a focus for the shade's window id, so only the rule stops the restore. With the rule taken out, the test fails. An unused import is gone. The comment on fetching the root in restoreLastFocusedNode used "only once" in two senses, and the comment on direct touch's window interpreter read oddly. Both now say plainly what they mean.
zywek123
marked this pull request as ready for review
October 12, 2026 14:10
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.
When the screen changes, the window interpreter asked Android for the list of windows 13 to 16 times for each window event, and again at each 10 ms check while it waited for the windows to settle, for up to 550 ms, or 200 ms with animations off. Most of those lookups were for roles that have no window, such as the second app of a split screen, so they never succeeded. In the new test, a screen change that waits the full 550 ms asked for the window list 913 times, and 275 times with the shorter wait. A window without a title also had its root fetched from its app at every check, to be named after the app, and that waits for the app's main thread, which is busy drawing the new screen.
The first commit adds tests that record everything the interpreter reports for common screen changes. The others change how windows are looked up, each leaving those tests as they are:
Measured on a Galaxy S10 (LineageOS 22.1, Android 15) and an API 36 emulator, going round six Settings pages (Internet, Accessibility, Sound, Display, Apps, Date and time), each opened from Settings and closed with back, in an order that changes every round: 24 openings and 24 backs on each build. Counters in both builds count the window lists Backtalk asks for and time its main thread work, and on the emulator Android's accessibility trace records Backtalk's calls into the system. Medians:
The time to the first speech is the same, since it depends on when the windows settle, which this PR doesn't change. Android's cache serves most window lists, so each costs little and the interpreter takes about as long as before. The main thread time saved is direct touch's and the focus restore's, about 30 ms per screen change.
Not tried on a watch yet. The watch from #152 can try it in the development build once this is merged.