Skip to content

fix: filter covered Android snapshot surfaces#675

Merged
thymikee merged 2 commits into
mainfrom
codex/android-visible-filter
Jun 2, 2026
Merged

fix: filter covered Android snapshot surfaces#675
thymikee merged 2 commits into
mainfrom
codex/android-visible-filter

Conversation

@thymikee
Copy link
Copy Markdown
Member

@thymikee thymikee commented Jun 2, 2026

Summary

Filter covered same-window Android snapshot surfaces so agent-facing refs match the foreground UI.

Android UiAutomation helper snapshots can include navigation/view surfaces that are still attached in the same accessibility window even though they are covered by the current screen. Some nodes inside those covered surfaces can still report visible-to-user=true, so filtering only on that flag is not enough.

This adds the helper drawing-order attribute and uses it in the host parser to suppress lower drawing-order sibling subtrees when a higher sibling geometrically covers them and contains agent-visible content. The filter is intentionally generic Android helper behavior, not a React Navigation-specific workaround. React Navigation exposed the issue through drawer + stack surfaces, but the invariant is the same for any same-window covered sibling tree.

The helper now emits drawing-order only on Android API 24+, where AccessibilityNodeInfo.getDrawingOrder() exists. On API 23 the attribute is omitted and the host keeps the existing conservative behavior instead of risking a helper crash.

The traversal was kept allocation-conscious: hidden subtree pruning compacts children in place, covered-sibling pruning runs bottom-up, and subtree agent-visible-content checks are memoized with a WeakMap so large RN trees are not repeatedly rescanned. Equal drawing-order siblings and sub-90% overlaps are intentionally kept; tests document those conservative limits because there is no reliable full-coverage z-order signal in those cases.

Also documents the helper XML attribute contract and accepts negative Android bounds from clipped/offscreen nodes.

Validation

  • tsc -p tsconfig.json
  • vitest run src/platforms/android/__tests__/index.test.ts src/compat/maestro/__tests__/runtime-targets.test.ts src/utils/__tests__/selector-is-predicates.test.ts
  • scripts/package-android-snapshot-helper.sh ... android-snapshot-helper/dist
  • Rslib build
  • Live Pixel 9 Pro XL helper-backed snapshot on React Navigation Stack Preload Flow: android-helper, 6 foreground refs, drawer leak labels []
  • git diff --check

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

Size Report

Metric Base Current Diff
JS raw 1.1 MB 1.1 MB +1.3 kB
JS gzip 363.1 kB 363.5 kB +406 B
npm tarball 468.0 kB 468.6 kB +565 B
npm unpacked 1.6 MB 1.6 MB +1.7 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.5 ms 26.1 ms -0.4 ms
CLI --help 41.1 ms 41.2 ms +0.0 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/221.js +1.3 kB +406 B

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 710a4ca013

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

appendNonEmptyAttribute(xml, "package", node.getPackageName());
appendNonEmptyAttribute(xml, "content-desc", node.getContentDescription());
appendAttribute(xml, "visible-to-user", Boolean.toString(node.isVisibleToUser()));
appendAttribute(xml, "drawing-order", Integer.toString(node.getDrawingOrder()));
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard getDrawingOrder on API 23

On Android 6/API 23 devices this helper can still be installed because the manifest/build scripts set minSdkVersion/MIN_SDK to 23, but AccessibilityNodeInfo.getDrawingOrder() is only available starting API 24 per the Android reference. In that supported environment, serializing the first node will throw NoSuchMethodError and the snapshot instrumentation fails instead of returning XML; gate this call on Build.VERSION.SDK_INT >= 24 or omit the attribute on API 23.

Useful? React with 👍 / 👎.

@thymikee thymikee merged commit 6f637d0 into main Jun 2, 2026
18 checks passed
@thymikee thymikee deleted the codex/android-visible-filter branch June 2, 2026 19:01
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-06-02 19:01 UTC

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.

1 participant