Skip to content

[Roadmap] feat(studio): Android Studio plugin Phase 1 MVP — thin-client IDE integration - #153

Open
RanjithRagavan wants to merge 3 commits into
google:mainfrom
RanjithRagavan:upstream-android-studio-plugin
Open

RanjithRagavan wants to merge 3 commits into
google:mainfrom
RanjithRagavan:upstream-android-studio-plugin

Conversation

@RanjithRagavan

@RanjithRagavan RanjithRagavan commented Sep 25, 2026 •

Copy link
Copy Markdown

Summary

Implements Phase 1 of the Android Studio Integration roadmap item — a native IDE plugin (thin client) that brings ARTEMIS task dispatch and monitoring into Android Studio.

Part of #152 (Phases 2–3 — run configurations, breakpoint-aware runs, record mode — intentionally left as follow-ups).

@somew1nd @yaoyao-open-source would love your review when you have a moment — happy to adjust scope, directory placement, or packaging to fit the project's conventions.

What the plugin does

  • Tool window (right anchor): server reachability indicator, device dropdown from GET /api/devices, natural-language prompt dispatch via POST /api/run (flash/pro), live task list with 2 s polling via GET /api/sessions/{id}, detail pane, and Stop via POST /api/stop
  • Settings → Tools → ARTEMIS: server base URL, default profile, default device serial
  • Balloon notifications on task completion/failure

Architecture

Strict thin client: the plugin only speaks the same HTTP API as packages/artemis-client (endpoint shapes mirrored field-for-field, including legacy fallbacks like session_id/task_id/trace_id). No agent logic, no credentials surface in the IDE. java.net.http.HttpClient + platform-bundled Gson — zero external dependencies, keeping the plugin small (~1.7 MB zip) and free of dependency conflicts.

┌──────────────────────┐   HTTP    ┌──────────────────┐   ADB   ┌────────┐
│ Android Studio        │ ───────► │ ARTEMIS server   │ ──────► │ Device │
│ ARTEMIS tool window   │ ◄─────── │ (agents/models)  │ ◄────── │        │
└──────────────────────┘           └──────────────────┘         └────────┘

Compatibility

  • since-build="231", no until-build cap → Android Studio Hedgehog 2023.1.1 through current (Iguana/Jellyfish/Koala/Ladybug/Meerkat/Narwhal), and IntelliJ IDEA 2023.1+
  • Compiled/verified against IC 2024.3, JBR 17, IntelliJ Platform Gradle Plugin 2.2.1, Kotlin 2.0.21

Testing

  • 25/25 tests pass (./gradlew test): model JSON parsing (canned payloads mirrored from packages/artemis-client/tests), /api/run request building, and full submit → poll → stop integration against an in-process mock HTTP server, plus error paths (server down, HTTP 500, task rejection, 404 fallbacks)
  • ./gradlew buildPlugin → artemis-android-studio-plugin-0.1.0.zip ✅
  • ./gradlew verifyPluginStructure ✅
  • Not covered here (needs GUI/device): manual install into Android Studio and a live run against a real server — steps documented in android-studio-plugin/README.md; ./gradlew runIde works for a sandbox smoke test
  • Repo CI note: current workflows are Python/frontend-only; a Gradle CI job for android-studio-plugin would be a natural follow-up

Layout

android-studio-plugin/
├── build.gradle.kts / settings.gradle.kts / gradle.properties / gradlew
├── README.md                       (compatibility matrix, install, architecture)
└── src/
    ├── main/kotlin/com/google/artemis/studio/
    │   ├── api/        ArtemisApiClient (java.net.http + Gson), typed exceptions
    │   ├── model/      Device, TaskHandle, TaskResult, Capabilities, RunRequest
    │   ├── settings/   PersistentStateComponent + Configurable
    │   ├── services/   TaskPollingService (coroutines, EDT-safe), notifications
    │   └── toolwindow/ ToolWindowFactory + panel
    ├── main/resources/META-INF/plugin.xml
    └── test/kotlin/... (25 tests)

All sources carry the repo-standard Apache 2.0 header.

Test plan

  • ./gradlew test — 25/25 pass
  • ./gradlew buildPlugin + verifyPluginStructure — pass
  • Manual: install zip into Android Studio, point at a running artemis ui server, dispatch a task (documented in plugin README)

@RanjithRagavan

