Skip to content

fix(android): return from orientation once the display reports the rotation - #2356

Merged
thymikee merged 1 commit into
mainfrom
claude/android-orientation-settle
Sep 7, 2026
Merged

fix(android): return from orientation once the display reports the rotation#2356
thymikee merged 1 commit into
mainfrom
claude/android-orientation-settle

Conversation

@thymikee

@thymikee thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

Android orientation wrote accelerometer_rotation and user_rotation and returned at once, while the display rotated some time later. On the loaded CI emulator that takes seconds, and accessibility reads hang meanwhile.

Evidence: the Android Smoke on #2344, https://github.com/callstack/agent-device/actions/runs/34025424834. wait text landscape right after orientation landscape-left reported wait_capture_stalled with zero readable captures: the helper session request timed out at 5s, the one-shot fallback ran into the wait's deadline, and the failed-step snapshot taken right after was already in landscape (nodes 2400px wide). The rotation had landed; the wait's whole budget went to the transition.

Change

setAndroidOrientation now polls dumpsys display for mCurrentOrientation to match the requested rotation, every 500ms up to 15s, before returning.

  • A display that reaches the rotation returns as soon as it does (about 1s on a local emulator with the fixture app foreground).
  • A display that never gets there fails the command with the observed rotation and a hint, instead of reporting success. This is a behavior change worth a look: on the launcher, which pins portrait (mCurrentAppOrientation=SCREEN_ORIENTATION_NOSENSOR), orientation landscape-left previously "succeeded" without rotating and now fails after 15s with observedRotation: 0.
  • A display that reports no mCurrentOrientation at all is left to the setting, as before.

Validation

  • Unit tests (fake adb, sleep mocked, fake clock for the budget): returns once the display reports the rotation after two stale reads; fails with requestedRotation: 1, observedRotation: 0 when it never does; leaves a display that reports nothing to the setting. Package suite 641 tests green; typecheck, oxlint, oxfmt, fallow clean.
  • Live on a local Pixel 9 Pro XL emulator with the fixture app foreground: orientation landscape-left 1s, mCurrentOrientation=1; orientation portrait 1s, mCurrentOrientation=0.

What this does not explain

The other Android Smoke failure family (the post-alert canary missing while the device is in landscape although orientation portrait had been confirmed) is still open; #2350 adds the rotation evidence for it. This change removes the transition cost from the command that starts a rotation, which is also where a later flip would be visible if it is a delayed re-application.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.50 MB 4.50 MB +973 B
Package (unpacked) 4.50 MB 4.50 MB +973 B
Package (download) 1.33 MB 1.33 MB +291 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.6 ms 29.0 ms +0.4 ms
CLI --help 82.6 ms 81.1 ms -1.5 ms

@thymikee

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

The new dumpsys display probe has no timeout derived from the remaining settle budget, so a stuck probe can bypass the intended 15-second loop. Add a hanging-probe regression and script the new ADB call in the provider scenario. Coverage and Integration currently fail on the unscripted shell dumpsys display call.

@thymikee
thymikee force-pushed the claude/android-orientation-settle branch from 88516f8 to 3104aa0 Compare September 6, 2026 11:14
@thymikee

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

Addressed, rebased onto main (one commit):

  • Each dumpsys display probe is bounded by what is left of the 15s settle budget (timeoutMs: remainingMs(deadline)), and the sleep between probes is bounded the same way, so a stuck probe ends the settle instead of bypassing it. A probe that times out fails the command with orientation <x> could not confirm the display rotation: <adb error>.
  • Regressions: the never-rotates case now also asserts the first probe gets the full 15s and every later probe strictly less; a new hanging-probe case scripts one probe that consumes its whole timeout and throws, and expects one probe, the failure, and the clock at 15s.
  • The provider world scripts shell dumpsys display to report the last settings put system user_rotation, so the Android Settings flow rotates the way the settle expects.

Local: platform-android 645 tests, provider Android scenarios 13, root typecheck, oxlint, oxfmt, fallow (against main) clean.

@thymikee

thymikee commented Sep 6, 2026

Copy link
Copy Markdown
Member Author

The bounded probe and provider scenario fixes are in place at 3104aa0. One failure path still returns success: dumpsys display runs with allowFailure, but its exit code is ignored. A failed ADB call with no orientation in stdout therefore looks like a successful probe that lacks the field. Reject failed probes through the existing ADB error handling and add a non-zero-exit regression; preserve the no-field case only for a successful probe. Android smoke also remains red at the later semantic-canary step.

@thymikee
thymikee force-pushed the claude/android-orientation-settle branch from 3104aa0 to eb426b1 Compare September 7, 2026 05:52
thymikee added a commit that referenced this pull request Sep 7, 2026
The first CI failure with the evidence hook (PR #2356, run 34029660070)
lost its logcat section: dumping the emulator's whole 2MB buffer took
longer than the 5s per-probe bound on the loaded host. The probe now
reads the last 4000 lines, which holds the rotation decisions of the
last minutes and returns well inside the bound.
@thymikee

thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

The failed-display-probe handling is fixed at eb426b1: nonzero exits now fail the operation, with a dedicated regression. The live Android run passed both rotation assertions before failing at automation-press, so that failure is likely unrelated to this change. Ready for human review.

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

`orientation` wrote accelerometer_rotation and user_rotation and returned
at once, while the display rotated some time later. On the loaded CI
emulator that takes seconds, and accessibility reads hang meanwhile: the
Android smoke's `wait text landscape` right after `orientation
landscape-left` got a helper request timeout and then no readable
capture for its whole 10s budget, with the failed-step snapshot taken
afterwards already in landscape (PR #2344, run 34025424834).

The command now polls `dumpsys display` for mCurrentOrientation to
match the requested rotation before returning, each probe bounded by
what is left of the 15s settle budget so a stuck probe ends the settle
as a failure. A display that never gets there fails the command with the
observed rotation instead of reporting success; a display that reports
no rotation at all is left to the setting as before. The provider
scenario scripts the display read against the last user_rotation write.
@thymikee
thymikee force-pushed the claude/android-orientation-settle branch from eb426b1 to cfb529b Compare September 7, 2026 06:25
@thymikee thymikee removed the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 7, 2026
@thymikee

thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

Addressed at cfb529b (rebased onto main, which now includes #2369):

@thymikee

thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

Reviewed cfb529b. No remaining code findings. Failed orientation probes now preserve the ADB error, and the single-probe regression remains covered. Android emulator smoke and the remaining checks pass on this head. Good for human review.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 7, 2026
@thymikee
thymikee merged commit 64b7cc4 into main Sep 7, 2026
23 of 24 checks passed
@thymikee
thymikee deleted the claude/android-orientation-settle branch September 7, 2026 08:14
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-07 08:14 UTC

thymikee added a commit that referenced this pull request Sep 7, 2026
The first CI failure with the evidence hook (PR #2356, run 34029660070)
lost its logcat section: dumping the emulator's whole 2MB buffer took
longer than the 5s per-probe bound on the loaded host. The probe now
reads the last 4000 lines, which holds the rotation decisions of the
last minutes and returns well inside the bound.
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.

1 participant