Skip to content

Commit d3151ae

Browse files
committed
Tighten Android API parity
1 parent f3f4bfd commit d3151ae

8 files changed

Lines changed: 384 additions & 159 deletions

File tree

client/src/app/AppShell.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,8 @@ export function AppShell({
352352
const [hierarchyVisible, setHierarchyVisible] = useState(() =>
353353
readStoredFlag(HIERARCHY_VISIBLE_STORAGE_KEY),
354354
);
355-
const [devToolsVisible, setDevToolsVisible] = useState(
356-
() => readStoredFlag(DEVTOOLS_VISIBLE_STORAGE_KEY, false),
355+
const [devToolsVisible, setDevToolsVisible] = useState(() =>
356+
readStoredFlag(DEVTOOLS_VISIBLE_STORAGE_KEY, false),
357357
);
358358
const [selectedUDID, setSelectedUDID] = useState(initialSelectedUDID ?? "");
359359
const [search, setSearch] = useState("");

client/src/features/stream/streamWorkerClient.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,12 +2132,18 @@ class WebRtcStreamClient implements StreamClientBackend {
21322132
this.rgbaChannel = channel;
21332133
channel.binaryType = "arraybuffer";
21342134
channel.addEventListener("message", (event) => {
2135-
if (generation !== this.connectGeneration || channel !== this.rgbaChannel) {
2135+
if (
2136+
generation !== this.connectGeneration ||
2137+
channel !== this.rgbaChannel
2138+
) {
21362139
return;
21372140
}
21382141
if (hasArrayBufferMethod(event.data)) {
21392142
void event.data.arrayBuffer().then((buffer) => {
2140-
if (generation === this.connectGeneration && channel === this.rgbaChannel) {
2143+
if (
2144+
generation === this.connectGeneration &&
2145+
channel === this.rgbaChannel
2146+
) {
21412147
this.handleRgbaMessage(buffer);
21422148
}
21432149
});
@@ -2204,7 +2210,13 @@ class WebRtcStreamClient implements StreamClientBackend {
22042210
}
22052211
assembly.buffer.set(chunk.payload, chunk.chunkOffset);
22062212
const chunkEnd = chunk.chunkOffset + chunk.payload.byteLength;
2207-
if (!rangeAlreadyReceived(assembly.receivedRanges, chunk.chunkOffset, chunkEnd)) {
2213+
if (
2214+
!rangeAlreadyReceived(
2215+
assembly.receivedRanges,
2216+
chunk.chunkOffset,
2217+
chunkEnd,
2218+
)
2219+
) {
22082220
assembly.receivedRanges.push([chunk.chunkOffset, chunkEnd]);
22092221
assembly.receivedBytes += chunk.payload.byteLength;
22102222
}
@@ -2250,7 +2262,11 @@ class WebRtcStreamClient implements StreamClientBackend {
22502262
frame.payload.byteLength,
22512263
);
22522264
try {
2253-
context.putImageData(new ImageData(rgba, frame.width, frame.height), 0, 0);
2265+
context.putImageData(
2266+
new ImageData(rgba, frame.width, frame.height),
2267+
0,
2268+
0,
2269+
);
22542270
} catch {
22552271
this.stats.droppedFrames += 1;
22562272
this.onMessage({ type: "stats", stats: { ...this.stats } });
@@ -2674,7 +2690,8 @@ function shouldUseLocalAndroidRgbaWebRtc(target: StreamConnectTarget): boolean {
26742690
!target.remote &&
26752691
isLoopbackHost(window.location.hostname) &&
26762692
(stream === "rgba" || stream === "webrtc-rgba") &&
2677-
(target.platform === "android-emulator" || target.udid.startsWith("android:"))
2693+
(target.platform === "android-emulator" ||
2694+
target.udid.startsWith("android:"))
26782695
);
26792696
}
26802697

docs/guide/testing.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,29 @@ try {
2828

2929
The current session object exposes:
3030

31-
| Method | Purpose |
32-
| -------------- | ----------------------------------------------------------------- |
33-
| `list()` | Fetch simulator inventory from `GET /api/simulators`. |
34-
| `launch()` | Launch an installed bundle ID. |
35-
| `openUrl()` | Open a URL or deep link. |
36-
| `tap()` | Tap normalized screen coordinates. |
37-
| `key()` | Send one HID key code. |
38-
| `button()` | Press a hardware button. |
39-
| `tree()` | Fetch an accessibility hierarchy. |
40-
| `query()` | Return compact matches for a selector. |
41-
| `waitFor()` | Poll until a selector appears. |
42-
| `assert()` | Assert a selector is present. |
43-
| `batch()` | Run multiple REST actions through `/api/simulators/{udid}/batch`. |
44-
| `screenshot()` | Return a PNG buffer. |
45-
| `close()` | Stop the daemon if this session started it. |
31+
| Method | Purpose |
32+
| -------------------------------------- | ----------------------------------------------------------------- |
33+
| `list()` | Fetch simulator inventory from `GET /api/simulators`. |
34+
| `install()`, `uninstall()` | Install or remove an app. |
35+
| `launch()` | Launch an installed bundle ID or Android package. |
36+
| `openUrl()` | Open a URL or deep link. |
37+
| `tap()`, `tapElement()` | Tap normalized coordinates or a matching accessibility element. |
38+
| `touch()`, `swipe()`, `gesture()` | Send normalized pointer gestures. |
39+
| `typeText()`, `key()`, `keySequence()` | Send text or HID keyboard input. |
40+
| `button()` | Press a hardware button. |
41+
| `home()`, `dismissKeyboard()` | Trigger common system controls. |
42+
| `appSwitcher()` | Open the app switcher. |
43+
| `rotateLeft()`, `rotateRight()` | Rotate the simulator display. |
44+
| `toggleAppearance()` | Toggle light/dark appearance. |
45+
| `pasteboardSet()`, `pasteboardGet()` | Read or write pasteboard text. |
46+
| `chromeProfile()` | Fetch screen/chrome geometry. |
47+
| `tree()` | Fetch an accessibility hierarchy. |
48+
| `query()` | Return compact matches for a selector. |
49+
| `waitFor()` | Poll until a selector appears. |
50+
| `assert()` | Assert a selector is present. |
51+
| `batch()` | Run multiple REST actions through `/api/simulators/{udid}/batch`. |
52+
| `screenshot()` | Return a PNG buffer. |
53+
| `close()` | Stop the daemon if this session started it. |
4654

4755
Selectors can match `id`, `label`, `value`, or `type`. Query options accept `source`, `maxDepth`, and `includeHidden`.
4856

packages/simdeck-test/dist/index.d.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export type QueryOptions = {
1313
| "react-native"
1414
| "flutter"
1515
| "uikit"
16-
| "native-ax";
16+
| "native-ax"
17+
| "android-uiautomator";
1718
maxDepth?: number;
1819
includeHidden?: boolean;
1920
};
@@ -28,6 +29,19 @@ export type TapOptions = QueryOptions & {
2829
waitTimeoutMs?: number;
2930
pollMs?: number;
3031
};
32+
export type SwipeOptions = {
33+
durationMs?: number;
34+
steps?: number;
35+
};
36+
export type GestureOptions = SwipeOptions & {
37+
delta?: number;
38+
};
39+
export type TypeTextOptions = {
40+
delayMs?: number;
41+
};
42+
export type KeySequenceOptions = {
43+
delayMs?: number;
44+
};
3145
export type SimDeckSession = {
3246
endpoint: string;
3347
pid: number;
@@ -44,8 +58,37 @@ export type SimDeckSession = {
4458
options?: TapOptions,
4559
): Promise<void>;
4660
touch(udid: string, x: number, y: number, phase: string): Promise<void>;
61+
swipe(
62+
udid: string,
63+
startX: number,
64+
startY: number,
65+
endX: number,
66+
endY: number,
67+
options?: SwipeOptions,
68+
): Promise<unknown>;
69+
gesture(
70+
udid: string,
71+
preset: string,
72+
options?: GestureOptions,
73+
): Promise<unknown>;
74+
typeText(
75+
udid: string,
76+
text: string,
77+
options?: TypeTextOptions,
78+
): Promise<unknown>;
4779
key(udid: string, keyCode: number, modifiers?: number): Promise<void>;
80+
keySequence(
81+
udid: string,
82+
keyCodes: number[],
83+
options?: KeySequenceOptions,
84+
): Promise<void>;
4885
button(udid: string, button: string, durationMs?: number): Promise<void>;
86+
home(udid: string): Promise<void>;
87+
dismissKeyboard(udid: string): Promise<void>;
88+
appSwitcher(udid: string): Promise<void>;
89+
rotateLeft(udid: string): Promise<void>;
90+
rotateRight(udid: string): Promise<void>;
91+
toggleAppearance(udid: string): Promise<void>;
4992
pasteboardSet(udid: string, text: string): Promise<void>;
5093
pasteboardGet(udid: string): Promise<string>;
5194
chromeProfile(udid: string): Promise<unknown>;

packages/simdeck-test/dist/index.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,68 @@ export async function connect(options = {}) {
6767
y,
6868
phase,
6969
}),
70+
swipe: (udid, startX, startY, endX, endY, swipeOptions = {}) =>
71+
requestJson(
72+
endpoint,
73+
"POST",
74+
`/api/simulators/${encodeURIComponent(udid)}/batch`,
75+
{
76+
steps: [
77+
{
78+
action: "swipe",
79+
startX,
80+
startY,
81+
endX,
82+
endY,
83+
...swipeOptions,
84+
},
85+
],
86+
},
87+
),
88+
gesture: (udid, preset, gestureOptions = {}) =>
89+
requestJson(
90+
endpoint,
91+
"POST",
92+
`/api/simulators/${encodeURIComponent(udid)}/batch`,
93+
{
94+
steps: [
95+
{
96+
action: "gesture",
97+
preset,
98+
...gestureOptions,
99+
},
100+
],
101+
},
102+
),
103+
typeText: (udid, text, typeOptions = {}) =>
104+
requestJson(
105+
endpoint,
106+
"POST",
107+
`/api/simulators/${encodeURIComponent(udid)}/batch`,
108+
{
109+
steps: [
110+
{
111+
action: "type",
112+
text,
113+
...typeOptions,
114+
},
115+
],
116+
},
117+
),
70118
key: (udid, keyCode, modifiers = 0) =>
71119
requestOk(endpoint, `/api/simulators/${encodeURIComponent(udid)}/key`, {
72120
keyCode,
73121
modifiers,
74122
}),
123+
keySequence: (udid, keyCodes, keySequenceOptions = {}) =>
124+
requestOk(
125+
endpoint,
126+
`/api/simulators/${encodeURIComponent(udid)}/key-sequence`,
127+
{
128+
keyCodes,
129+
...keySequenceOptions,
130+
},
131+
),
75132
button: (udid, button, durationMs = 0) =>
76133
requestOk(
77134
endpoint,
@@ -81,6 +138,42 @@ export async function connect(options = {}) {
81138
durationMs,
82139
},
83140
),
141+
home: (udid) =>
142+
requestOk(
143+
endpoint,
144+
`/api/simulators/${encodeURIComponent(udid)}/home`,
145+
null,
146+
),
147+
dismissKeyboard: (udid) =>
148+
requestOk(
149+
endpoint,
150+
`/api/simulators/${encodeURIComponent(udid)}/dismiss-keyboard`,
151+
null,
152+
),
153+
appSwitcher: (udid) =>
154+
requestOk(
155+
endpoint,
156+
`/api/simulators/${encodeURIComponent(udid)}/app-switcher`,
157+
null,
158+
),
159+
rotateLeft: (udid) =>
160+
requestOk(
161+
endpoint,
162+
`/api/simulators/${encodeURIComponent(udid)}/rotate-left`,
163+
null,
164+
),
165+
rotateRight: (udid) =>
166+
requestOk(
167+
endpoint,
168+
`/api/simulators/${encodeURIComponent(udid)}/rotate-right`,
169+
null,
170+
),
171+
toggleAppearance: (udid) =>
172+
requestOk(
173+
endpoint,
174+
`/api/simulators/${encodeURIComponent(udid)}/toggle-appearance`,
175+
null,
176+
),
84177
pasteboardSet: (udid, text) =>
85178
requestOk(
86179
endpoint,

0 commit comments

Comments
 (0)