Skip to content

Add Compose hierarchy inspector (preview)#60

Open
actorFromCalifornia wants to merge 1 commit into
Grigory-Rylov:masterfrom
actorFromCalifornia:6b87e646/2026-05-29
Open

Add Compose hierarchy inspector (preview)#60
actorFromCalifornia wants to merge 1 commit into
Grigory-Rylov:masterfrom
actorFromCalifornia:6b87e646/2026-05-29

Conversation

@actorFromCalifornia

Copy link
Copy Markdown

Summary

Adds a new menu action Tools → YALI → Inspect Compose Hierarchy that captures the on-screen UI via uiautomator dump and surfaces a Compose-focused summary in a Swing dialog. The change is purely additive — the existing Launch YALI flow is untouched.

The dialog reports:

  • total / visible node counts
  • Compose roots (AndroidComposeView / ComposeView)
  • Compose candidate nodes (heuristic: anything under an AndroidComposeView, plus android.view.View leaves with empty resource-id but non-empty text / content-desc — the typical shape of Compose semantics nodes exposed through accessibility)
  • nodes with text, with content-desc, with resource-id
  • top classes / top texts / top content descriptions

Plus a tree view of the Compose candidate subtree and a "Copy summary to clipboard" action.

Why UI Automator for now

The complete Compose tree (with @Composable names, source location, parameters, recomposition counts) requires Android Studio's App Inspection framework: a transport daemon pushed to the device, which deploys compose-ui-inspection.jar into the target process via JVMTI, and a protobuf RPC channel between the IDE and the agent. That path touches com.android.tools.idea.appinspection.* internals which are unstable across Studio releases. UI Automator gives a stable subset (semantics-merged tree) immediately and lets us ship the UI without committing to the full agent integration yet.

The full plan, including the layered roadmap, is in docs/COMPOSE_INSPECTOR_SPEC.md. The protobuf used by the App Inspection agent (taken from the existing compose branch / AOSP androidx.compose.ui:ui-inspection) is checked in at proto/compose_layout_inspection.proto for the next iteration.

Files

  • src/main/kotlin/com/github/grishberg/android/li/compose/InspectComposeHierarchyAction.kt
  • src/main/kotlin/com/github/grishberg/android/li/compose/ComposeHierarchyAnalyzer.kt
  • src/main/kotlin/com/github/grishberg/android/li/compose/ComposeInspectDialog.kt
  • src/main/kotlin/com/github/grishberg/android/li/compose/model/{ComposeCandidateNode,ComposeHierarchySummary}.kt
  • src/main/resources/META-INF/plugin.xml (registers the new action inside the existing YALI.TopMenu)
  • docs/COMPOSE_INSPECTOR_SPEC.md, proto/compose_layout_inspection.proto

Test plan

  • Build the plugin locally: ./gradlew buildPlugin. (I was unable to run this in my sandbox — the build needs to download the Android Studio target platform and a JDK 21 toolchain, both blocked behind my proxy. Please confirm the build is green.)
  • Install the built plugin in Android Studio 2024.3.x / 2025.x.
  • Connect a debuggable device, open a Compose-based app, run Tools → YALI → Inspect Compose Hierarchy.
  • Verify the summary numbers look reasonable for a known screen (e.g. open the Now-in-Android sample, hit Inspect Compose Hierarchy — expect non-zero Compose roots and Compose candidates, plus a populated content-description list).
  • Re-run the action while in a fully-classic-View screen and verify the heuristic correctly reports zero Compose roots.

Open as a draft if a reviewer prefers — happy to iterate. The next iteration (Layer 1 in the spec) plugs in the proto-based agent path and yields real @Composable names / source positions.

…mpose Hierarchy

Adds a new menu action that captures the current screen via `uiautomator dump`
and analyses it with a Compose-aware heuristic to produce a summary dialog.
The action is independent of the existing capture flow and does not modify
any code paths used by Launch YALI.

What the new action does:
- enumerates connected devices via the existing ConnectedDeviceInfoProvider;
- runs `adb shell uiautomator dump`, pulls the XML and parses it with a SAX handler;
- classifies nodes as "Compose candidates" by two rules:
    1. any node whose ancestor is `AndroidComposeView` / `ComposeView`;
    2. any `android.view.View` with empty resource-id and a non-empty
       text or content-description (typical for Compose semantics leaves);
- displays a Swing dialog with the summary stats (total / visible /
  Compose roots / Compose candidates / nodes with text / nodes with
  content-desc / nodes with resource-id), a tree of Compose candidates
  and three side tables (top classes, top texts, top content-descriptions);
- `Copy summary to clipboard` button serialises stats as JSON-like text.

Files added:
- docs/COMPOSE_INSPECTOR_SPEC.md — technical spec covering the proper
  App Inspection / compose-ui-inspection.jar approach used by Android
  Studio and explaining why this iteration ships the UI Automator-based
  Layer 0 (with a roadmap for Layers 1 and 2).
- proto/compose_layout_inspection.proto — vendored protocol file
  (Apache 2.0, originates from AOSP / Android Studio source).
  Not used at build time yet, kept for the next iteration.
- src/main/kotlin/com/github/grishberg/android/li/compose/* — implementation:
  - InspectComposeHierarchyAction.kt — the action;
  - ComposeHierarchyAnalyzer.kt — SAX parser + heuristic classifier;
  - ComposeInspectDialog.kt — Swing UI;
  - model/ComposeCandidateNode.kt — TreeNode for the Compose candidate tree;
  - model/ComposeHierarchySummary.kt — summary data class.
- src/main/resources/META-INF/plugin.xml — registers the new action under
  the existing `YALI.TopMenu` group, no other changes.

Why UI Automator first:
The full Compose tree (with @composable names, source file / line, parameter
values, recomposition counts) requires Android Studio's App Inspection
framework: a transport daemon pushed to the device deploys
`compose-ui-inspection.jar` into the target process via JVMTI, and the IDE
talks to it over RSocket-on-UDS using the protobuf in
`proto/compose_layout_inspection.proto`. That path involves Studio internal
APIs in `com.android.tools.idea.appinspection.*`, which are unstable across
Studio releases and require non-trivial wiring.

UI Automator is a much simpler proxy: it walks the accessibility tree, which
exposes Compose nodes that opt in via `Modifier.semantics { ... }`. We lose
internal Compose details but get bounds, text, content-desc, resource-id
and clickable/focusable info — enough to ship a useful summary today and
to validate the UI surface before committing to the full agent integration.

See docs/COMPOSE_INSPECTOR_SPEC.md for the staged roadmap.
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