feat: automated widget screenshot via UIAutomator2 + GitHub Actions - #6
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 130cfd638a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| private fun takeScreenshot() { | ||
| val out = File("/sdcard/Pictures/01_widget.png") | ||
| out.parentFile?.mkdirs() | ||
| device.takeScreenshot(out, 1.0f, 100) |
There was a problem hiding this comment.
Fail test when screenshot capture reports failure
UiDevice.takeScreenshot(...) returns a boolean and does not throw on all write failures, but this result is currently ignored. If /sdcard/Pictures/01_widget.png cannot be written (for example due to storage access constraints), the instrumentation test still passes and CI can treat the run as successful while keeping a stale screenshot. Check the return value and fail the test when capture returns false.
Useful? React with 👍 / 👎.
| adb shell cmd statusbar collapse | ||
| sleep 1 | ||
| adb shell am instrument -w -e class info.yuryv.androiddebugmode.screenshot.WidgetScreenshotTest info.yuryv.androiddebugmode.test/androidx.test.runner.AndroidJUnitRunner | ||
| adb pull /sdcard/Pictures/01_widget.png fastlane/metadata/android/en-US/images/phoneScreenshots/01_widget.png || true |
There was a problem hiding this comment.
Stop masking missing screenshot pull failures
The workflow swallows adb pull errors with || true, so a missing /sdcard/Pictures/01_widget.png does not fail the job. In that scenario the run can end as "successful" with "Screenshot unchanged" even though capture failed, which defeats the automation goal. Let this command fail (or add an explicit file-existence check) so broken screenshot runs are surfaced.
Useful? React with 👍 / 👎.
Hierarchy/text dumps go via Log.d("WDIAG") since the test process cannot
write files outside /sdcard/ without the accessibility service. CI now
pulls all /sdcard/Pictures/ screenshots and captures logcat filtered to
WDIAG so widget picker state is visible in artifacts on failure.
…eads-up notifications Launcher3 needs a force-stop/restart to pick up newly installed widget providers; without it the app section never appears in the picker. Heads-up notifications (serial console) were appearing mid-transition and interfering with the widget picker. Also switch scrollUntilVisible to UiScrollable so the scroll stays inside the Launcher3 RecyclerView and cannot accidentally dismiss the picker.
…ble TextView
UIAutomator ACTION_CLICK does nothing on a non-clickable view; device.click(x,y)
sends a raw touch event that propagates to the parent container's onClick. Also
prefer By.clickable(true).hasDescendant(By.text("Widgets")) so the correct target
is identified before falling back to coordinate tap.
…ment failure set -e ensures CI fails if adb instrument exits non-zero. Pre-click screen capture and CLICK_TARGET log reveal exactly what element is being tapped and whether the notification shade is already open at click time.
…is accessible The emulator's persistent Serial console notification expands the notification shade and covers the Launcher3 widget picker during its open transition. Force- collapse it via cmd statusbar collapse both in CI (before test) and in the test itself (after clicking Widgets, before waiting for the picker scrollable).
…popup row
By.clickable(true).hasDescendant(By.text("Widgets")) returns the outermost
clickable container covering all 3 popup items, not the specific Widgets row.
device.click() on that container doesn't reach the individual item's onClick.
shell("input tap x y") at the Widgets TextView centre goes through the native
input pipeline and is delivered directly to the OptionItem's click handler.
The widget tile sits at ~y=830 (⅓ of 2400px screen); dropping at displayHeight/3 was placing the drag endpoint inside the picker itself. Dropping at displayHeight/8 (y=300) ensures the gesture crosses into the home screen area above the picker during Launcher3's drag-to-place transition. Increase steps to 120 for a slower gesture that gives Launcher3 time to register the long-press-to-drag.
…tCell parent not child TextView
…drag to guarantee long-press fires before movement
…1200) with 400 steps
9532126 to
1d61198
Compare
Summary
WidgetScreenshotTest) that places the Debug Mode widget on the AOSP Launcher3 home screen and captures a full-resolution screenshot viaUiDevice.takeScreenshot().github/workflows/screenshots.yml) that runs the test on a KVM-accelerated API 33 emulator and commits the result back to the branch automaticallyfastlane/metadata/android/en-US/images/phoneScreenshots/01_widget.pngTest plan
feature/real-screenshotsbranch (see CI history)01_widget.pngshows the widget on the home screen with USB Debugging chip visibleworkflow_dispatchproduces an updated screenshot without manual steps