Skip to content

Commit a513ac3

Browse files
committed
Normalize iOS swipe timing to safe duration
1 parent 711e26b commit a513ac3

5 files changed

Lines changed: 25 additions & 6 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ Pinch:
125125
- `pinch` is supported on iOS simulators.
126126
- On Android, `pinch` currently returns `UNSUPPORTED_OPERATION` in the adb backend.
127127

128+
Swipe timing:
129+
- `swipe` accepts optional `durationMs` (default `250`, range `16..10000`).
130+
- Android uses requested swipe duration directly.
131+
- iOS uses a safe normalized duration to avoid long-press side effects.
132+
128133
## Skills
129134
Install the automation skills listed in [SKILL.md](skills/agent-device/SKILL.md).
130135

ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ final class RunnerTests: XCTestCase {
255255
guard let x = command.x, let y = command.y, let x2 = command.x2, let y2 = command.y2 else {
256256
return Response(ok: false, error: ErrorPayload(message: "drag requires x, y, x2, and y2"))
257257
}
258-
let holdDuration = min(max((command.durationMs ?? 250) / 1000.0, 0.016), 10.0)
258+
let holdDuration = min(max((command.durationMs ?? 60) / 1000.0, 0.016), 10.0)
259259
dragAt(app: activeApp, x: x, y: y, x2: x2, y2: y2, holdDuration: holdDuration)
260260
return Response(ok: true, data: DataPayload(message: "dragged"))
261261
case .type:

skills/agent-device/SKILL.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ agent-device apps --platform android --user-installed
173173

174174
- `press` supports gesture series controls: `--count`, `--interval-ms`, `--hold-ms`, `--jitter-px`.
175175
- `swipe` supports coordinate + timing controls and repeat patterns: `swipe x1 y1 x2 y2 [durationMs] --count --pause-ms --pattern`.
176+
- `swipe` timing is platform-safe: Android uses requested duration; iOS uses normalized safe timing to avoid long-press side effects.
176177
- Pinch (`pinch <scale> [x y]`) is currently supported on iOS simulators only.
177178
- Snapshot refs are the core mechanism for interactive agent flows.
178179
- Use selectors for deterministic replay artifacts and assertions (e.g. in e2e test workflows).

src/core/dispatch.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,9 @@ export async function dispatchCommand(
158158
throw new AppError('INVALID_ARGS', 'swipe requires x1 y1 x2 y2 [durationMs]');
159159
}
160160

161-
const rawDurationMs = positionals[4] ? Number(positionals[4]) : 250;
162-
const durationMs = requireIntInRange(rawDurationMs, 'durationMs', 16, 10_000);
161+
const requestedDurationMs = positionals[4] ? Number(positionals[4]) : 250;
162+
const durationMs = requireIntInRange(requestedDurationMs, 'durationMs', 16, 10_000);
163+
const effectiveDurationMs = device.platform === 'ios' ? 60 : durationMs;
163164
const count = requireIntInRange(context?.count ?? 1, 'count', 1, 200);
164165
const pauseMs = requireIntInRange(context?.pauseMs ?? 0, 'pause-ms', 0, 10_000);
165166
const pattern = context?.pattern ?? 'one-way';
@@ -169,12 +170,23 @@ export async function dispatchCommand(
169170

170171
for (let index = 0; index < count; index += 1) {
171172
const reverse = pattern === 'ping-pong' && index % 2 === 1;
172-
if (reverse) await interactor.swipe(x2, y2, x1, y1, durationMs);
173-
else await interactor.swipe(x1, y1, x2, y2, durationMs);
173+
if (reverse) await interactor.swipe(x2, y2, x1, y1, effectiveDurationMs);
174+
else await interactor.swipe(x1, y1, x2, y2, effectiveDurationMs);
174175
if (index < count - 1 && pauseMs > 0) await sleep(pauseMs);
175176
}
176177

177-
return { x1, y1, x2, y2, durationMs, count, pauseMs, pattern };
178+
return {
179+
x1,
180+
y1,
181+
x2,
182+
y2,
183+
durationMs,
184+
effectiveDurationMs,
185+
timingMode: device.platform === 'ios' ? 'safe-normalized' : 'direct',
186+
count,
187+
pauseMs,
188+
pattern,
189+
};
178190
}
179191
case 'long-press': {
180192
const x = Number(positionals[0]);

website/docs/docs/commands.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ agent-device pinch 0.5 200 400 # zoom out at coordinates (iOS simulator)
5353
`fill` clears then types. `type` does not clear.
5454
On Android, `fill` also verifies text and performs one clear-and-retry pass on mismatch.
5555
`swipe` accepts an optional `durationMs` argument (default `250ms`, range `16..10000`).
56+
On iOS, swipe timing uses a safe normalized duration to avoid long-press side effects.
5657
`pinch` is iOS-simulator-only in the current adb-backed Android implementation.
5758

5859
## Find (semantic)

0 commit comments

Comments
 (0)