Say who closed the picker, because it was us and the KDoc denied it
The commit below describes "a back press aimed at a picker that had closed five seconds earlier". The timing is right and the agency is wrong, and the agency is the interesting half. Re-read out of the same logcat: 20:59:35.686 UiDevice: Retrieving node ... [RES='android:id/button1']. 20:59:35.689 UiObject2: Clicking on (927, 2274). 20:59:36.033 MainActivity RESUMED 20:59:36.350 VRI[PickActivity]: visibilityChanged ... newVisibility=false `aerr_wait` and `aerr_close` both missed on that iteration and `dismissASystemErrorDialog` fell through to `android:id/button1` -- the framework's generic AlertDialog positive button, which is on every AlertDialog on the device. It hit one inside DocumentsUI, and that is what closed the picker. The picker did not close on its own; this class closed it. So the destroyed Activity and #271 are one incident rather than two findings that happened to share a trace, and the loop's shape is three iterations rather than two: iteration 2 closes the picker through `button1` and then presses back into an app that is already in front, iteration 3 dismisses the launcher's ANR dialog and presses again, and that press finishes MainActivity. It also sharpens what the fix does. With the re-read, iteration 2 returns -- the app is focused within a second of the `button1` click -- so neither of the two presses that followed it happens at all. The previous message implied the fix caught only the last one. `requireAReadableScreen` now drops a Boolean return value, which this codebase treats as a smell. It is correct there -- the `device.wait` on the next line is the re-probe -- and the call site says so rather than leaving a reader to work out whether it was an oversight. No behaviour change beyond the comment: the fix itself is unchanged and the sweep is re-run because `app/src` is touched. Refs #102, #271 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -978,6 +978,8 @@ class SafPickerRoundTripTest {
|
||||
private fun requireAReadableScreen() {
|
||||
val app = By.pkg(appPackage)
|
||||
if (device.wait(Until.hasObject(app), READABLE_TIMEOUT_MS) == true) return
|
||||
// The return value is deliberately dropped here: the wait on the next line IS the re-probe
|
||||
// that dismissThePicker had to be given, so there is nothing for it to gate.
|
||||
dismissASystemErrorDialog()
|
||||
if (device.wait(Until.hasObject(app), READABLE_TIMEOUT_MS) == true) return
|
||||
unlockTheDevice()
|
||||
@@ -1171,21 +1173,31 @@ class SafPickerRoundTripTest {
|
||||
* `34161043035` attempt 1, which is #269's own head:
|
||||
*
|
||||
* ```
|
||||
* 20:59:36.033 MainActivity RESUMED <- the save picker has already returned
|
||||
* 20:59:41.094 UiDevice: Retrieving node with selector: BySelector [RES='android:id/aerr_wait']
|
||||
* 20:59:35.689 UiObject2: Clicking on (927, 2274) <- iteration 2's dismissal, on button1
|
||||
* 20:59:36.033 MainActivity RESUMED <- so the picker is gone, by our hand
|
||||
* 20:59:36.350 VRI[PickActivity]: visibilityChanged ... newVisibility=false
|
||||
* 20:59:37.068 UiDevice: Pressing back button. <- iteration 2 presses anyway
|
||||
* 20:59:41.094 UiDevice: Retrieving node ... [RES='android:id/aerr_wait']
|
||||
* 20:59:41.169 Input channel object 'Application Not Responding:
|
||||
* com.google.android.apps.nexuslauncher' was disposed
|
||||
* 20:59:41.713 UiDevice: Pressing back button.
|
||||
* 20:59:41.713 UiDevice: Pressing back button. <- iteration 3
|
||||
* 20:59:41.754 TopTaskTracker: onTaskMovedToFront: ... NexusLauncherActivity
|
||||
* 20:59:42.278 MainActivity DESTROYED
|
||||
* ```
|
||||
*
|
||||
* The launcher's ANR dialog — #93's occluder, still ambient on these runners — was the only
|
||||
* reason the focus read false. Removing it made the app focused, and the back press aimed at a
|
||||
* picker that had closed five seconds earlier finished `MainActivity` instead. Every later
|
||||
* `onActivity` in the test then threw
|
||||
* Read the first two lines before the rest, because they are the part that is easy to get
|
||||
* wrong: **the picker did not close on its own — this function closed it**, on iteration 2,
|
||||
* when [dismissASystemErrorDialog] fell through to `android:id/button1` and clicked what was
|
||||
* almost certainly DocumentsUI's own positive button (#271). From `20:59:36.033` onwards there
|
||||
* was nothing left to back out of. Iteration 2 pressed back regardless, iteration 3 dismissed
|
||||
* the launcher's ANR dialog — #93's occluder, still ambient on these runners, and the only
|
||||
* remaining reason the focus read false — and pressed again, and that press finished
|
||||
* `MainActivity`. Every later `onActivity` in the test then threw
|
||||
* `NullPointerException: Cannot run onActivity since Activity has been destroyed already`.
|
||||
*
|
||||
* **With the re-read below, iteration 2 returns** — the app is focused within a second of the
|
||||
* `button1` click — and iterations 2 and 3 never press at all.
|
||||
*
|
||||
* **So the reading is retaken after the dialog goes, and only then.** This removes a back
|
||||
* press sent on a stale reading; it does not retry one, and it does not make the dismissal
|
||||
* more tolerant. A picker that really is in front still leaves the app unfocused, so the press
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
with a disposition for each. **1489 gating leg-attempts, 129 failures, 8.7%** — 2026-08-20 to
|
||||
2026-09-07. This is the standing answer to "my docs-only PR turned an emulator leg red, what is
|
||||
it?", and it is what #102 asked for before being closed as an umbrella.
|
||||
**Last verified:** 2026-09-07, against `main` at `ef9d35e`.
|
||||
**Last verified:** 2026-09-07, against `main` at `ef9d35e`. Mode 6's fix is in #272 and is the only
|
||||
thing here not yet on `main`.
|
||||
|
||||
This document is about **the emulator failing underneath the suite**. It is not a defect record
|
||||
(`docs/defect-audit.md`), not a coverage read (`docs/coverage-read-findings.md`), and not a
|
||||
@@ -108,20 +109,28 @@ Traced on the API 35 gating leg of run `34161043035` **attempt 1**, whose head i
|
||||
commit:
|
||||
|
||||
```
|
||||
20:59:36.033 MainActivity RESUMED <- the save picker has already returned
|
||||
20:59:37.068 UiDevice: Pressing back button.
|
||||
20:59:35.689 UiObject2: Clicking on (927, 2274) <- iteration 2's dismissal, on button1
|
||||
20:59:36.033 MainActivity RESUMED <- the picker is gone, by the test's own hand
|
||||
20:59:36.350 VRI[PickActivity]: visibilityChanged ... newVisibility=false
|
||||
20:59:37.068 UiDevice: Pressing back button. <- iteration 2 presses anyway
|
||||
20:59:41.094 UiDevice: Retrieving node ... [RES='android:id/aerr_wait']
|
||||
20:59:41.169 Input channel 'Application Not Responding: ...nexuslauncher' was disposed
|
||||
20:59:41.713 UiDevice: Pressing back button.
|
||||
20:59:41.713 UiDevice: Pressing back button. <- iteration 3
|
||||
20:59:41.754 TopTaskTracker: onTaskMovedToFront: ... NexusLauncherActivity
|
||||
20:59:42.278 MainActivity DESTROYED
|
||||
```
|
||||
|
||||
`dismissThePicker` guarded its back presses on `Activity.hasWindowFocus`. A system app-error dialog
|
||||
is a fullscreen `system_server` window, so **it makes that false too** — the guard could not tell
|
||||
"the picker is still up" from "a dialog is on top of an app that is already in front". The loop
|
||||
dismissed the launcher's ANR dialog (#93's occluder, still ambient) and then pressed back on the
|
||||
reading it had taken before doing so, into an app with nothing left to go back to.
|
||||
"the picker is still up" from "a dialog is on top of an app that is already in front".
|
||||
|
||||
**And the first two lines are the part to read carefully, because the obvious reading is wrong.**
|
||||
The picker did not close on its own: `dismissASystemErrorDialog` closed it on iteration 2, by
|
||||
falling through to `android:id/button1` and clicking DocumentsUI's own positive button (#271). From
|
||||
`20:59:36.033` there was nothing to back out of — and the loop pressed back on iteration 2 anyway,
|
||||
then dismissed the launcher's ANR dialog on iteration 3 and pressed again on the reading taken
|
||||
before doing so. That press finished `MainActivity`. **So this mode and #271 are one incident**, and
|
||||
the fix stops it at iteration 2, where the re-read now returns.
|
||||
|
||||
Fixed by re-reading the focus after a dialog is actually dismissed, and only then —
|
||||
`SafPickerRoundTripTest.dismissThePicker` carries the trace. That **removes** a press sent on a
|
||||
|
||||
Reference in New Issue
Block a user