fix: Android status/nav-bar systemui chrome leaks into non-raw captures (#1251)#1256
fix: Android status/nav-bar systemui chrome leaks into non-raw captures (#1251)#1256thymikee wants to merge 2 commits into
Conversation
) The non-raw Android walk (walkUiHierarchyNode/shouldIncludeStructuralAndroidNode in ui-hierarchy.ts) drops unlabeled/unidentified structural nodes, re-parenting their children upward. That silently swallows the status_bar*/navigation_bar* WRAPPER nodes carrying the marker ids collectAndroidSystemChromeRunIndexes keys on, leaving only their labeled/identified LEAVES (clock, battery, wifi/mobile icons, nav buttons) in a non-raw capture. Those leaves' own ids have no status_bar/navigation_bar prefix, so the systemui run loses its marker and is no longer dropped -- leaking status-bar chrome into --settle and replay divergence screen.refs. --raw keeps the wrapper markers, so it was unaffected. Recognize the surviving leaves directly by EXACT resource-id (not prefix, to stay tight -- actionable systemui overlays like the volume dialog or a media picker must keep surviving). Test derives a faithful non-raw tree from a real --raw Android capture (checkout-form fixture app, Gboard + status bar) by simulating the walk's drop+reparent for the specific marker-bearing wrappers, then asserts: every surviving status-bar leaf is classified as chrome, the whole systemui run drops, app fields and the IME keyboard are handled unchanged, and a synthetic volume-dialog run still survives. A second synthetic case covers the nav-bar leaves (no real nav-bar capture was available on the gesture-nav test device).
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
Code review on |
…led structural nodes The get/is/wait divergence uses a full (non-interactive) capture so static-text targets survive, but that also pulls in unlabeled structural containers (ViewGroups/ComposeViews) that carry a ref yet no identity and aren't tappable. On deeply-nested RN trees they consume the SCREEN_REF_CAPTURE_LIMIT budget ahead of the actionable controls (and the app content the excluded status/nav chrome just freed room for). Filter divergence screen.refs to nodes an agent could actually re-target: identifiable (display label/value/non-generic id) or interactive (hittable).
|
Additional blocking test-validity finding on The Android “non-raw” fixture does not reproduce the production walker closely enough for the nav-bar assertion. Please run the fixture through the real Android inclusion/walk behavior (or reproduce all of its relevant decisions exactly) and test the Android target-binding divergence route rather than an iOS session with mocked dispatch. The previously requested practical emulator evidence for the actual non-raw capture-to-bounded- Readiness remains withheld. No fixer was dispatched. |
Root cause
walkUiHierarchyNode(src/platforms/android/ui-hierarchy.ts) includes every node whenoptions.raw, but in the non-raw path runsshouldIncludeAndroidNode→shouldIncludeStructuralAndroidNode, which drops unlabeled/unidentified structural nodes and re-parents their children upward.That silently swallows the
com.android.systemui:id/status_bar*/navigation_bar*wrapper nodes — the only nodeshasAndroidSystemChromeMarker(insrc/core/snapshot-chrome.ts) matches. A non-raw capture is left with only their labeled/identified leaves (clock,battery,wifi_signal/wifi_combo,mobile_signal/mobile_combo, etc.), whose own resource-ids carry nostatus_bar/navigation_barprefix. The systemui run loses its marker,collectAndroidSystemChromeRunIndexesstops dropping it, and status-bar chrome leaks into--settleand the replay-divergencescreen.refscap.--rawkeeps the wrapper markers, so it was unaffected.Fix
ANDROID_SYSTEM_CHROME_MARKER_LEAF_IDSinsrc/core/snapshot-chrome.ts: a set of stable AOSP status-bar/nav-bar leaf resource-ids (clock,battery,statusIcons,notificationIcons,notification_icon_area,system_icons,cutout_space_view,mobile_signal/mobile_combo/mobile_group,wifi_signal/wifi_combo/wifi_group,start_side_notif_and_chip_container; nav:back,home,recent_apps,home_handle), matched by exact id (not prefix) so actionable systemui overlays (volume dialog, media/output pickers) keep surviving. The existing prefix check stays for--raw, which still carries the wrapper markers.Deferred alternative noted in a code comment: thread the AOSP window-type constants (
TYPE_STATUS_BAR/TYPE_NAVIGATION_BAR, already parsed inreadNodeAttributesbut not copied to the output node) through to the snapshot node and key off that instead of resource-ids — left for later unless the id-based approach proves insufficient.Test
src/core/__tests__/snapshot-chrome-android-statusbar.test.tsderives its fixture from a real--rawAndroid capture (checkout-form fixture app, Gboard open, status bar visible). AsimulateNonRawWalkhelper reproduces the walk's drop+reparent for the specificstatus_bar*/navigation_bar*marker wrappers (verified node-for-node against the source capture), producing a realistic "leaves only" tree. Assertions:field-name/field-email/field-phone) and the IME keyboard, from the same real capture, are handled unchangedback/home/recent_apps/home_handleVerification
npx tsc --noEmit— cleannpx oxlint --deny-warnings/npx oxfmt --checkon touched files — cleannpx vitest run— 4130 tests, all pass on a clean re-run afterpnpm installin the fresh worktree (an initial run without deps installed hit an unrelated build-tooling failure; a couple of runs also hit known-flaky iOS runner-client/runtime-hints tests under parallel contention, all confirmed passing in isolation — seeunit-suite-flaky-under-contention.md)pnpm check:fallow --base origin/main— no issues in the 2 changed filesFixes #1251.