Skip to content

fix: remove Android ADB swipe fallbacks#1243

Merged
thymikee merged 16 commits into
mainfrom
agent/drop-android-swipe-fallback
Jul 13, 2026
Merged

fix: remove Android ADB swipe fallbacks#1243
thymikee merged 16 commits into
mainfrom
agent/drop-android-swipe-fallback

Conversation

@thymikee

@thymikee thymikee commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Route Android gesture plans, scroll, and long-press through one planned-touch boundary: provider-native touch when available, otherwise the bundled instrumentation helper. This removes every production adb shell input swipe path and surfaces helper failures instead of silently executing a lower-fidelity fallback.

The Android-local executor accepts the cross-platform GesturePlan plus a stationary long-press plan. Touch providers own a paired touch/viewport capability; helper long-press skips the unused viewport round-trip, while provider long-press receives its validated provider viewport. Helper install/manifest ownership is split from gesture transport to keep modules local and bounded.

Scroll remains viewport-planned and returns the absolute coordinates it executes against a coherent zero-origin reference frame. Public 0–15 ms scroll durations remain accepted on Android, normalize to the planner's 16 ms physical minimum, and report the executed duration. The long-press request envelope is 210 seconds so helper identity/install work, snapshot-helper handoff, a 120-second hold, and helper completion overhead all fit on a cold route.

On bare ADB, scroll and long-press require the bundled touch helper and UiAutomation; installation or runtime failure is reported directly. The optional follow-up to reuse one helper preparation across scroll viewport and injection is tracked in #1250 with a no-bundle-growth acceptance criterion.

Closes #690.

Validation

  • pnpm check:affected --base origin/main --run: all runnable checks passed
  • Related suite: 2,522/2,522 tests passed
  • Full coverage: 4,121/4,121 tests across 474 files passed
  • Provider integration: 125/125 tests passed
  • Typecheck, lint, format, layering, Fallow, production-unused exports, and build passed
  • Fresh build against current origin/main: -4 B raw JS, -2 B gzip
  • Pixel 9 Pro XL API 37 / emulator-5556: scroll returned android-multitouch-helper 0.19.3, 8 injected events, and absolute coordinates (672,1546) -> (672,1446)
  • Pixel 9 Pro XL / emulator-5554: helper 0.19.3 active and the viewport-free helper long-press completed successfully; all manual sessions were closed

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.7 MB 1.7 MB -79 B
JS gzip 542.6 kB 542.6 kB +9 B
npm tarball 652.9 kB 653.1 kB +207 B
npm unpacked 2.3 MB 2.3 MB +407 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.3 ms 28.3 ms +1.0 ms
CLI --help 57.4 ms 58.0 ms +0.5 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/sdk-android-adb.js -133 B -27 B
dist/src/runner-client.js 0 B -13 B
dist/src/sdk-batch.js +8 B +9 B
dist/src/session.js 0 B -7 B
dist/src/cli.js 0 B +4 B

@thymikee thymikee changed the title fix: remove Android gesture swipe fallback fix: remove Android raw swipe touch paths Jul 13, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Scope expanded after the review follow-up: scroll and long-press were the two remaining production users of raw adb shell input swipe, and both now share planned provider/helper touch execution. A repository search confirms no production Android raw swipe path remains.

I intentionally left snapshot recovery, text-input compatibility, selector recovery, and app-launch heuristics unchanged: they are separate reliability/lookup contracts rather than touch-execution fallbacks, so removing them would not complete this migration and would reduce supported behavior.

@thymikee thymikee changed the title fix: remove Android raw swipe touch paths fix: route Android gestures through planned touch backends Jul 13, 2026
@thymikee thymikee marked this pull request as ready for review July 13, 2026 14:07
@thymikee

Copy link
Copy Markdown
Member Author

