skip to content

Driver Idle Detection

Before it will touch the screen the driver waits for the app to go quiet, and the two platforms measure quiet differently - which is why the same suite is slow on one and jumpy on the other.

on this pageshow

explore

questions

4

In Appium, what does the driver wait to go quiet before it touches the screen on Android and iOS?

level: juniorimportance: should knowfreq 58%

answer

  1. the driver waits before it acts
  2. two platforms, two idle signals
  3. one watches an event stream
  4. the other watches a thread
  5. iOS adds an animation cool-off

basics

~20 s

Appium's UiAutomator2 driver on Android waits for the device's accessibility event stream to fall silent. Its XCUITest driver on iOS waits for the app's own main thread to settle, then adds an animation cool-off window.

solid answer

~40 s

Before Appium dispatches a tap it first waits for the app to look settled, and the two platforms measure "settled" with different signals. On Android, the UiAutomator2 driver reaches the screen through the accessibility framework and treats the device as idle once the accessibility event stream stops producing events; that wait is bounded by UiAutomator2's `waitForIdleTimeout` setting, 10000 ms by default. On iOS, the XCUITest driver waits for the application under test to become *quiescent* — for its main thread to stop working — bounded by `appium:waitForIdleTimeout`, and XCUITest adds a further settle window through its `animationCoolOffTimeout` setting. So an Android screen that keeps emitting events and an iOS screen that keeps its main thread busy both stall the driver, but for different reasons and through different knobs.

go deeper

for a junior

Be able to say that Appium waits for the app to settle before it interacts, and that Android's UiAutomator2 driver and iOS's XCUITest driver watch different signals to decide it has.

for a middle

Explain the mechanics: the accessibility event stream on Android bounded by the waitForIdleTimeout setting at 10000 ms, main-thread quiescence on iOS bounded by the appium:waitForIdleTimeout capability plus the animationCoolOffTimeout window.

for a senior

Show you can attribute suite slowness to the right layer — recognise a screen whose events or main thread never go quiet, and reason about what changing the bound costs in tap reliability.

for a principal

Own the position that idle configuration is per-platform by nature, and that a suite carrying one shared timeout constant for Android and iOS has encoded a false equivalence into its framework.

