From a72f5dcd0eeb94bd950b4fa44194de2142a1aa75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 06:18:58 +0000 Subject: [PATCH 1/5] Initial plan From e6b742cca375ab1ae49e48f1ee8026911b603a63 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 06:29:22 +0000 Subject: [PATCH 2/5] Restore launcher readiness check with ANR dismissal; check both logcat markers Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com> --- .github/workflows/run.yml | 11 +++++-- AndroidSdk/Emulator/Emulator.cs | 53 +++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index f1bebfe..abd0b42 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -167,15 +167,20 @@ jobs: for i in $(seq 1 30); do dotnet $TOOL device logcat --output artifacts/device-logcat.txt if grep -q "$APP_START_MARKER" artifacts/device-logcat.txt; then - echo "✅ Marker found on attempt $i" + echo "✅ App marker '$APP_START_MARKER' found on attempt $i" FOUND=1 break fi - echo "Attempt $i/30 - marker not found yet, waiting 5s..." + if grep -q "Displayed $TEST_APP_PACKAGE" artifacts/device-logcat.txt; then + echo "✅ System 'Displayed' marker found on attempt $i" + FOUND=1 + break + fi + echo "Attempt $i/30 - neither marker found yet, waiting 5s..." sleep 5 done if [ "$FOUND" -ne 1 ]; then - echo "❌ Marker '$APP_START_MARKER' not found in logcat after 30 attempts" + echo "❌ Neither '$APP_START_MARKER' nor 'Displayed $TEST_APP_PACKAGE' found in logcat after 30 attempts" cat artifacts/device-logcat.txt exit 1 fi diff --git a/AndroidSdk/Emulator/Emulator.cs b/AndroidSdk/Emulator/Emulator.cs index d0fd0ff..73c70c8 100644 --- a/AndroidSdk/Emulator/Emulator.cs +++ b/AndroidSdk/Emulator/Emulator.cs @@ -373,6 +373,7 @@ public bool WaitForBootComplete(CancellationToken token) } // Keep trying to see if the boot complete prop is set + var booted = false; while (!token.IsCancellationRequested) { if (process.HasExited) @@ -381,14 +382,62 @@ public bool WaitForBootComplete(CancellationToken token) if (adb.Shell("getprop dev.bootcomplete", Serial).Any(l => l.Contains("1")) || adb.Shell("getprop sys.boot_completed", Serial).Any(l => l.Contains("1"))) { - return true; + booted = true; + break; } if (token.WaitHandle.WaitOne(1000)) return false; } - return false; + // After boot_completed=1, wait for the launcher to gain focus. + // On slow emulators (e.g. macOS without KVM) ANR dialogs can + // steal mCurrentFocus and block the launcher from appearing. + // Dismiss them so the launcher can take focus. Use a hard 120s + // timeout so we never block indefinitely — if the launcher + // doesn't appear, proceed anyway since boot IS complete. + if (booted && !token.IsCancellationRequested) + { + var launcherTimeout = TimeSpan.FromSeconds(120); + var launcherSw = System.Diagnostics.Stopwatch.StartNew(); + + while (launcherSw.Elapsed < launcherTimeout && !token.IsCancellationRequested) + { + if (process.HasExited) + break; + + try + { + var output = adb.Shell("dumpsys window displays", Serial); + + if (output.Any(l => + l.Contains("mCurrentFocus", StringComparison.OrdinalIgnoreCase) && + l.Contains("launcher", StringComparison.OrdinalIgnoreCase))) + { + break; + } + + // ANR dialogs block the launcher from getting focus. + // Dismiss them by pressing BACK so the launcher can appear. + if (output.Any(l => + l.Contains("mCurrentFocus", StringComparison.OrdinalIgnoreCase) && + l.Contains("Application Not Responding", StringComparison.OrdinalIgnoreCase))) + { + try { adb.Shell("input keyevent KEYCODE_BACK", Serial); } + catch (SdkToolFailedExitException) { } + } + } + catch (SdkToolFailedExitException) + { + // adb can transiently fail; retry on next iteration. + } + + if (token.WaitHandle.WaitOne(2000)) + break; + } + } + + return booted; } internal bool WaitForCpuLoadBelow(double threshold, TimeSpan timeout, TimeSpan settleDelay, CancellationToken token) From 8c7a92f8c2c8c477f9fc5ffb93538e59996391e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 22 Feb 2026 06:32:38 +0000 Subject: [PATCH 3/5] Require both logcat markers found; log each individually to show ordering Co-authored-by: mattleibow <1096616+mattleibow@users.noreply.github.com> --- .github/workflows/run.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index abd0b42..223a7ad 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -163,28 +163,30 @@ jobs: - name: Validate Launch test app timeout-minutes: 10 run: | - FOUND=0 + FOUND_APP=0 + FOUND_DISPLAYED=0 for i in $(seq 1 30); do dotnet $TOOL device logcat --output artifacts/device-logcat.txt - if grep -q "$APP_START_MARKER" artifacts/device-logcat.txt; then + if [ "$FOUND_APP" -eq 0 ] && grep -q "$APP_START_MARKER" artifacts/device-logcat.txt; then echo "✅ App marker '$APP_START_MARKER' found on attempt $i" - FOUND=1 - break + FOUND_APP=1 fi - if grep -q "Displayed $TEST_APP_PACKAGE" artifacts/device-logcat.txt; then + if [ "$FOUND_DISPLAYED" -eq 0 ] && grep -q "Displayed $TEST_APP_PACKAGE" artifacts/device-logcat.txt; then echo "✅ System 'Displayed' marker found on attempt $i" - FOUND=1 + FOUND_DISPLAYED=1 + fi + if [ "$FOUND_APP" -eq 1 ] && [ "$FOUND_DISPLAYED" -eq 1 ]; then break fi - echo "Attempt $i/30 - neither marker found yet, waiting 5s..." + echo "Attempt $i/30 - waiting 5s... (app_marker=$FOUND_APP, displayed=$FOUND_DISPLAYED)" sleep 5 done - if [ "$FOUND" -ne 1 ]; then - echo "❌ Neither '$APP_START_MARKER' nor 'Displayed $TEST_APP_PACKAGE' found in logcat after 30 attempts" + if [ "$FOUND_APP" -ne 1 ] || [ "$FOUND_DISPLAYED" -ne 1 ]; then + echo "❌ Not all markers found after 30 attempts (app_marker=$FOUND_APP, displayed=$FOUND_DISPLAYED)" cat artifacts/device-logcat.txt exit 1 fi - echo "✅ Launch validated via logcat marker" + echo "✅ Launch validated — both markers found" env: ANDROID_TOOL_PROCESS_RUNNER_LOG_PATH: artifacts/device-launch-validate.log From fafe5adfaa2bfa73c5c962fcb9ebeabac6737fa2 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 22 Feb 2026 11:49:10 +0200 Subject: [PATCH 4/5] Update run.yml --- .github/workflows/run.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index 223a7ad..e8ea2d0 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -24,7 +24,7 @@ jobs: image: system-images;android-34;google_apis;x86_64 abi: google_apis/x86_64 cores: 2 - cpu_threshold: 3 + cpu_threshold: 25 timeout_seconds: 1800 - os: macos-15-intel gpu: guest From 42c0919439a03e9cac74bbeb009c0d385174820f Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Sun, 22 Feb 2026 13:09:28 +0200 Subject: [PATCH 5/5] Update run.yml --- .github/workflows/run.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index e8ea2d0..fb0f1e9 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -24,14 +24,14 @@ jobs: image: system-images;android-34;google_apis;x86_64 abi: google_apis/x86_64 cores: 2 - cpu_threshold: 25 + cpu_threshold: 3 timeout_seconds: 1800 - os: macos-15-intel gpu: guest image: system-images;android-34;google_apis;x86_64 abi: google_apis/x86_64 cores: 2 - cpu_threshold: 3 + cpu_threshold: 25 timeout_seconds: 1800 runs-on: ${{ matrix.os }} env: