Skip to content

fix(android): carry the heading flag and the role description on the snapshot node - #2915

Merged
thymikee merged 1 commit into
callstack:mainfrom
okwasniewski:oskar/android-heading
Sep 24, 2026
Merged

thymikee merged 1 commit into
callstack:mainfrom
okwasniewski:oskar/android-heading

Conversation

@okwasniewski

@okwasniewski okwasniewski commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

React Native puts a header, a tab, a tab list, a radio group, a link, or a menu on a plain android.view.View and marks what it is through two facts: the heading flag and the role description androidx stores in the node extras. The helper serialized neither, and the host reads only its XML, so each was a nameless View to an agent and to get attrs.

The helper now writes heading when the node reports it (API 28 or later) and role-description when the app set one. The parser, the Android hierarchy node, and the published snapshot node carry them to get attrs, the unchanged-snapshot comparison, and the selector digest as heading and roleDescription. The class stays the type and snapshot text is unchanged; mapping a localized description to a role is the consumer's call.

{ "identifier": "inventory-header", "heading": true }
{ "identifier": "section-tabs", "roleDescription": "Tab List" }
{ "identifier": "tab-fields", "label": "Fields", "roleDescription": "Tab" }

10 files. No HELPER_API_VERSION bump, as with selected (#2515).

Validation

Tested at 926d4f9 (rebased onto 86d719d). pnpm check:affected --run --base 86d719dc3 passed: format, lint, typecheck, layering, fallow, build, 853 test files, 6,671 tests.

Rebuilt helper on an API 36 emulator, React Native app: accessibilityRole="header" reports heading: true; tablist, tab, and radiogroup views report Tab List, Tab, and Radio Group; text views report neither key.

Risk: a heading on API 23 to 27 still reports nothing, since the compat flag lives in an extras bit the helper does not read.

Copilot AI lite review requested due to automatic review settings September 24, 2026 14:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation is covered end-to-end, with only minor test-coverage nits remaining.

Review effort: Lite
Findings: None

What changed in this PR

Adds Android accessibility heading and role-description metadata to snapshots, get attrs, and unchanged-snapshot comparisons.

Changes:

  • Serializes and parses heading and role-description.
  • Propagates fields through Android and kernel snapshot nodes.
  • Updates digests, documentation, changelog, and tests.
File Description
website/​docs/​docs/​snapshots.md Documents new snapshot metadata.
src/​daemon/​response-views.ts Includes fields in selector digests.
src/​commands/​capture/​runtime/​snapshot-unchanged.ts Compares fields for snapshot changes.
src/​__tests__/​android-ui-hierarchy.test.ts Tests published Android snapshots.
packages/​platform-android/​src/​ui-hierarchy.ts Parses and normalizes metadata.
packages/​platform-android/​src/​ui-hierarchy-node.ts Adds hierarchy metadata fields.
packages/​platform-android/​src/​ui-hierarchy-builder.ts Publishes fields in snapshots.
packages/​platform-android/​src/​__tests__/​ui-hierarchy-role-facts.test.ts Tests metadata propagation.
packages/​kernel/​src/​snapshot.ts Extends snapshot node types.
CHANGELOG.md Records the fix.
android/​snapshot-helper/​src/​main/​java/​com/​callstack/​agentdevice/​snapshothelper/​AccessibilityTreeXml.java Serializes Android accessibility metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@thymikee

Copy link
Copy Markdown
Member

Reviewed at 4d6fb65. The change looks correct: heading and roleDescription flow from the helper through the parser and the kernel type into get attrs, the unchanged-snapshot comparison, and the selector digest. It is ready for human review.

#2913 edits the same comment block in AccessibilityTreeXml.java, a few lines above this hunk. Whichever PR lands second needs a small rebase.

The on-device run comes from the PR description; I did not repeat it. I could not confirm from repo sources that AccessibilityNodeInfo.roleDescription is the exact androidx extras key, but the reported device output (Tab List, Tab, Radio Group) is consistent with it. The Smoke Tests jobs were still queued or running at review time, so there is no failure to attribute.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 24, 2026
@okwasniewski

Copy link
Copy Markdown
Contributor Author

The extras key is androidx's AccessibilityNodeInfoCompat.ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription"; setRoleDescription writes it with mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, ...): https://github.com/androidx/androidx/blob/androidx-main/core/core/src/main/java/androidx/core/view/accessibility/AccessibilityNodeInfoCompat.java (search ROLE_DESCRIPTION_KEY). The platform AccessibilityNodeInfo has no getter, which is why the helper reads the extras. I will name the constant in the Java comment when this branch rebases over #2913.

…snapshot node

React Native puts a header, a tab, a tab list, a radio group, a link, or a menu on a plain android.view.View and tells the accessibility tree what it is through two facts: the heading flag and the role description androidx stores in the node extras. The helper serialized neither, and the host reads only the helper's XML, so every one of them was a nameless View to an agent and to `get attrs`. The helper now writes `heading` when the node reports it (API 28 or later) and `role-description` when the app set one; the parser, the Android hierarchy node, and the published snapshot node carry them to `get attrs`, the unchanged-snapshot comparison, and the selector digest. The class stays the type, and snapshot text is unchanged: mapping a description to a role is the consumer's call.
Copilot AI review requested due to automatic review settings September 24, 2026 15:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Two moderate regression-test gaps remain unresolved.

Review effort: Lite
Findings: None

@thymikee
thymikee merged commit efce352 into callstack:main Sep 24, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants