@delacour/warden-e2e 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{chunk-yb1hcjqm.mjs → chunk-vs5npy59.mjs} +3370 -218
- package/index.mjs +247 -16
- package/package.json +2 -2
- package/preload.mjs +8264 -2387
- package/types/core/src/a11y/a11y.config.d.ts +47 -0
- package/types/core/src/affected/affected.schema.d.ts +142 -1
- package/types/core/src/allocate.d.ts +2 -1
- package/types/core/src/android-keyguard.d.ts +36 -0
- package/types/core/src/batch/preset.schema.d.ts +13 -1
- package/types/core/src/biometrics.d.ts +15 -0
- package/types/core/src/builds/app-option.schema.d.ts +1 -1
- package/types/core/src/builds/builds.defaults.d.ts +15 -0
- package/types/core/src/builds/config.d.ts +5 -1
- package/types/core/src/builds/config.schema.d.ts +275 -2
- package/types/core/src/builds/define-config.d.ts +159 -0
- package/types/core/src/builds/install-device.d.ts +37 -0
- package/types/core/src/builds/install.d.ts +17 -3
- package/types/core/src/builds/kinds.d.ts +21 -3
- package/types/core/src/builds/lock.d.ts +38 -0
- package/types/core/src/builds/resolve.d.ts +12 -2
- package/types/core/src/camera-mode.d.ts +17 -0
- package/types/core/src/camera-placeholder.d.ts +9 -0
- package/types/core/src/camera-profile.d.ts +12 -0
- package/types/core/src/claim-errors.d.ts +34 -0
- package/types/core/src/conditions/a11y-keys.d.ts +45 -0
- package/types/core/src/conditions/camera-media.d.ts +30 -0
- package/types/core/src/conditions/conditions.config.d.ts +141 -0
- package/types/core/src/conditions/conditions.d.ts +22 -0
- package/types/core/src/conditions/conditions.types.d.ts +171 -0
- package/types/core/src/conditions/inject-state.d.ts +13 -0
- package/types/core/src/conditions/launch-settings.d.ts +14 -0
- package/types/core/src/conditions/network.presets.d.ts +42 -0
- package/types/core/src/conditions/text-size.d.ts +19 -0
- package/types/core/src/golden/android-biometrics.d.ts +35 -0
- package/types/core/src/ios-runner/build.d.ts +28 -0
- package/types/core/src/ios-runner/cache.d.ts +44 -0
- package/types/core/src/ios-runner/classify.d.ts +7 -0
- package/types/core/src/ios-runner/pack.d.ts +17 -0
- package/types/core/src/ios-runner/runner-build.types.d.ts +76 -0
- package/types/core/src/ios-runner/signing.d.ts +40 -0
- package/types/core/src/ios-runner/sim-build.d.ts +36 -0
- package/types/core/src/ios-runner/stage.d.ts +26 -0
- package/types/core/src/lease-events.d.ts +126 -0
- package/types/core/src/netproxy/control.d.ts +75 -0
- package/types/core/src/netproxy/decide.d.ts +22 -0
- package/types/core/src/netproxy/handle-file.d.ts +12 -0
- package/types/core/src/netproxy/lease-proxy.d.ts +53 -0
- package/types/core/src/netproxy/netproxy.main.d.ts +40 -0
- package/types/core/src/netproxy/pipe.d.ts +37 -0
- package/types/core/src/netproxy/proxy.d.ts +48 -0
- package/types/core/src/netproxy/shaping.d.ts +43 -0
- package/types/core/src/ownership.d.ts +44 -0
- package/types/core/src/providers/android.d.ts +46 -2
- package/types/core/src/providers/provider.types.d.ts +9 -0
- package/types/core/src/queue.d.ts +43 -0
- package/types/core/src/store.d.ts +61 -5
- package/types/core/src/types.d.ts +57 -0
- package/types/core/src/xcode.d.ts +22 -0
- package/types/e2e/src/a11y/a11y-target.d.ts +23 -0
- package/types/e2e/src/a11y/a11y.types.d.ts +81 -0
- package/types/e2e/src/a11y/announcements.d.ts +24 -0
- package/types/e2e/src/a11y/audit.d.ts +22 -0
- package/types/e2e/src/a11y/native/atf.d.ts +51 -0
- package/types/e2e/src/a11y/native/xcuitest.d.ts +60 -0
- package/types/e2e/src/a11y/order.d.ts +5 -0
- package/types/e2e/src/a11y/rules/duplicate-name.d.ts +6 -0
- package/types/e2e/src/a11y/rules/hidden-focusable.d.ts +3 -0
- package/types/e2e/src/a11y/rules/image-no-name.d.ts +6 -0
- package/types/e2e/src/a11y/rules/label-in-name.d.ts +7 -0
- package/types/e2e/src/a11y/rules/missing-name.d.ts +3 -0
- package/types/e2e/src/a11y/rules/role-in-name.d.ts +3 -0
- package/types/e2e/src/a11y/rules/rule.context.d.ts +22 -0
- package/types/e2e/src/a11y/rules/target-size.d.ts +21 -0
- package/types/e2e/src/a11y/rules/text-clipped.d.ts +9 -0
- package/types/e2e/src/a11y/speech.d.ts +26 -0
- package/types/e2e/src/a11y/talkback-log.d.ts +13 -0
- package/types/e2e/src/alert-buttons.d.ts +9 -0
- package/types/e2e/src/app.d.ts +3 -2
- package/types/e2e/src/conditions/condition-events.d.ts +68 -0
- package/types/e2e/src/conditions/device-conditions.d.ts +198 -0
- package/types/e2e/src/conditions/geo.d.ts +15 -0
- package/types/e2e/src/conditions/gpx.d.ts +8 -0
- package/types/e2e/src/conditions/lease-recorder.d.ts +27 -0
- package/types/e2e/src/conditions/lease-store.d.ts +9 -0
- package/types/e2e/src/conditions/location-plan.d.ts +17 -0
- package/types/e2e/src/conditions/location-scenarios.data.d.ts +17 -0
- package/types/e2e/src/conditions/route-ticker.d.ts +53 -0
- package/types/e2e/src/conditions/scheduler.d.ts +83 -0
- package/types/e2e/src/device-a11y.d.ts +97 -0
- package/types/e2e/src/device.d.ts +67 -4
- package/types/e2e/src/driver/a11y-events.d.ts +30 -0
- package/types/e2e/src/driver/a11y-read.d.ts +12 -0
- package/types/e2e/src/driver/android/android-animations.d.ts +7 -0
- package/types/e2e/src/driver/android/android-app.d.ts +4 -0
- package/types/e2e/src/driver/android/android-argv.d.ts +21 -0
- package/types/e2e/src/driver/android/android-camera-host.d.ts +23 -0
- package/types/e2e/src/driver/android/android-camera.d.ts +28 -0
- package/types/e2e/src/driver/android/android-clock.d.ts +28 -0
- package/types/e2e/src/driver/android/android-device.d.ts +8 -0
- package/types/e2e/src/driver/android/android-driver.d.ts +22 -0
- package/types/e2e/src/driver/android/android-network.d.ts +66 -0
- package/types/e2e/src/driver/android/android-phone.d.ts +47 -0
- package/types/e2e/src/driver/android/android-screen-reader.d.ts +23 -0
- package/types/e2e/src/driver/android/android-settings.d.ts +41 -0
- package/types/e2e/src/driver/android/android-spoken.d.ts +18 -0
- package/types/e2e/src/driver/android/android-state.d.ts +10 -0
- package/types/e2e/src/driver/android/android-talkback.d.ts +57 -0
- package/types/e2e/src/driver/android/atf-device.d.ts +23 -0
- package/types/e2e/src/driver/android/atf-dex.generated.d.ts +7 -0
- package/types/e2e/src/driver/android/uiad-dex.generated.d.ts +5 -5
- package/types/e2e/src/driver/android/uiad-ops.d.ts +27 -1
- package/types/e2e/src/driver/android/uiad-protocol.d.ts +8 -0
- package/types/e2e/src/driver/android/uiad-screen-reader.d.ts +33 -0
- package/types/e2e/src/driver/clock-recorder.d.ts +9 -0
- package/types/e2e/src/driver/device-settings.d.ts +10 -0
- package/types/e2e/src/driver/driver.types.d.ts +242 -1
- package/types/e2e/src/driver/element-actions.d.ts +16 -0
- package/types/e2e/src/driver/ios/device/capabilities.d.ts +3 -0
- package/types/e2e/src/driver/ios/device/device-driver.d.ts +49 -0
- package/types/e2e/src/driver/ios/device/devicectl.d.ts +38 -0
- package/types/e2e/src/driver/ios/device/runner-protocol.d.ts +21 -0
- package/types/e2e/src/driver/ios/hid-recovery.d.ts +15 -0
- package/types/e2e/src/driver/ios/inject.d.ts +124 -0
- package/types/e2e/src/driver/ios/ios-a11y.d.ts +73 -0
- package/types/e2e/src/driver/ios/ios-audit.d.ts +36 -0
- package/types/e2e/src/driver/ios/ios-driver.d.ts +50 -1
- package/types/e2e/src/driver/ios/ios-network.d.ts +51 -0
- package/types/e2e/src/driver/ios/ios-settings.d.ts +44 -0
- package/types/e2e/src/driver/ios/sim-runner.d.ts +41 -0
- package/types/e2e/src/driver/ios/simctl.d.ts +41 -1
- package/types/e2e/src/driver/ios/simd-transport.d.ts +11 -2
- package/types/e2e/src/driver/ios/type-budget.d.ts +6 -1
- package/types/e2e/src/driver/native-audit.d.ts +26 -0
- package/types/e2e/src/driver/network-proxy.d.ts +52 -0
- package/types/e2e/src/driver/open.d.ts +20 -0
- package/types/e2e/src/driver/physical-conditions.d.ts +11 -0
- package/types/e2e/src/driver/requirements.d.ts +14 -0
- package/types/e2e/src/driver/screen-reader.d.ts +26 -0
- package/types/e2e/src/driver/typing.d.ts +1 -1
- package/types/e2e/src/env.d.ts +47 -0
- package/types/e2e/src/expect/a11y-matchers.d.ts +33 -0
- package/types/e2e/src/expect/expect.d.ts +7 -2
- package/types/e2e/src/expect/matchers.d.ts +14 -0
- package/types/e2e/src/fixture-session.d.ts +4 -0
- package/types/e2e/src/fixtures.d.ts +6 -1
- package/types/e2e/src/index.d.ts +6 -0
- package/types/e2e/src/runner/callsite.d.ts +3 -1
- package/types/e2e/src/runner/scope.d.ts +1 -0
- package/types/e2e/src/runner/test.d.ts +6 -0
- package/types/e2e/src/screen/render.d.ts +8 -0
- package/types/e2e/src/traced-device.d.ts +2 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Result } from "../../../types/src/result";
|
|
2
|
+
import type { A11yEvent, A11yEventSource } from "../a11y/a11y.types";
|
|
3
|
+
import type { Driver, DriverResult } from "./driver.types";
|
|
4
|
+
/**
|
|
5
|
+
* Optional capability next to the frozen `Driver` interface (pattern: `ReadsA11y`): the announcements, live-region
|
|
6
|
+
* changes and screen/layout notifications an app emitted since `since`. `cursor` is opaque to callers: pass the last
|
|
7
|
+
* one back to get only what is new (Android: the server's sequence number; iOS: a byte offset into the inject events
|
|
8
|
+
* file). `since` omitted reads from the start. `lost` is set when the Android ring overwrote events the caller never saw.
|
|
9
|
+
* iOS needs the app launched with the injected library (`WARDEN_A11Y=1` / the `a11y` option) and answers
|
|
10
|
+
* `E_UNSUPPORTED` otherwise.
|
|
11
|
+
*/
|
|
12
|
+
export type A11yEventsRead = {
|
|
13
|
+
events: A11yEvent[];
|
|
14
|
+
cursor: number;
|
|
15
|
+
lost?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type ReadsA11yEvents = {
|
|
18
|
+
a11yEvents(since?: number): DriverResult<A11yEventsRead>;
|
|
19
|
+
};
|
|
20
|
+
export declare function canReadA11yEvents(driver: Driver): driver is Driver & ReadsA11yEvents;
|
|
21
|
+
export declare function parseA11yEvent(value: unknown, source: A11yEventSource): A11yEvent | undefined;
|
|
22
|
+
/** The `a11yEvents` reply of `warden-uiad`: `{events:[{kind,text,at}], cursor, lost?}`. */
|
|
23
|
+
export declare function parseUiadA11yEvents(data: unknown): Result<A11yEventsRead, string>;
|
|
24
|
+
/**
|
|
25
|
+
* The injected library's `<state>.events` file (JSON lines, append-only) from byte offset `since`. Only lines that end
|
|
26
|
+
* in a newline count: a half-written tail stays unread and the returned cursor stops before it, so the next read
|
|
27
|
+
* starts there. A malformed complete line is skipped (the cursor moves past it). A `since` beyond the file (the file
|
|
28
|
+
* was reset by a relaunch) restarts from 0.
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseInjectEvents(text: string, since?: number): A11yEventsRead;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Driver, DriverResult, Snapshot } from "./driver.types";
|
|
2
|
+
/**
|
|
3
|
+
* Optional capability next to the frozen `Driver` interface (pattern: `RepeatingKeys` in `typing.ts`): read the
|
|
4
|
+
* screen-reader facts a plain snapshot lacks and return the snapshot with `Element.a11y` filled in. iOS: the injected
|
|
5
|
+
* dylib's UIKit walk merged by identifier / frame (`ios/ios-a11y.ts`); needs the app launched with the dylib
|
|
6
|
+
* (`WARDEN_A11Y=1` or the `a11y` driver option) and answers `E_UNSUPPORTED` otherwise. Android has no such driver
|
|
7
|
+
* method: `warden-uiad` snapshots carry `a11y` already.
|
|
8
|
+
*/
|
|
9
|
+
export type ReadsA11y = {
|
|
10
|
+
readA11y(snapshot: Snapshot): DriverResult<Snapshot>;
|
|
11
|
+
};
|
|
12
|
+
export declare function canReadA11y(driver: Driver): driver is Driver & ReadsA11y;
|
|
@@ -12,6 +12,8 @@ import { type AndroidStateStore } from "./android-state";
|
|
|
12
12
|
export type AnimationGuard = {
|
|
13
13
|
/** put the scales back (once); a restore that fails leaves the saved originals for the next driver */
|
|
14
14
|
restore(): Promise<void>;
|
|
15
|
+
/** the transition scale the device had before it was zeroed (`"null"` = never set); undefined when it was off already */
|
|
16
|
+
transitionOriginal(): string | undefined;
|
|
15
17
|
};
|
|
16
18
|
export type AnimationDeps = {
|
|
17
19
|
session: AdbSession;
|
|
@@ -25,5 +27,10 @@ export type AnimationDeps = {
|
|
|
25
27
|
/**
|
|
26
28
|
* One shell round trip that reads the three scales and sets them to 0, then (when something has to be put
|
|
27
29
|
* back) saves the originals. Never fails the open: a device that refuses just keeps its animations.
|
|
30
|
+
*
|
|
31
|
+
* The transition scale is the exception: RN (0.86) reads it as "reduce motion", and zero would make every app
|
|
32
|
+
* under test report reduce-motion on. It goes straight back to the device's own value, so only the window and
|
|
33
|
+
* animator scales stay at 0 (those are what makes the run fast and stable); `a11y({ reduceMotion: true })` zeroes it
|
|
34
|
+
* on request.
|
|
28
35
|
*/
|
|
29
36
|
export declare function disableAnimations(deps: AnimationDeps): Promise<AnimationGuard>;
|
|
@@ -9,6 +9,10 @@ export type AppDeps = {
|
|
|
9
9
|
log?: Logger;
|
|
10
10
|
/** the app under test: `openUrl` is addressed to it (`am start -p`) so no other handler or chooser can take the link */
|
|
11
11
|
appPackage?: string;
|
|
12
|
+
/** a real phone: `uninstall` and `clearData` only touch `appPackage` and `ownedPackages` (`E_REFUSED` otherwise) */
|
|
13
|
+
physical?: boolean;
|
|
14
|
+
/** packages warden installed on this device besides `appPackage` */
|
|
15
|
+
ownedPackages?: readonly string[];
|
|
12
16
|
/** how long `am start -W` may wait for the first frame (default `START_WAIT_TIMEOUT_MS`); tests shorten it */
|
|
13
17
|
startWaitTimeoutMs?: number;
|
|
14
18
|
/** how long the `pidof` after a timed-out start may take (default `START_PROBE_TIMEOUT_MS`); tests shorten it */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LatLon } from "../../../../core/src/conditions/conditions.types";
|
|
1
2
|
import type { Result } from "../../../../types/src/result";
|
|
2
3
|
import type { DriverError, HardwareButton, KeyName, Point } from "../driver.types";
|
|
3
4
|
import type { GesturePlan } from "../gesture-geometry";
|
|
@@ -14,6 +15,13 @@ export type MotionAction = "DOWN" | "MOVE" | "UP" | "CANCEL";
|
|
|
14
15
|
export declare function motionEventArgv(action: MotionAction, point: Point): string[];
|
|
15
16
|
/** Lowest sdk with `input motionevent` (Android 8.0). */
|
|
16
17
|
export declare const MOTIONEVENT_MIN_SDK = 26;
|
|
18
|
+
/** Host-side `adb -s <serial> emu finger touch <id>`: the emulator console presents fingerprint `id` to the sensor. */
|
|
19
|
+
export declare function emuFingerTouchArgv(adb: string, serial: string, fingerId: number): string[];
|
|
20
|
+
/** An id no enrollment holds: the emulator reports a non-matching touch. */
|
|
21
|
+
export declare const UNENROLLED_FINGER_ID = 99;
|
|
22
|
+
export declare function dumpsysFingerprintArgv(): string[];
|
|
23
|
+
/** Emulator serials (`emulator-5554`); the console commands exist nowhere else. */
|
|
24
|
+
export declare const isEmulatorSerial: (serial: string) => boolean;
|
|
17
25
|
/** `input keycombination` (and so select-all by Ctrl+A) exists from Android 13. */
|
|
18
26
|
export declare const SELECT_ALL_MIN_SDK = 33;
|
|
19
27
|
export declare const DRAG_STEPS = 8;
|
|
@@ -85,6 +93,8 @@ export declare function animationScaleArgvs(): string[][];
|
|
|
85
93
|
export declare function animationReadArgvs(): string[][];
|
|
86
94
|
/** Put saved scales back: a value is `put` again, a setting that was never set (`null`) is deleted. */
|
|
87
95
|
export declare function animationRestoreArgvs(values: AnimationValues): string[][];
|
|
96
|
+
/** Put just the transition scale back (a setting that was never set, `null`, is deleted). */
|
|
97
|
+
export declare function transitionRestoreArgv(value: string): string[];
|
|
88
98
|
/** Host argv: `adb -s <serial> exec-out screencap -p` (binary PNG on stdout). */
|
|
89
99
|
export declare function screencapArgv(adb: string, serial: string): string[];
|
|
90
100
|
/** `getprop <key>` (boot flag, sdk level, model). */
|
|
@@ -104,6 +114,17 @@ export declare function dumpTtyHostArgv(adb: string, serial: string): string[];
|
|
|
104
114
|
export declare function dumpFileCommand(path?: string): string;
|
|
105
115
|
/** Host argv: `adb -s <serial> install -r <apk>`. */
|
|
106
116
|
export declare function installArgv(adb: string, serial: string, apkPath: string): string[];
|
|
117
|
+
/**
|
|
118
|
+
* Host argv: `adb -s <serial> emu geo fix <lon> <lat> [alt]`. The emulator console takes LONGITUDE first,
|
|
119
|
+
* the reverse of `simctl location set lat,lon` and of everything else here.
|
|
120
|
+
*/
|
|
121
|
+
export declare function geoFixArgv(adb: string, serial: string, point: LatLon, altM?: number): string[];
|
|
122
|
+
/** `adb emu` exits 0 even when the console answers `KO: …`; the reason, or undefined when it took. */
|
|
123
|
+
export declare function geoFixFailure(res: {
|
|
124
|
+
exitCode: number;
|
|
125
|
+
stdout: string;
|
|
126
|
+
stderr: string;
|
|
127
|
+
}): string | undefined;
|
|
107
128
|
export declare function uninstallArgv(adb: string, serial: string, packageName: string): string[];
|
|
108
129
|
/** Exit 0 and `package:/…` when installed, exit 1 and nothing otherwise. */
|
|
109
130
|
export declare function pmPathArgv(packageName: string): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Exec } from "../../../../core/src/exec";
|
|
2
|
+
import type { DeviceProvider } from "../../../../core/src/providers/provider.types";
|
|
3
|
+
import type { Store } from "../../../../core/src/store";
|
|
4
|
+
import { type Result } from "../../../../types/src/result";
|
|
5
|
+
import type { AndroidCameraDeps } from "./android-camera";
|
|
6
|
+
export type AndroidCameraHostOptions = {
|
|
7
|
+
serial: string;
|
|
8
|
+
env?: Record<string, string | undefined>;
|
|
9
|
+
exec?: Exec;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
/** the lease store (default: the process's shared connection) */
|
|
12
|
+
store?: () => Result<Store>;
|
|
13
|
+
/** the Android provider (default: a real one on `adb` / `emulator`) */
|
|
14
|
+
provider?: (store: Store) => DeviceProvider;
|
|
15
|
+
};
|
|
16
|
+
/** What `createAndroidCamera` needs from warden's state: the device's recorded profile, a restart, the lease record. */
|
|
17
|
+
export type AndroidCameraHost = Pick<AndroidCameraDeps, "profile" | "relaunch"> & Required<Pick<AndroidCameraDeps, "record">>;
|
|
18
|
+
/**
|
|
19
|
+
* The camera driver's view of warden's store and provider, opened lazily: a run that never touches the camera never
|
|
20
|
+
* opens either. The profile (`<avd>+cam`) is what the claim recorded for the serial; a restart goes through the same
|
|
21
|
+
* provider that launched the emulator, so the serial, console port, device record and lease stay.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createAndroidCameraHost(options: AndroidCameraHostOptions): AndroidCameraHost;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type CameraCondition } from "../../../../core/src/conditions/conditions.types";
|
|
2
|
+
import type { Exec } from "../../../../core/src/exec";
|
|
3
|
+
import type { Driver } from "../driver.types";
|
|
4
|
+
export type AndroidCameraDeps = {
|
|
5
|
+
serial: string;
|
|
6
|
+
wardenHome: string;
|
|
7
|
+
/** host process runner: `sips` re-encodes images to PNG */
|
|
8
|
+
exec: Exec;
|
|
9
|
+
/** the profile warden recorded for this device (`pixel-10+cam`); undefined = not a warden device */
|
|
10
|
+
profile: () => string | undefined;
|
|
11
|
+
/** restart the emulator on its own serial through the provider and wait until it is ready */
|
|
12
|
+
relaunch: () => Promise<{
|
|
13
|
+
success: true;
|
|
14
|
+
data: undefined;
|
|
15
|
+
} | {
|
|
16
|
+
success: false;
|
|
17
|
+
error: string;
|
|
18
|
+
}>;
|
|
19
|
+
/** told the feeds now playing, so the lease carries the `camera` area and release undoes it */
|
|
20
|
+
record?: (feeds: CameraCondition) => void;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The Android emulator camera. `-camera-back` / `-camera-front` name a file the emulator re-reads whenever an app
|
|
24
|
+
* opens the camera, so an image swap is an atomic file replace (`appliesOnCameraOpen`). Only PNG renders, so every
|
|
25
|
+
* other image is re-encoded with `sips`. The source TYPE (image or video) is fixed at launch: a change of it is
|
|
26
|
+
* recorded in `mode.json` and the emulator is restarted on the same serial (`rebooted`).
|
|
27
|
+
*/
|
|
28
|
+
export declare function createAndroidCamera(deps: AndroidCameraDeps): Driver["camera"];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ClockCondition } from "../../../../core/src/conditions/conditions.types";
|
|
2
|
+
import type { Exec } from "../../../../core/src/exec";
|
|
3
|
+
import type { ClockState, DriverResult } from "../driver.types";
|
|
4
|
+
import type { AdbSession } from "./adb-session";
|
|
5
|
+
/**
|
|
6
|
+
* Android mock clock: system time, device-wide. `settings put global auto_time 0` stops the network time sync from
|
|
7
|
+
* undoing it, `cmd alarm set-time <epoch ms>` sets it (a shell-uid command on emulator images, verified on the
|
|
8
|
+
* device's own `date`); where that does not take, `adb root` + `date -s @<secs>`. `real` is the undo in
|
|
9
|
+
* `core/conditions/undo.ts`: `auto_time 1` then the host's time. There is no way to freeze Android's clock, so
|
|
10
|
+
* `frozen` is `E_UNSUPPORTED`. Monotonic clocks are not affected by a wall-clock set.
|
|
11
|
+
*/
|
|
12
|
+
export declare const AUTO_TIME_OFF_ARGV: readonly string[];
|
|
13
|
+
export declare const AUTO_TIME_ON_ARGV: readonly string[];
|
|
14
|
+
export declare const DATE_ARGV: readonly string[];
|
|
15
|
+
export declare const setTimeArgv: (epochMs: number) => string[];
|
|
16
|
+
/** How far the device's `date` may be from the target (it only reports whole seconds, and a call takes time). */
|
|
17
|
+
export declare const CLOCK_TOLERANCE_MS = 5000;
|
|
18
|
+
export type AndroidClockDeps = {
|
|
19
|
+
session: AdbSession;
|
|
20
|
+
/** host runner for the `adb root` fallback */
|
|
21
|
+
exec: Exec;
|
|
22
|
+
adb: string;
|
|
23
|
+
serial: string;
|
|
24
|
+
/** host wall time, ms (default `Date.now`) */
|
|
25
|
+
wallNow?: () => number;
|
|
26
|
+
};
|
|
27
|
+
/** Put the emulator's wall clock at `condition`; reads it back and fails with `E_IO` when it did not move. */
|
|
28
|
+
export declare function applyAndroidClock(deps: AndroidClockDeps, condition: ClockCondition): DriverResult<ClockState>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DriverResult, Logger, Orientation, ScreenInfo } from "../driver.types";
|
|
2
2
|
import type { AdbSession } from "./adb-session";
|
|
3
3
|
import { type RotationValue } from "./android-argv";
|
|
4
|
+
import { type PhoneFacts } from "./android-phone";
|
|
4
5
|
/** Device facts read once at open: boot flag, screen size/density. Pure parsers + small session helpers. */
|
|
5
6
|
export declare const BOOT_TIMEOUT_MS = 30000;
|
|
6
7
|
export type Clock = {
|
|
@@ -15,11 +16,18 @@ export declare function parseWmSize(text: string): {
|
|
|
15
16
|
} | undefined;
|
|
16
17
|
/** `wm density`: `Physical density: 420` / `Override density: 320`; scale = dpi / 160. */
|
|
17
18
|
export declare function parseWmDensity(text: string): number | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* The probe for `serial`. A console `emulator-N` is an emulator by construction. Anything else (a phone, or a
|
|
21
|
+
* network emulator) also reads the qemu props, wakefulness and keyguard, in the same round trip.
|
|
22
|
+
*/
|
|
23
|
+
export declare function bootProbeFor(serial: string): string;
|
|
18
24
|
/** The sdk level on the probe's second line, if numeric. */
|
|
19
25
|
export declare function sdkFromProbe(stdout: string): number | undefined;
|
|
26
|
+
/** `physical`: set only for a real phone (its qemu props are empty); an emulator, or an unprobed serial, has none. */
|
|
20
27
|
export type BootInfo = {
|
|
21
28
|
screen: ScreenInfo | undefined;
|
|
22
29
|
sdk: number | undefined;
|
|
30
|
+
physical: PhoneFacts | undefined;
|
|
23
31
|
};
|
|
24
32
|
/** The screen out of a boot probe's output, if `wm` answered. */
|
|
25
33
|
export declare function screenFromProbe(stdout: string): ScreenInfo | undefined;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { Exec } from "../../../../core/src/exec";
|
|
2
|
+
import type { ConditionSink } from "../../conditions/condition-events";
|
|
3
|
+
import { type TickerClock } from "../../conditions/route-ticker";
|
|
4
|
+
import type { ClockRecorder } from "../clock-recorder";
|
|
2
5
|
import type { Driver, DriverResult, Element, Logger, Point, ScreenInfo } from "../driver.types";
|
|
6
|
+
import type { NetworkProxyPort } from "../network-proxy";
|
|
3
7
|
import { type SpawnAdb } from "./adb-session";
|
|
8
|
+
import { type AndroidCameraHost } from "./android-camera-host";
|
|
4
9
|
import { type Clock } from "./android-device";
|
|
5
10
|
import { type DumpRoute } from "./android-dump";
|
|
6
11
|
import { type AndroidStateStore } from "./android-state";
|
|
@@ -23,6 +28,10 @@ export type AndroidDriverOptions = {
|
|
|
23
28
|
/** override how the resident shell is spawned (tests) */
|
|
24
29
|
spawn?: SpawnAdb;
|
|
25
30
|
log?: Logger;
|
|
31
|
+
/** the lease's shaping proxy: loss and per-host faults route through it (`createAndroidNetwork`); without it loss stays in `needsProxy` */
|
|
32
|
+
networkProxy?: NetworkProxyPort;
|
|
33
|
+
/** told about every successful `clock` op, so the lease records the `clock` area (`leaseClockRecorder`) */
|
|
34
|
+
clockRecorder?: ClockRecorder;
|
|
26
35
|
/** skip `wm size`/`wm density` */
|
|
27
36
|
screen?: ScreenInfo;
|
|
28
37
|
/** binary runner for screenshots, default {@link bunExecBinary} */
|
|
@@ -40,6 +49,11 @@ export type AndroidDriverOptions = {
|
|
|
40
49
|
state?: AndroidStateStore;
|
|
41
50
|
/** the app under test: `app.openUrl` is addressed to it (`am start -p`), so no other app or chooser takes the link */
|
|
42
51
|
appPackage?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Packages besides `appPackage` that warden installed on this device (the `installs` table). On a physical phone
|
|
54
|
+
* only these may be uninstalled or have their data cleared; anything else is `E_REFUSED` (`physical_protected`).
|
|
55
|
+
*/
|
|
56
|
+
ownedPackages?: readonly string[];
|
|
43
57
|
/** how long to wait for `sys.boot_completed`, default 30 s */
|
|
44
58
|
bootTimeoutMs?: number;
|
|
45
59
|
/**
|
|
@@ -48,6 +62,14 @@ export type AndroidDriverOptions = {
|
|
|
48
62
|
* (a fake spawn, a fake dex push) a test replaces. API 26 and up only.
|
|
49
63
|
*/
|
|
50
64
|
uiad?: boolean | UiadOptions;
|
|
65
|
+
/** pacing of in-process location routes (default real time); tests pass a fake */
|
|
66
|
+
tickerClock?: TickerClock;
|
|
67
|
+
/** told about every network flap transition (the `condition` events of `results.jsonl`) */
|
|
68
|
+
conditionSink?: ConditionSink;
|
|
69
|
+
/** warden's home, where a camera emulator's feeds live (default `$WARDEN_HOME`, else `~/.warden`) */
|
|
70
|
+
wardenHome?: string;
|
|
71
|
+
/** the camera op's view of warden's store and provider (default: the real ones, opened on first use) */
|
|
72
|
+
cameraHost?: AndroidCameraHost;
|
|
51
73
|
};
|
|
52
74
|
/** Deepest hittable element containing `point` (later in preorder wins ties: drawn on top); else deepest any. */
|
|
53
75
|
export declare function elementAt(flat: readonly Element[], point: Point): Element | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { NetworkCondition } from "../../../../core/src/conditions/conditions.types";
|
|
2
|
+
import type { Exec } from "../../../../core/src/exec";
|
|
3
|
+
import type { Driver, DriverResult, NetworkState } from "../driver.types";
|
|
4
|
+
import { type NetworkProxyPort } from "../network-proxy";
|
|
5
|
+
import type { AdbSession } from "./adb-session";
|
|
6
|
+
import type { Clock } from "./android-device";
|
|
7
|
+
/**
|
|
8
|
+
* Android native network conditions. Speed and delay go to the emulator console (`adb emu network ...`, host
|
|
9
|
+
* side); online/offline is airplane mode (`cmd connectivity`, falling back to `svc wifi|data`). Every switch is
|
|
10
|
+
* verified against what `dumpsys connectivity` reports, polled on the injected clock, before it returns.
|
|
11
|
+
* Loss, per-host faults and flapping are not native: loss is reported in `needsProxy` (COND-4), the rest never
|
|
12
|
+
* reach this driver.
|
|
13
|
+
*/
|
|
14
|
+
/** Longest wait for the OS to agree with one switch. */
|
|
15
|
+
export declare const NETWORK_VERIFY_MS = 10000;
|
|
16
|
+
export declare const DUMPSYS_CONNECTIVITY_ARGV: readonly string[];
|
|
17
|
+
/** Host argv: `adb -s <serial> emu network speed|delay <value>`. */
|
|
18
|
+
export declare function emuNetworkArgv(adb: string, serial: string, what: "speed" | "delay", value: string): string[];
|
|
19
|
+
/** Device shell argv. */
|
|
20
|
+
export declare function airplaneArgv(enable: boolean): string[];
|
|
21
|
+
/** Device shell argvs: the radios by hand, for images whose `cmd connectivity` has no airplane-mode. */
|
|
22
|
+
export declare function svcArgvs(enable: boolean): string[][];
|
|
23
|
+
/** The emulator console answers `KO: ...` with exit code 0 on a bad argument. */
|
|
24
|
+
export declare function emuReplyError(stdout: string): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* The default network out of `dumpsys connectivity`: its header line is `Active default network: 101` while a
|
|
27
|
+
* network is up and `Active default network: none` when airplane mode or disabled radios took it away. Anything
|
|
28
|
+
* else (a service that is not there, truncated output) is unreadable.
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseActiveNetwork(dump: string): {
|
|
31
|
+
online: boolean;
|
|
32
|
+
netId?: number;
|
|
33
|
+
} | undefined;
|
|
34
|
+
export type AndroidNetworkDeps = {
|
|
35
|
+
session: AdbSession;
|
|
36
|
+
/** host runner for `adb emu` */
|
|
37
|
+
exec: Exec;
|
|
38
|
+
adb: string;
|
|
39
|
+
serial: string;
|
|
40
|
+
clock: Clock;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Put the emulator's network into `condition`. Offline: airplane mode (radios off by `svc` where the image has no
|
|
44
|
+
* airplane command). Anything else: back online first, then the preset's / custom speed and delay on the console.
|
|
45
|
+
* Physical devices have no console. `flap` is the scheduler's: the driver wraps this.
|
|
46
|
+
*/
|
|
47
|
+
export declare function applyAndroidNetwork(deps: AndroidNetworkDeps, condition: NetworkCondition): DriverResult<NetworkState>;
|
|
48
|
+
/** The emulator's alias for the host's loopback: a proxy bound to 127.0.0.1 on the host answers here. */
|
|
49
|
+
export declare const EMULATOR_HOST_ALIAS = "10.0.2.2";
|
|
50
|
+
/** Device shell argv: point the system HTTP(S) proxy at `value` (`host:port`, or `:0` to clear). */
|
|
51
|
+
export declare function httpProxyPutArgv(value: string): string[];
|
|
52
|
+
export declare const HTTP_PROXY_GET_ARGV: readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* Android network conditions, native first: speed, delay and offline stay on the emulator (`applyAndroidNetwork`).
|
|
55
|
+
* What the console cannot do, packet loss and per-host faults, goes through the lease's shaping proxy: the system
|
|
56
|
+
* `http_proxy` setting points at it (`10.0.2.2:<port>`) and the proxy applies only `lossPct` and the faults, so the
|
|
57
|
+
* native delay and bandwidth are not applied twice. Apps that honour the system proxy (OkHttp, HttpURLConnection,
|
|
58
|
+
* Chromium WebView, therefore React Native fetch) are covered; raw sockets and apps that set `Proxy.NO_PROXY` are not.
|
|
59
|
+
* Without a proxy port a loss stays in `needsProxy`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createAndroidNetwork(deps: AndroidNetworkDeps & {
|
|
62
|
+
proxy?: NetworkProxyPort;
|
|
63
|
+
}): {
|
|
64
|
+
network: Driver["network"];
|
|
65
|
+
networkFaults: Driver["networkFaults"];
|
|
66
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { DriverResult, Logger } from "../driver.types";
|
|
2
|
+
import type { AdbSession } from "./adb-session";
|
|
3
|
+
import type { Clock } from "./android-device";
|
|
4
|
+
import { type AndroidDeviceState, type AndroidStateStore } from "./android-state";
|
|
5
|
+
/** `ro.boot.qemu` / `ro.kernel.qemu` joined (empty on hardware), the power state and the keyguard, as the tail of the boot probe. */
|
|
6
|
+
export declare const PHONE_PROBE_TAIL: string;
|
|
7
|
+
/** `dumpsys window policy`'s keyguard lines: `showing=true`, `secure=true`. */
|
|
8
|
+
export declare const KEYGUARD_COMMAND = "dumpsys window policy | grep -E 'showing=|secure='";
|
|
9
|
+
/** What the phone-probe tail found out; every field is `undefined` when `dumpsys` printed nothing parseable. */
|
|
10
|
+
export type PhoneFacts = {
|
|
11
|
+
awake?: boolean;
|
|
12
|
+
keyguardShowing?: boolean;
|
|
13
|
+
keyguardSecure?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The phone facts in a boot probe's output, or `undefined` when the probe had no phone tail (a console emulator)
|
|
17
|
+
* or the qemu props say this is an emulator (`localhost:5555`, Genymotion): not a phone.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parsePhoneFacts(stdout: string): PhoneFacts | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Make an attached phone usable, never unlock it: a sleeping one gets `KEYCODE_WAKEUP`; a keyguard without a
|
|
22
|
+
* credential is dismissed (`wm dismiss-keyguard`); a secure keyguard is `E_DEVICE_LOCKED` (no swipe, no PIN).
|
|
23
|
+
*/
|
|
24
|
+
export declare function preparePhone(session: AdbSession, clock: Pick<Clock, "sleep">, facts: PhoneFacts, log?: Logger): DriverResult<void>;
|
|
25
|
+
export type SettingsGuard = {
|
|
26
|
+
/** before the first rotation write: save the current rotation settings (once); an error means do not write */
|
|
27
|
+
beforeRotate(): DriverResult<void>;
|
|
28
|
+
/** before the first `cmd uimode night` write: save the current mode (once) */
|
|
29
|
+
beforeAppearance(): DriverResult<void>;
|
|
30
|
+
/** put everything saved back (once); a failed restore leaves the originals in the state file for the next driver */
|
|
31
|
+
restore(): Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
export type SettingsGuardDeps = {
|
|
34
|
+
session: AdbSession;
|
|
35
|
+
serial: string;
|
|
36
|
+
sdk: number | undefined;
|
|
37
|
+
/** originals a process that died left in the state file */
|
|
38
|
+
pending: Pick<AndroidDeviceState, "rotation" | "uimode">;
|
|
39
|
+
state?: AndroidStateStore;
|
|
40
|
+
log?: Logger;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Rotation (`accelerometer_rotation`, `user_rotation`) and dark mode (`cmd uimode night`) are settings that
|
|
44
|
+
* outlive the driver. On a phone the originals are read and written to the state file BEFORE the first change
|
|
45
|
+
* (so a crash cannot lose them) and restored when the driver closes, the way animation scales are.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createSettingsGuard(deps: SettingsGuardDeps): Promise<SettingsGuard>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Driver } from "../driver.types";
|
|
2
|
+
import type { ActsOnElements } from "../element-actions";
|
|
3
|
+
import type { DrivesScreenReader } from "../screen-reader";
|
|
4
|
+
import type { AdbSession } from "./adb-session";
|
|
5
|
+
import type { Clock } from "./android-device";
|
|
6
|
+
import type { TalkBackControl } from "./android-talkback";
|
|
7
|
+
import type { UiadOps } from "./uiad-ops";
|
|
8
|
+
/**
|
|
9
|
+
* The Android driver while TalkBack is on (WDN-A11Y, A11Y-7): the `DrivesScreenReader` calls, and the element actions
|
|
10
|
+
* that replace touches. With TalkBack on a tap only moves its focus and a one-finger swipe navigates, so a locator tap
|
|
11
|
+
* is `ACTION_CLICK` on the node and a locator scroll is `ACTION_SCROLL_*` on its scrollable (server ops, no touch).
|
|
12
|
+
* Raw coordinate taps never come through here and stay touches: with TalkBack on they move its focus, and whether that
|
|
13
|
+
* also activates depends on its "single-tap to activate" setting.
|
|
14
|
+
*/
|
|
15
|
+
export type ScreenReaderDeps = {
|
|
16
|
+
uiad: UiadOps | undefined;
|
|
17
|
+
talkback: TalkBackControl;
|
|
18
|
+
session: AdbSession;
|
|
19
|
+
clock: Clock;
|
|
20
|
+
/** a touch, for the focus-then-double-tap fallback */
|
|
21
|
+
tap: Driver["tap"];
|
|
22
|
+
};
|
|
23
|
+
export declare function createScreenReaderOps(deps: ScreenReaderDeps): DrivesScreenReader & ActsOnElements;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PermissionName, PermissionState } from "../../../../core/src/conditions/conditions.types";
|
|
2
|
+
import type { Driver } from "../driver.types";
|
|
3
|
+
import type { AdbSession } from "./adb-session";
|
|
4
|
+
import { type TalkBackControl } from "./android-talkback";
|
|
5
|
+
/** Permission name to the manifest permissions it covers; a name absent here is skipped with the reason in `ANDROID_NO_PERMISSION`. */
|
|
6
|
+
export declare const ANDROID_PERMISSIONS: Partial<Record<PermissionName, readonly string[]>>;
|
|
7
|
+
export declare const ANDROID_NO_PERMISSION: Partial<Record<PermissionName, string>>;
|
|
8
|
+
export declare const permissionArgv: (state: PermissionState, pkg: string, permission: string) => string[];
|
|
9
|
+
/** `unset` also clears the flags a user choice sets, so the app is asked again. */
|
|
10
|
+
export declare const clearPermissionFlagsArgv: (pkg: string, permission: string) => string[];
|
|
11
|
+
export declare const setTimezoneArgv: (tz: string) => string[];
|
|
12
|
+
export declare const TIMEZONE_PROP_ARGV: readonly string[];
|
|
13
|
+
export declare const setAppLocaleArgv: (pkg: string, tag: string | null) => string[];
|
|
14
|
+
export declare const getAppLocaleArgv: (pkg: string) => string[];
|
|
15
|
+
export declare const settingGetArgv: (table: "system" | "secure" | "global", key: string) => string[];
|
|
16
|
+
export declare const BOLD_TEXT_ADJUSTMENT = 300;
|
|
17
|
+
export declare const trimMemoryArgv: (pkg: string) => string[];
|
|
18
|
+
export declare const BATTERY_RESET_ARGV: readonly string[];
|
|
19
|
+
export declare function batteryArgvs(op: {
|
|
20
|
+
level?: number;
|
|
21
|
+
charging?: boolean;
|
|
22
|
+
}): string[][];
|
|
23
|
+
export declare const APP_LOCALES_MIN_SDK = 33;
|
|
24
|
+
export type AndroidSettingsDeps = {
|
|
25
|
+
session: AdbSession;
|
|
26
|
+
serial: string;
|
|
27
|
+
/** the session's app package, used when an op names none */
|
|
28
|
+
appPackage?: string;
|
|
29
|
+
/** wait between a settings write and its read-back (default `Bun.sleep`) */
|
|
30
|
+
sleep?: (ms: number) => Promise<void>;
|
|
31
|
+
/** the host's timezone, restored on `timezone(null)` when no previous one is given (default: `Intl`) */
|
|
32
|
+
hostTimezone?: () => string;
|
|
33
|
+
/** the transition animation scale the device had before the driver zeroed it (what `reduceMotion: false` restores); `"null"` / absent = none known */
|
|
34
|
+
transitionOriginal?: () => string | undefined;
|
|
35
|
+
/** is `warden-uiad` how this driver reads the screen (TalkBack mode needs it: the dump fallback unbinds TalkBack); default false */
|
|
36
|
+
uiadAvailable?: () => boolean;
|
|
37
|
+
};
|
|
38
|
+
export type AndroidSettings = Pick<Driver, "permissions" | "timezone" | "locale" | "a11y" | "battery" | "memoryWarning" | "push">;
|
|
39
|
+
export declare function createAndroidSettings(deps: AndroidSettingsDeps): AndroidSettings & {
|
|
40
|
+
talkback: TalkBackControl;
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DriverResult } from "../driver.types";
|
|
2
|
+
import type { SpokenRead } from "../screen-reader";
|
|
3
|
+
import type { SrEventsRead } from "./uiad-screen-reader";
|
|
4
|
+
/**
|
|
5
|
+
* What TalkBack said since a cursor (`DrivesScreenReader.screenReaderSpoken`). The cursor is the device epoch ms of the
|
|
6
|
+
* last line returned, whichever source it came from. Real speech needs TalkBack's verbose log (a developer setting
|
|
7
|
+
* only its UI can change); without it the lines are composed by the speech model from the focus events the
|
|
8
|
+
* screen-reader stream saw, labelled `simulated`. Whichever the log allows is used for the whole read, never a mix.
|
|
9
|
+
*/
|
|
10
|
+
export type SpokenDeps = {
|
|
11
|
+
/** TalkBack's log, epoch timestamps (`TALKBACK_LOGCAT_ARGV`); undefined when it cannot be read */
|
|
12
|
+
readLog(): Promise<string | undefined>;
|
|
13
|
+
/** focus moves since 0 (the ring is small) */
|
|
14
|
+
focusEvents(): DriverResult<SrEventsRead>;
|
|
15
|
+
now(): number;
|
|
16
|
+
sleep(ms: number): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export declare function readSpoken(deps: SpokenDeps, since?: number): DriverResult<SpokenRead>;
|
|
@@ -21,7 +21,17 @@ export type AndroidDeviceState = {
|
|
|
21
21
|
uiadUnsupported?: string | undefined;
|
|
22
22
|
/** the scales to put back (what they were before warden set them to 0), while warden's zeros are in place */
|
|
23
23
|
animations?: AnimationValues | undefined;
|
|
24
|
+
/** physical phones: the rotation settings to put back, while warden's pinned rotation is in place */
|
|
25
|
+
rotation?: RotationValues | undefined;
|
|
26
|
+
/** physical phones: the `cmd uimode night` mode to put back, while warden's override is in place */
|
|
27
|
+
uimode?: UimodeValue | undefined;
|
|
24
28
|
};
|
|
29
|
+
/** `settings get system` values as printed: a digit, or `null` when never set. */
|
|
30
|
+
export type RotationValues = {
|
|
31
|
+
accelerometer_rotation: string;
|
|
32
|
+
user_rotation: string;
|
|
33
|
+
};
|
|
34
|
+
export type UimodeValue = "yes" | "no" | "auto";
|
|
25
35
|
/** The slice of `node:fs/promises` the store uses (injected in tests). */
|
|
26
36
|
export type StateFs = {
|
|
27
37
|
readFile(path: string): Promise<string>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ScreenReaderState } from "../../a11y/a11y.types";
|
|
2
|
+
import type { DriverResult } from "../driver.types";
|
|
3
|
+
/**
|
|
4
|
+
* TalkBack as the screen reader of an Android emulator (WDN-A11Y, A11Y-7). Everything is shell: the two secure settings
|
|
5
|
+
* that switch an accessibility service on, `pm` for presence and the notification grant, `dumpsys accessibility` to
|
|
6
|
+
* see that the service is bound (enabled in settings is not running: a UiAutomation client connected without
|
|
7
|
+
* `FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES` unbinds it). The previous values of both settings are kept so turning
|
|
8
|
+
* TalkBack off, or the lease's undo, puts back exactly what was there.
|
|
9
|
+
*/
|
|
10
|
+
export declare const TALKBACK_PACKAGE = "com.google.android.marvin.talkback";
|
|
11
|
+
export declare const TALKBACK_SERVICE = "com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService";
|
|
12
|
+
export declare const POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
|
|
13
|
+
export declare const talkbackPathArgv: readonly string[];
|
|
14
|
+
export declare const talkbackGrantArgv: readonly string[];
|
|
15
|
+
export declare const accessibilityDumpArgv: readonly string[];
|
|
16
|
+
export declare const secureGetArgv: (key: string) => string[];
|
|
17
|
+
/** Set a secure key, or delete it when `value` is null (it was unset). The driver's shell quotes each argument. */
|
|
18
|
+
export declare const secureWriteArgv: (key: string, value: string | null) => string[];
|
|
19
|
+
/** `settings get` answers the text `null` for an unset key. */
|
|
20
|
+
export declare function settingValue(stdout: string): string | null;
|
|
21
|
+
/** `services` with the TalkBack component added after whatever is there (`:` separated, once). */
|
|
22
|
+
export declare function withTalkBack(services: string | null): string;
|
|
23
|
+
/** Is a TalkBack service among the bound ones in `dumpsys accessibility`? */
|
|
24
|
+
export declare function talkbackBound(dump: string): boolean;
|
|
25
|
+
export type Previous = {
|
|
26
|
+
services: string | null;
|
|
27
|
+
enabled: string | null;
|
|
28
|
+
};
|
|
29
|
+
type Shelled = {
|
|
30
|
+
ok: boolean;
|
|
31
|
+
stdout: string;
|
|
32
|
+
failure: string | undefined;
|
|
33
|
+
};
|
|
34
|
+
export type TalkBackDeps = {
|
|
35
|
+
serial: string;
|
|
36
|
+
shell(argv: readonly string[]): Promise<Shelled>;
|
|
37
|
+
must(argv: readonly string[]): DriverResult<string>;
|
|
38
|
+
/** is `warden-uiad` the way this driver reads the screen (the dump unbinds TalkBack) */
|
|
39
|
+
uiadAvailable(): boolean;
|
|
40
|
+
sleep(ms: number): Promise<void>;
|
|
41
|
+
};
|
|
42
|
+
export type TalkBackControl = {
|
|
43
|
+
/** warden turned TalkBack on and has not turned it off */
|
|
44
|
+
active(): boolean;
|
|
45
|
+
/** TalkBack is the screen reader now: warden's doing, or found already on and bound by `detect` */
|
|
46
|
+
on(): boolean;
|
|
47
|
+
/** read the device once (`fresh`: again, for a TalkBack another process turned on since) for a TalkBack that was on before warden touched anything (a crashed run, a person) */
|
|
48
|
+
detect(fresh?: boolean): Promise<boolean>;
|
|
49
|
+
state(): ScreenReaderState;
|
|
50
|
+
previous(): Previous | undefined;
|
|
51
|
+
enable(): DriverResult<ScreenReaderState>;
|
|
52
|
+
disable(): DriverResult<ScreenReaderState>;
|
|
53
|
+
/** is the service bound right now */
|
|
54
|
+
bound(): Promise<boolean>;
|
|
55
|
+
};
|
|
56
|
+
export declare function createTalkBack(deps: TalkBackDeps): TalkBackControl;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DriverResult, Logger } from "../driver.types";
|
|
2
|
+
import type { AdbSession } from "./adb-session";
|
|
3
|
+
import { type PushDex } from "./uiad-device";
|
|
4
|
+
/**
|
|
5
|
+
* `warden-atf.jar` (the Accessibility Test Framework, ~180 KB) goes to the device on the first audit only, named by its
|
|
6
|
+
* hash like the uiad dex, so a new build is a new file and the always-pushed uiad dex stays small.
|
|
7
|
+
*/
|
|
8
|
+
export type AtfJar = {
|
|
9
|
+
bytes: number;
|
|
10
|
+
jarSha256: string;
|
|
11
|
+
base64: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function atfDevicePath(jar?: Pick<AtfJar, "jarSha256">): string;
|
|
14
|
+
export type EnsureAtfDeps = {
|
|
15
|
+
session: AdbSession;
|
|
16
|
+
adb: string;
|
|
17
|
+
serial: string;
|
|
18
|
+
push?: PushDex;
|
|
19
|
+
jar?: AtfJar;
|
|
20
|
+
log?: Logger;
|
|
21
|
+
};
|
|
22
|
+
/** The jar is on the device (written now if it was not); the result is its path. */
|
|
23
|
+
export declare function ensureAtfJar(deps: EnsureAtfDeps): DriverResult<string>;
|