Coordinator + independent review at e92a3224f: the Android planned-touch migration is not ready yet despite 22 green checks.

  1. A valid Android longpress ... 120000 can outlive the generic 90-second client request envelope. The helper/runtime accept 120 seconds and the instrumentation timeout expands, but the command descriptor still uses the generic interaction timeout; align the outer timeout policy and add boundary coverage.
  2. readAndroidGestureViewport throws a generic error on nonzero helper exit before parseAndroidGestureViewportResult can preserve the helper's structured message/errorType. Scroll and long-press now depend on this route, so retain actionable failure details.
  3. The focused tests do not drive performGestureAndroid through a failing single-pointer helper. Reintroducing the removed catch + adb-input-swipe-fallback would still pass them. Add a regression proving helper failure propagates with no raw swipe invocation.
  4. Practical emulator evidence is still missing. Run the changed long-press/scroll/gesture paths through the bundled helper and capture backend metadata (android-multitouch-helper or provider-native-touch) plus direct failure propagation; mocked provider integration does not prove shipped UiAutomation.injectInputEvent behavior.

No branch changes or fixer were dispatched.

@thymikee

Copy link
Copy Markdown
Member Author

Addressed all four points in a40b8f695:

  1. longpress now has a 150-second base request envelope, covering the maximum valid 120-second hold plus the helper's 15-second completion overhead. The descriptor policy and client timeout tests include the 120000 boundary; --settle still widens from that base.
  2. Viewport instrumentation records are parsed before a nonzero process exit is generalized. A structured helper failure now keeps its message, errorType, and helper payload; unparseable process failures still retain the ADB execution details.
  3. The regression now drives a failing single-pointer plan through executeAndroidTouchPlan, not just the helper parser. It requires the propagated AppError message/code/error type; any subsequent raw ADB command would also fail the focused provider script. This tests the behavior guarantee without restoring a fallback-specific test.
  4. Live Pixel 9 Pro XL API 37 evidence uses freshly packaged helper version 0.19.3. Snapshot reported android-helper; long-press diagnostics selected android_multitouch_helper_gesture; scroll and pan returned backend: android-multitouch-helper, with pan reporting 33 injected events. A safe malformed plan sent through the real production executor and installed helper returned COMMAND_FAILED, java.lang.IllegalArgumentException, and Planned pointer path requires at least two samples, proving structured failure propagation end-to-end without modifying device state.

Local validation is green: focused suites 64/64, full provider/coverage aggregate 4,097/4,097 across 472 files, plus typecheck, lint, format, layering, fallow, helper packaging, and build. A fresh comparison against current origin/main is -3,843 B raw JS and -1,258 B gzip.

@thymikee

thymikee commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

Re-review at 6c2efd8 found three remaining production-contract blockers despite green CI and the live helper evidence:

  1. The 150s longpress envelope covers the 120s hold plus gesture-call overhead, but not the preceding first-run helper install and gestureViewport instrumentation call (up to 45s). A valid max-duration first run can still time out outside while helper work continues. Derive the outer budget from the full route and add first-run boundary coverage.
  2. scrollAndroid injects viewport-offset absolute coordinates but returns the unoffset plan. Recording consumes the returned x1/y1/x2/y2, so non-zero viewport origins can record/replay a different path. Return the executed coordinates, matching the WebDriver path.
  3. Shared scroll validation permits duration-ms 0, but Android now feeds zero into gesture planning, which rejects durations below 16ms. Preserve the public scroll contract or tighten it consistently across surfaces, with regression coverage.

No fixer was dispatched.

@thymikee thymikee force-pushed the agent/drop-android-swipe-fallback branch from 6c2efd8 to dae33d4 Compare July 13, 2026 16:54
@thymikee thymikee changed the title fix: route Android gestures through planned touch backends fix: remove Android ADB swipe fallbacks Jul 13, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Addressed the end-to-end review in dae33d48e:

  • Bare-ADB long-press no longer resolves a viewport. It prepares the helper once and runs only gesture instrumentation; provider-native long-press still receives its validated provider-owned viewport.
  • The provider type now makes touch and viewport genuinely paired in both union arms, and one Android-local resolver returns that capability as a unit.
  • Scroll response metadata is absolute again and matches the injected coordinates.
  • Viewport process-error handling now has one generic throw while preserving structured helper failures.
  • ADR 0013 and the PR release note explicitly document the new bare-ADB helper/UiAutomation dependency and direct failure behavior.
  • The optional scroll prepared-helper reuse was prototyped, but it made the JS bundle grow. I removed that extra orchestration and tracked the latency polish in perf(android): reuse touch-helper preparation across scroll viewport and injection #1250 with a raw+gzip non-growth acceptance criterion. The final PR is -137 B raw JS and -1 B gzip against a fresh origin/main build.

