Repository navigation
fix(android): open the macOS emulator window behind the focused app - #3617
Conversation
The emulator activates itself when its window opens, and it has no flag to stop that. A GUI launch on macOS now starts a short JXA watcher. When the emulator becomes frontmost, the watcher reactivates the app that was frontmost before it, so the window lands directly below that app. Co-Authored-By: Claude <noreply@anthropic.com>
…launch path Production boots emulators through readiness/runtime.ts and the host launch port. This second launch path had no caller outside its own tests. Co-Authored-By: Claude <noreply@anthropic.com>
|
There was a problem hiding this comment.
All reported issues were addressed across 6 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
Size Report
Startup median (7 runs, lower is better):
|
Read the frontmost app before spawning the emulator, so the watcher has an app to restore even if the emulator activates before its first poll. Bound the watcher by the remaining startup budget instead of a fixed 30 seconds. The launch port is async now because it reads the frontmost app. Co-Authored-By: Claude <noreply@anthropic.com>
|
The code in 2cb3c31 looks right to me, and I found no defect in the change itself. Checks are still pending: Smoke Tests and Analyze are queued, and Compatibility & Provenance was cancelled, probably because a newer run replaced it. The diff only touches the Android emulator launch host and dead platform-android code, and CI does not run the macOS GUI emulator route, so nothing points to a failure from this PR. I did not reproduce the live macOS GUI boot. I relied on the base-vs-head table in the PR body (macOS 26.6.2, emulator 36.2.12). I assumed the Not blocking: the new sentence at https://github.com/callstack/agent-device/blob/2cb3c31/website/docs/docs/commands.md#L69 says the window "returns focus to it", but the watcher returns focus, not the window. It also sits only under Two open inline threads from the other review still hold, and I would like them addressed before this is ready. The first is that the unit test only checks that the script contains Before merge, please address those two threads; the queued Smoke Tests and Analyze jobs need to finish green, and Compatibility & Provenance needs a rerun. No conflicts. |
There was a problem hiding this comment.
All reported issues were addressed across 13 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…pp read runCmd rejects on a timeout or a missing tool even with allowFailure, so a failed lsappinfo read stopped the AVD from booting. Treat the read as best-effort, give it a 1 s budget, and say in the docs that open takes the same route as boot. Co-Authored-By: Claude <noreply@anthropic.com>
|
Replies to the review of 2cb3c31. Current head is d5562c8.
|
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
The code looks good at d5562c8, and I found nothing that blocks it. No conflicts. CI is still pending: CodeQL, both Smoke Tests, deploy-preview and Coverage are queued or running, and none has failed. The Smoke Tests do exercise the Android readiness launch route that this diff makes async. If one fails on a Linux or headless runner, look at the await and the boot budget change first, because the watcher only runs for windowed macOS launches. I did not rerun the live macOS boot. I relied on the PR body's run at 3ad7668, and the later change only touches the failure branch of the frontmost read. I also did not verify that the emulator launcher pid is the same pid that becomes frontmost. The reported live run on emulator 36.2.12 implies it is. Not blocking, and you can take or leave these: the detached osascript watcher in https://github.com/callstack/agent-device/blob/d5562c8/src/platform-runtime-android-emulator-host.ts#L50 keeps its 50 ms wakeups after a cancelled boot until the boot budget ends, because the emulator is terminated but the watcher is not. It could exit when the emulator pid is no longer running. Also, the watcher stops at the boot deadline, so an emulator that activates after a boot_timeout can still take focus. Please say that in the same best-effort wording as the docs fix below. On the open threads, the Cubic thread on the unqualified docs claim still applies: #3617 (comment). The four other Cubic threads are fixed at this head, so please resolve them: #3617 (comment) (failed frontmost read is now caught), #3617 (comment) (pid is read before spawn and passed as argv), #3617 (comment) (boot budget replaces the 30s cap), and #3617 (comment) (test asserts the pid and budget reach argv). Before merge, please qualify the wording in website/docs/docs/commands.md as best-effort, then wait for the queued Smoke Tests and Coverage to pass on d5562c8. |
Co-Authored-By: Claude <noreply@anthropic.com>
|
Replies to the review of d5562c8. Current head is 8e1b826, which only changes docs.
|
|
The code in 8e1b826 looks good to me. The three problems from the earlier review at d5562c8 are fixed: a failed frontmost read is now caught, the frontmost pid is read before spawn and passed as argv, and the boot budget replaces the fixed cap. The docs now describe the behavior as best-effort and name both gaps, which matches the host code. CI is green: 22 checks, none failing. The delta since d5562c8 is docs-only, and the author reports Smoke Tests, Coverage, Integration, CodeQL and Compatibility & Provenance passed on that commit. There are no conflicts, and nothing else stands in the way of merge. I did not rerun the live macOS windowed boot. I relied on the run in the PR body at 3ad7668, and later commits only touched the frontmost-read failure branch and the docs. I also did not verify that the emulator launcher pid is the same pid that becomes frontmost, though the reported live run implies it is. Unit tests cannot observe the JXA activation behavior, which needs a window server. I did not check whether other docs or help text repeat the unqualified focus claim. |
Summary
On macOS, a GUI Android emulator launch (
boot --platform android --device <avd>, oropenbooting a stopped AVD) took focus from the app you were using. The emulator has no flag to stop this;-qt-hide-windowhides the window, and Qt's background-only mode removes the Dock icon and Cmd-Tab entry. The launch host now reads the frontmost app withlsappinfobefore spawning the emulator, then starts a JXA watcher for the remaining startup budget. When the emulator becomes frontmost, the watcher reactivates the previous app once and exits. The window lands directly below that app, which matches how iOS opens Simulator withopen -g. Headless and non-macOS launches are unchanged. TheandroidEmulator.launchport is async now and receives the boot budget.The second commit removes
ensureAndroidEmulatorBooted. Production boots emulators only throughreadiness/runtime.tsand the hostlaunchport, so this other launch path had no caller outside its own tests.Validation
Tested head
3ad7668d79, macOS 26.6.2, emulator 36.2.12, AVDPixel_9_Pro_XL_API_37. Frontmost app polled every 20 ms duringagent-device boot:1s front: qemu-system-aarch64, focus stays stolen3s front: qemu-system-aarch64, then back toClaudewithin the same second; window order:Claude, thenqemu-system-aarch64No watcher process was left after the run.
pnpm check:affected --run: passed on8e1b826052. CI passed in full ond5562c845b, and8e1b826052only changes docs wording. The later commits only make the frontmost-app read best-effort and change docs wording, so the live run on3ad7668d79still covers the success path.Remaining risk: the emulator holds focus for up to ~50 ms (one watcher poll).