Copy link
Copy Markdown
Author

Note on the failing zizmor-output check: the findings (unpinned action reference in ci.yml lines 33/36/44/…) are pre-existing on main — actions/checkout@v4, actions/setup-python@v5, astral-sh/setup-uv@v6 etc. are tag-pinned rather than hash-pinned in the base branch, and this PR's diff touches only the new android-studio-plugin/ directory (no workflow files). The Sep 13 security scan on main itself ended in action_required for the same reason, so this will fail for any PR until the actions are hash-pinned repo-wide.

I'm happy to open a separate PR that pins all workflow actions to their commit SHAs (with # tag=vX comments for readability) — it would need a maintainer to confirm that's wanted, since external contributors can't push workflow-file changes without elevated token scopes.

…egration

Implements Phase 1 of the Android Studio Integration roadmap item (google#152):
- Tool window: server status, device picker (GET /api/devices),
  natural-language task dispatch (POST /api/run), live status polling
  (GET /api/sessions/{id}), task stop (POST /api/stop)
- Settings page (Tools > ARTEMIS): server URL, default profile, device serial
- Thin client over the same HTTP API as packages/artemis-client; no agent
  logic in the IDE; java.net.http + Gson, zero external dependencies
- Kotlin models mirror the Python artemis-client payload shapes, including
  legacy field fallbacks
- 25 unit/integration tests (model parsing, request building, submit/poll/
  stop against a mock HTTP server, error paths)
- Compatibility: since-build 231 (Android Studio Hedgehog+ / IntelliJ
  2023.1+), no until-build cap; verified with buildPlugin +
  verifyPluginStructure
@RanjithRagavan
RanjithRagavan force-pushed the upstream-android-studio-plugin branch from 66a791f to b23bd95 Compare September 30, 2026 06:03
Self-review pass before upstream review:
- ArtemisProtocolException now extends ArtemisApiException so parser
  failures surface as UI errors instead of IDE error reports
- TaskPollingService stops the 2s polling loop when no active tasks
  remain; poll cycles serialized to prevent double completion
  notifications; server-unreachable status reported on transitions only
- submit() mirrors client.py setdefault semantics for session_id;
  listDevices() accepts missing 'devices' key per the Python client;
  device_info accepted in JSON-string form
- Clear stale error tooltip after server recovery
- 30/30 tests green, buildPlugin passes
@RanjithRagavan

Copy link
Copy Markdown
Author

Rebased onto latest main (post third-party reorg — no conflicts, diff remains android-studio-plugin/ only) and completed a self-review hardening pass:

  • Polling lifecycle: the 2 s status loop now exits when no active tasks remain (previously a permanent heartbeat per open project), and poll cycles are serialized to prevent double completion notifications
  • Error taxonomy: protocol/parse errors now surface as readable UI errors instead of IDE error reports
  • API parity with packages/artemis-client: session_id setdefault semantics, missing devices key tolerance, device_info in JSON-string form

Test count grew 25 → 30, all green; buildPlugin + verifyPluginStructure pass. Ready for review whenever you have time, @somew1nd — and note the failing zizmor-output gate here is the repo-wide unpinned-actions issue fixed in #164.

Found by live integration testing against a real ARTEMIS server:
java.net.http defaults to HTTP/2 and sends an h2c upgrade attempt on the
first request. Uvicorn does not support cleartext upgrade; while
processing it the POST body is lost, so FastAPI rejects /api/run with
422 'body: Field required' and task submission always failed from the
IDE (Python/curl clients were unaffected as they speak HTTP/1.1).

Pinning HTTP_1_1 makes submit() succeed against the live server
(verified end-to-end: task admitted, executed on emulator-5554).
@RanjithRagavan

Copy link
Copy Markdown
Author

Live integration test result (real server + emulator, not just mocks): caught and fixed a genuine transport bug — java.net.http defaults to HTTP/2 and attempts an h2c upgrade on first request; uvicorn drops the POST body during the unsupported upgrade, so /api/run returned 422 and IDE-side submission always failed. Fixed by pinning HttpClient.Version.HTTP_1_1 (commit 08050ab); verified end-to-end — task submitted from the IDE, admitted by the server, and executed on emulator-5554. This is exactly the class of bug the mock-based tests could not see; a live smoke test is now part of the plugin README's verification checklist.

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