Live evidence on emulator-5556: helper 0.19.3 scroll injected 8 events and returned the executed absolute path (672,1546) -> (672,1446). Helper long-press also completed on emulator-5554 without a viewport probe in the focused call transcript. All manual sessions are closed.

@thymikee

Copy link
Copy Markdown
Member Author

Current-head re-review at 96b24e1 found that #1243 is still not ready:

  1. The max-duration timeout blocker remains. Removing the viewport probe helps, but a cold helper path can still spend up to 30s installing before a 120s hold plus 15s gesture overhead. The 150s outer envelope can therefore expire before a valid first-run command finishes. Budget the complete route and cover the cold boundary.
  2. The public scroll contract still accepts duration-ms 0 through 15, while Android passes it to gesture planning, which requires at least 16ms. Preserve the accepted public behavior or tighten the shared contract consistently.
  3. Returning absolute injected coordinates with viewport-only referenceWidth/referenceHeight makes recording visualization scale against the wrong origin when viewport x/y is non-zero. Return a coherent reference frame or explicit origin so recorded touch evidence matches the executed path.

The injected-coordinate mismatch itself is fixed, and the live helper evidence remains useful. No fixer was dispatched.

@thymikee thymikee force-pushed the agent/drop-android-swipe-fallback branch from 96b24e1 to cab53f6 Compare July 13, 2026 17:39
@thymikee

Copy link
Copy Markdown
Member Author

Addressed all three current-head findings in cab53f64f:

  1. Cold max-duration route: raised the long-press request envelope from 150s to 210s. The budget now covers helper identity/install work, snapshot-helper handoff, the 120s hold, and the helper's 15s completion overhead. Timeout-policy and daemon-client boundary tests cover both the base envelope and --settle widening.
  2. Public scroll durations 0–15ms: preserved the accepted public contract. Android normalizes those values to the planner's 16ms physical minimum and reports durationMs: 16, so the response remains honest about what executed. Tests cover both 0 and 15.
  3. Absolute coordinate reference frame: Android keeps returning the injected absolute path, but now reports zero-origin reference extents as viewport.x + viewport.width and viewport.y + viewport.height. Recording telemetry tests prove the absolute path and frame stay paired when the viewport origin is non-zero.

The branch is rebased onto current main. check:affected passed all runnable checks: 2,522 related tests, 4,121 coverage tests, and 125 provider-integration tests. Fallow and production-unused-export checks are clean. A fresh bundle comparison remains negative at -4 B raw / -2 B gzip.

@thymikee

Copy link
Copy Markdown
Member Author

Current-head review at cab53f6 confirms the three production fixes and all checks are green after rerunning the unrelated settle-observation contention failure. One focused regression gap remains before readiness: directly assert that runAndroidMultiTouchHelperGesture uses timeoutMs 135000 for a 120000ms request. The current helper timeout test only exercises a short gesture and expects the 45000ms floor; reverting the helper to its old fixed 45s timeout would still pass the new outer-envelope and longpress-shape tests. No fixer was dispatched.

@thymikee

Copy link
Copy Markdown
Member Author

Addressed the final regression gap in c97142277. The helper test now builds the real 120,000ms Android long-press request, calls runAndroidMultiTouchHelperGesture, and directly requires the ADB executor timeout to be 135_000. Reverting the implementation to the old fixed 45-second timeout now fails this test. Focused helper tests (8/8), lint, and typecheck pass.

@thymikee thymikee merged commit 66910f1 into main Jul 13, 2026
22 checks passed
@thymikee thymikee deleted the agent/drop-android-swipe-fallback branch July 13, 2026 18:12
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-07-13 18:12 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.

Drop automatic adb input swipe fallback from Android gesture swipes

1 participant