Skip to content

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

Open
thymikee wants to merge 1 commit into
mainfrom
claude/android-orientation-settle
Open

fix(android): return from orientation once the display reports the rotation#2356
thymikee wants to merge 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 +989 B
Package (unpacked) 4.50 MB 4.50 MB +989 B
Package (download) 1.33 MB 1.33 MB +251 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 27.2 ms 27.2 ms +0.0 ms
CLI --help 79.6 ms 78.2 ms -1.3 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.

…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 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.

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