App¶
device.app(package_name): the app's lifecycle, its permissions and languages, and its
elements (only nodes of that package match). Guide: App lifecycle,
App or screen.
App
¶
One app on a device: its elements, its lifecycle and the waits on it. Obtain with
device.app(package_name), which performs no I/O.
element and wait add the package as one more selector predicate, so only this app's
nodes match (in any of its windows); device.screen matches anywhere. Lifecycle calls are
executed by the server over ADB and verified against a postcondition; failures are
AppLifecycleError.
Example::
app = device.app("com.example.shop")
app.cold_launch()
app.element(res("search")).set_text("socks")
app.wait(text("3 results")).visible()
Timeouts left as None use the device's client-side defaults (Timeouts) where the call
has one, else the server's default.
Methods:
| Name | Description |
|---|---|
element |
A lazy element: |
wait |
A wait on |
is_installed |
Whether the package is installed. |
install |
|
uninstall |
|
force_stop |
|
clear_data |
|
grant_permission |
|
is_permission_granted |
Whether |
set_locales |
The app's own languages (Android's per-app language, API 33+), as BCP-47 tags in |
locales |
The app's own languages now (canonical BCP-47 tags); empty when it follows the |
revoke_permission |
|
launch |
Starts the activity with |
await_visible |
Waits on the device until this package owns the focused window. Raises |
await_toast |
|
await_notification |
|
await_screen_stable |
Waits on the device until this package's focused window has stopped changing for |
await_settled |
Maestro's |
await_animation_end |
Maestro's |
foreground |
Bring the app to the front the way the launcher does: its launcher intent with |
background |
Send the app to the background with the Home key, as a user would; the process keeps |
open_link |
Open |
cold_launch |
Force-stops, launches (with |
process |
The single current process identity; waits briefly for it to exist. |
is_running |
Whether any process of the package is alive. |
await_idle |
Waits until the app's own sync contract reports idle for |
element
¶
A lazy element: selector restricted to this package's nodes. Nothing is looked
up until an action or query runs.
wait
¶
wait(selector: Selector, timeout: float | None = None) -> ElementWait
A wait on selector restricted to this package's nodes; timeout (seconds)
defaults to device.timeouts.wait.
install
¶
install(apk_path: str | PathLike[str], timeout: float | None = None) -> None
adb install -r -t of the APK at apk_path, verified. apk_path is a file on
this machine: its bytes are streamed to the server in 1 MiB chunks, so the server may
run elsewhere.
force_stop
¶
force_stop(timeout: float | None = None) -> None
am force-stop plus proof that no process and no activity of the package remain.
clear_data
¶
clear_data(timeout: float | None = None) -> None
pm clear: data, cache and runtime permissions are gone; the app is left stopped.
grant_permission
¶
grant_permission(permission: str) -> None
pm grant a runtime permission, e.g. android.permission.CAMERA.
is_permission_granted
¶
is_permission_granted(permission: str) -> bool
Whether permission is granted to the package now, as dumpsys package lists it:
the read-back for grant_permission, revoke_permission, clear_data and the
permission dialog.
set_locales
¶
set_locales(locales: Sequence[str]) -> None
The app's own languages (Android's per-app language, API 33+), as BCP-47 tags in
preference order ("fr-FR", "en"); an empty list makes it follow the system again.
The server checks and canonicalizes the tags (INVALID_ARGUMENT for a malformed one)
and reads the change back. Like the device conditions, the app's languages before the
session's first change come back on Device.detach(). Below API 33: ServerError
(reason UNSUPPORTED_API). Android applies it as a configuration change: the app's
activities are recreated unless it handles the change itself.
locales
¶
locales() -> list[str]
The app's own languages now (canonical BCP-47 tags); empty when it follows the system. API 33+.
revoke_permission
¶
revoke_permission(permission: str) -> None
pm revoke a runtime permission, proven by dumpsys package. Android kills the
app's process when one of its runtime permissions is revoked.
launch
¶
launch(activity: str | None = None, timeout: float | None = None, *, extras: Mapping[str, str | bool | int | float | Long] | None = None) -> None
Starts the activity with am start -W and returns when Android reports the launch
complete. Nothing about the UI is assumed: wait for what the test needs
(await_visible, await_screen_stable, an element wait).
extras are put on the intent (am start --es/--ez/--ei/--el/--ef): str,
bool, int (32-bit, getIntExtra), float (32-bit, getFloatExtra) or
tap_e2e.Long(n) for getLongExtra. Anything else raises before the call.
await_visible
¶
await_visible(timeout: float | None = None) -> None
Waits on the device until this package owns the focused window. Raises
WaitTimeoutError only when the device reports WAIT_TIMEOUT; any other failure
(driver unhealthy, transport lost, ...) is a CommandError.
await_toast
¶
await_toast(text: str | None = None, mode: MatchMode = EXACT, *, timeout: float | None = None) -> Toast
Device.await_toast for this package's toasts only: on Android 11+ a text toast is
drawn by SystemUI but still reported under the app that posted it.
await_notification
¶
await_notification(title: str | None = None, text: str | None = None, mode: MatchMode = EXACT, *, timeout: float | None = None) -> Notification
Device.await_notification for this package's notifications only.
await_screen_stable
¶
await_screen_stable(stable_for: float = 0.5, timeout: float | None = None, signal: StabilitySignal = ALL) -> None
Waits on the device until this package's focused window has stopped changing for
stable_for seconds according to signal: the accessibility tree
(StabilitySignal.TREE), the window pixels (StabilitySignal.PIXELS, 0.5 %
tolerance) or both (default). Call it explicitly after an action that starts an animation
or transition; nothing waits for this implicitly. A screen that keeps changing times out
with detail SCREEN_CHANGING. await_settled / await_animation_end are the
shorthands. Only a device WAIT_TIMEOUT becomes WaitTimeoutError; other failures
are CommandError.
await_settled
¶
await_settled(stable_for: float = 0.5, timeout: float | None = None) -> None
Maestro's waitForAppToSettle, on request only: this package's accessibility
hierarchy has not changed for stable_for seconds. Cheap (no screenshots); misses pure
drawing.
await_animation_end
¶
await_animation_end(stable_for: float = 0.5, timeout: float | None = None) -> None
Maestro's waitForAnimationToEnd, on request only: this package's window pixels
have not changed (beyond 0.5 %) for stable_for seconds. One screenshot per 100 ms.
foreground
¶
foreground(timeout: float | None = None) -> None
Bring the app to the front the way the launcher does: its launcher intent with
NEW_TASK | RESET_TASK_IF_NEEDED, so a running task resumes where it was instead of
gaining a second copy of the launcher activity, and a stopped app starts. Returns when
am start -W reports the launch complete; wait for the screen you need.
background
¶
background() -> None
Send the app to the background with the Home key, as a user would; the process keeps
running. Bring it back with foreground.
open_link
¶
open_link(uri: str, any_app: bool = False, timeout: float | None = None) -> str | None
Open uri (a deep link or app link, e.g. myapp://orders/42 or
https://example.com/x) with an ACTION_VIEW intent restricted to this package, so
no chooser or browser can take it; any_app=True lets Android resolve it like a tap on
a link elsewhere would. Returns the activity Android reported starting
(package/.Activity) when it reported one. Nothing about the screen is checked: wait
for what the link should show.
cold_launch
¶
cold_launch(activity: str | None = None, timeout: float | None = None, *, extras: Mapping[str, str | bool | int | float | Long] | None = None) -> AppProcess
Force-stops, launches (with extras, as launch) and returns the verified new
process identity.
process
¶
process(timeout: float | None = None) -> AppProcess
The single current process identity; waits briefly for it to exist.
await_idle
¶
await_idle(timeout: float | None = None, stable_for: float = 0.2) -> None
Waits until the app's own sync contract reports idle for stable_for seconds.
Experimental: synchronization is still being designed; this may change in any release.