## Why a driver waits at all An Appium interaction — a tap, a swipe, a keystroke — is not fired the moment your test asks for it. Both native drivers first ask the device whether the application has stopped changing, and only dispatch the interaction once the answer is yes or the wait has run out of patience. The reason is mechanical: a tap that lands while a view is still sliding into position can hit the wrong coordinates, hit a view that is about to be replaced, or hit nothing at all. This check sits **below** anything your test does. It is not the wait you wrote, and it runs on every interaction even when your test never asks to wait for anything. It is also, in most suites, the largest single line item in wall-clock time that nobody has ever looked at. The catch — and the whole content of this topic — is that **the two platforms measure "stopped changing" with different signals, on different layers, through differently-shaped configuration**. ## Android: quiet means the accessibility event stream stopped Appium's UiAutomator2 driver reaches the screen through Android's accessibility framework. Window changes, content updates, text changes and scrolls all emit accessibility events, and the driver treats the device as idle when that stream falls silent. The wait is bounded by UiAutomator2's `waitForIdleTimeout` **setting**, whose default is 10000 ms: the driver waits up to ten seconds for silence and then proceeds anyway rather than failing the command. Two consequences follow directly: - Anything that emits accessibility events continuously never produces silence. A wine-cellar inventory app that animates a progress bar while it re-syncs the bottle list keeps the stream alive, so every interaction on that screen pays the whole bounded wait before it is dispatched. - The signal is broader than your app. Events raised by other windows on the device are noise on the same stream, so a chatty notification shade or a system dialog can be what is keeping the device "busy". Because it is a driver setting rather than a capability, it can travel at session start inside `appium:settings[waitForIdleTimeout]` and be changed later through the driver's settings API — mid-session, per screen, if a single screen is the problem. ## iOS: quiet means the app's main thread settled Appium's XCUITest driver asks a different question. WebDriverAgent waits for the application under test to become **quiescent** — for the app's own main thread to stop working — before it will act. That wait is bounded by `appium:waitForIdleTimeout`, which the XCUITest driver declares as a capability and also carries in its settings reference. Because the signal is the app's own run loop, what stalls it is different in kind: a spinner that never stops, an animation with an infinite repeat count, a timer redrawing a label every frame. None of those has to be anywhere near the element you are tapping; it only has to keep the app busy. On top of quiescence, the XCUITest driver exposes the `animationCoolOffTimeout` setting — an extra, purely time-based settle window spent *after* the app has reported itself idle, so that animations already in flight can finish before the interaction is dispatched. Android's driver has no equivalent second stage. ## The two mechanisms side by side | | Android — UiAutomator2 driver | iOS — XCUITest driver | |---|---|---| | What must go quiet | the accessibility event stream | the app's main thread | | Scope of the signal | device-wide | the app under test | | Where it is configured | `waitForIdleTimeout` driver setting | `appium:waitForIdleTimeout` capability, also a setting | | Default | 10000 ms | read the driver's own docs; do not assume Android's | | Second stage | none | the `animationCoolOffTimeout` settle window | | Making it stop blocking | set the setting to `0` | lower the bound so the driver gives up sooner | ## What this explains in a real suite 1. **The same suite is slow on one platform and jumpy on the other.** The two platforms are not tuned by the same number, so a value that is generous on one is reckless on the other. 2. **The knob name lies.** Reading `waitForIdleTimeout` out of a shared configuration file and assuming one meaning is the classic mistake on this tree: same word, two layers, two configuration surfaces. 3. **The cost is invisible in your test code.** Nothing in the test says "wait"; the seconds are spent inside the driver, before the command ever reaches the app. ## Reading it in practice - If a single Android tap consistently costs about ten seconds, suspect a screen whose accessibility events never stop long before you suspect the network. - If an iOS command is slow everywhere in the app rather than on one screen, suspect a global animation or timer that keeps the main thread busy. - Never copy a value from one platform's configuration into the other's expecting the same behaviour: the number bounds two different measurements of two different things.

  • Does Appium's idle check on Android or iOS fail the command when the app never goes quiet?
    No. On both platforms the idle wait is bounded, not fatal. UiAutomator2 waits up to its `waitForIdleTimeout` (10000 ms by default) and then dispatches the interaction anyway; the XCUITest driver bounds its quiescence wait with `appium:waitForIdleTimeout` and proceeds when that expires. The symptom of a never-quiet app is therefore slowness, not an error you can grep for.
  • Why can't one shared timeout value serve both platforms in an Appium suite?
    Because the value bounds different measurements. On Android it caps a wait on the device's accessibility event stream; on iOS it caps a wait on the app's main thread, and iOS has a second `animationCoolOffTimeout` stage Android lacks. A number that is a sane ceiling for one signal is arbitrary for the other, so the config should be per-platform.

Two doormen are told "wait until the room is quiet." One listens for whether anyone is still talking; the other checks whether the host is still busy. Same instruction, two different measurements, two different waits.

saying these in an interview costs you the question

  • Says Appium taps immediately and all waiting comes from the test's own explicit waits
  • Assumes waitForIdleTimeout means the same thing on Android and iOS
  • Thinks the iOS driver watches accessibility events the way the Android driver does
  • Believes the idle wait throws an error when the app never goes quiet
  • Treats the Android idle check as scoped to the app under test only
open as a page

In Appium on Android, what does setting UiAutomator2's waitForIdleTimeout to 0 do?

level: middleimportance: should knowfreq 37%

basics

~10 s

It disables the driver's idle wait completely. The UiAutomator2 driver stops waiting for the device's accessibility event stream to fall silent and dispatches each interaction immediately, even while the screen is still animating.

open as a page

In Appium on iOS, what does the XCUITest driver's animationCoolOffTimeout setting control?

level: middleimportance: should knowfreq 31%

basics

~20 s

It is a second settle window on iOS, spent after the app has already reported itself idle, so that animations still in flight can finish before the XCUITest driver dispatches the interaction. Android's driver has no equivalent.

open as a page

Your Appium wine-cellar suite crawls on iOS and taps mid-animation on Android — what do you tune?

level: seniorimportance: should knowfreq 44%

basics

~10 s

Treat them as two faults. On iOS, something keeps the app's main thread busy so every command pays the full appium:waitForIdleTimeout. On Android, the UiAutomator2 waitForIdleTimeout setting has almost certainly been lowered or zeroed.

open as a page