We ran into this in a Compose app that uses Jetpack Navigation 3. After navigating twice, agent-device snapshot keeps returning the screen from the first navigation. The first navigation reports fine; the second one (and anything after) doesn't. From that point every selector on the new screen fails to match (click, fill, is, wait, find), even though the app has actually moved on.
adb shell uiautomator dump at the same moment shows the correct screen, so it's not the app or the device — the helper's snapshot just isn't refreshing. Looks like the same family as #564 and #850, but the recovery from #861 only kicks in for system-only captures, so this case (a stale-but-plausible app screen) slips past it.
Repro
Minimal project here: https://github.com/antFrancon/nav3-agent-device-snapshot-repro
It's a bare ComponentActivity with three trivial Nav3 destinations, ~110 lines. ./repro.sh builds, installs, runs the two navigations and checks the mismatch, but by hand it's:
agent-device open com.example.nav3repro --relaunch
agent-device snapshot # Home ok
agent-device click id=to-screen2
agent-device snapshot # Screen 2 ok (first swap refreshes)
agent-device click id=to-screen3
agent-device snapshot # Screen 2 <-- wrong, the app is on Screen 3
At that last step the app really is on Screen 3:
adb shell uiautomator dump /dev/tty # contains screen3-title and screen3-field
Navigation 3 renders every destination inside one AndroidComposeView and swaps the content in place — there's no new Activity or window, dumpsys window | grep mCurrentFocus stays on the same MainActivity the whole time.
Environment
- agent-device 0.19.2 (also saw it on 0.19.3)
- Android emulator, Pixel 8, API 35
- androidx.navigation3 1.0.1 (pulls in navigationevent-compose 1.0.2, activity 1.13.0, compose-ui 1.11.4), Compose BOM 2026.06.01, Kotlin 2.4.0, compileSdk 36 / targetSdk 35 / minSdk 26
Things I checked while cutting it down
- Activity type doesn't matter — happens with both
ComponentActivity and AppCompatActivity.
- Doesn't depend on
entryDecorators, enableEdgeToEdge, ViewModels, a custom theme, or whether you snapshot between the two clicks.
snapshot --force-full doesn't help — it re-emits the cached (stale) tree instead of recapturing.
- Coordinate taps still land, so the app is fine; it's only the helper's tree that's stuck.
- Reproduces every run.
Guess at the cause
The helper's accessibility cache doesn't seem to get invalidated after an in-place content swap that keeps the same window/Activity. uiautomator dump does a fresh getRootInActiveWindow() after waitForIdle, which is why it's unaffected — same cache angle discussed in #429. Resetting the cache before capture, or extending the #861 recovery to also catch a stale/divergent capture (not just system-only) and fall back to uiautomator, would both fix it.
Happy to adjust the repro if that helps.
We ran into this in a Compose app that uses Jetpack Navigation 3. After navigating twice,
agent-device snapshotkeeps returning the screen from the first navigation. The first navigation reports fine; the second one (and anything after) doesn't. From that point every selector on the new screen fails to match (click,fill,is,wait,find), even though the app has actually moved on.adb shell uiautomator dumpat the same moment shows the correct screen, so it's not the app or the device — the helper's snapshot just isn't refreshing. Looks like the same family as #564 and #850, but the recovery from #861 only kicks in for system-only captures, so this case (a stale-but-plausible app screen) slips past it.Repro
Minimal project here: https://github.com/antFrancon/nav3-agent-device-snapshot-repro
It's a bare
ComponentActivitywith three trivial Nav3 destinations, ~110 lines../repro.shbuilds, installs, runs the two navigations and checks the mismatch, but by hand it's:At that last step the app really is on Screen 3:
Navigation 3 renders every destination inside one
AndroidComposeViewand swaps the content in place — there's no new Activity or window,dumpsys window | grep mCurrentFocusstays on the same MainActivity the whole time.Environment
Things I checked while cutting it down
ComponentActivityandAppCompatActivity.entryDecorators,enableEdgeToEdge, ViewModels, a custom theme, or whether you snapshot between the two clicks.snapshot --force-fulldoesn't help — it re-emits the cached (stale) tree instead of recapturing.Guess at the cause
The helper's accessibility cache doesn't seem to get invalidated after an in-place content swap that keeps the same window/Activity.
uiautomator dumpdoes a freshgetRootInActiveWindow()afterwaitForIdle, which is why it's unaffected — same cache angle discussed in #429. Resetting the cache before capture, or extending the #861 recovery to also catch a stale/divergent capture (not just system-only) and fall back touiautomator, would both fix it.Happy to adjust the repro if that helps.