agent-device 0.21.13 → 0.21.15

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.
Files changed (298) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.13.apk → agent-device-android-ime-helper-0.21.15.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.15.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.13.manifest.json → agent-device-android-ime-helper-0.21.15.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.15.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.13.manifest.json → agent-device-android-snapshot-helper-0.21.15.manifest.json} +6 -6
  7. package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +11 -1
  8. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +110 -2
  9. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +4 -2
  10. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerMainOwnedState.swift +27 -0
  11. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.h +8 -2
  12. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedTextEntry.m +26 -1
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +12 -19
  14. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +59 -20
  15. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +2 -3
  16. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +179 -91
  17. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +21 -24
  18. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -1
  19. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +9 -13
  20. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +36 -49
  21. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +11 -15
  22. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +136 -29
  23. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +20 -21
  24. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +3 -0
  25. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +6 -5
  26. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +12 -24
  27. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +22 -42
  28. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +15 -18
  29. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +73 -31
  30. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +20 -11
  31. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +9 -7
  32. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +5 -4
  33. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +2 -2
  34. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +51 -19
  35. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +5 -2
  36. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +78 -10
  37. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +32 -2
  38. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +7 -4
  39. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +23 -0
  40. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +17 -10
  41. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +8 -9
  42. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +9 -15
  43. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +12 -11
  44. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotCoordinateSpace.swift +16 -19
  45. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +24 -9
  46. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +66 -10
  47. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +12 -10
  48. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +1 -0
  49. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +27 -5
  50. package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -0
  51. package/dist/src/adapter.js +1 -1
  52. package/dist/src/adb-executor.js +1 -1
  53. package/dist/src/adb-failure.js +1 -1
  54. package/dist/src/adb-transport.js +1 -1
  55. package/dist/src/agent-browser-provider.js +1 -1
  56. package/dist/src/agent-browser-tool.js +1 -1
  57. package/dist/src/agent-device-client.js +2 -2
  58. package/dist/src/ai-sdk.js +1 -1
  59. package/dist/src/alert-runtime.js +1 -1
  60. package/dist/src/android-adb.d.ts +1 -8
  61. package/dist/src/android-input-ownership.js +1 -1
  62. package/dist/src/android-snapshot-quality.js +1 -0
  63. package/dist/src/android-system-chrome.js +1 -1
  64. package/dist/src/android.js +1 -1
  65. package/dist/src/app-catalog.js +1 -1
  66. package/dist/src/app-deployment-resolution.js +1 -1
  67. package/dist/src/app-inventory.js +1 -1
  68. package/dist/src/app-launch.js +1 -1
  69. package/dist/src/app-lifecycle.js +1 -1
  70. package/dist/src/app-lifecycle2.js +1 -1
  71. package/dist/src/app-log-files.js +1 -1
  72. package/dist/src/app-log-runtime2.js +1 -1
  73. package/dist/src/app-resolution.js +2 -2
  74. package/dist/src/apple-runner-platform.js +1 -1
  75. package/dist/src/application-lifecycle-interaction.js +1 -1
  76. package/dist/src/archive.js +1 -1
  77. package/dist/src/artifact-download.js +1 -1
  78. package/dist/src/auth-session.js +1 -1
  79. package/dist/src/auth.js +1 -1
  80. package/dist/src/backend-snapshot-options.js +1 -1
  81. package/dist/src/boot-diagnostics.js +1 -1
  82. package/dist/src/capture-disclosure.js +1 -1
  83. package/dist/src/capture.js +1 -1
  84. package/dist/src/cli-config.js +1 -1
  85. package/dist/src/cli-help.js +2 -2
  86. package/dist/src/cli.js +4 -4
  87. package/dist/src/click-button.js +1 -1
  88. package/dist/src/client-metro.js +1 -1
  89. package/dist/src/client-types.d.ts +102 -95
  90. package/dist/src/clipboard-shell-response.js +1 -1
  91. package/dist/src/command-schema.js +1 -1
  92. package/dist/src/command-tools.js +3 -3
  93. package/dist/src/connection-runtime.js +1 -1
  94. package/dist/src/connection.js +1 -1
  95. package/dist/src/contracts.d.ts +1 -1
  96. package/dist/src/contracts.js +1 -1
  97. package/dist/src/daemon-client-lifecycle.js +1 -1
  98. package/dist/src/daemon.js +1 -1
  99. package/dist/src/debug-symbols-facade.js +1 -1
  100. package/dist/src/device-claim-rule.js +2 -2
  101. package/dist/src/device-input-state.d.ts +15 -2
  102. package/dist/src/device-inventory-context.js +1 -1
  103. package/dist/src/device-rotation.js +1 -1
  104. package/dist/src/device-selection-resolver.js +1 -1
  105. package/dist/src/device-session.js +1 -1
  106. package/dist/src/device-shell.js +1 -1
  107. package/dist/src/device2.js +1 -1
  108. package/dist/src/devicectl.js +1 -1
  109. package/dist/src/diagnostics.js +1 -1
  110. package/dist/src/dispatch-resolve.js +1 -1
  111. package/dist/src/doctor2.js +1 -1
  112. package/dist/src/engine-eval-script.js +1 -1
  113. package/dist/src/error.js +1 -1
  114. package/dist/src/exec.js +1 -1
  115. package/dist/src/file.js +1 -1
  116. package/dist/src/find.js +1 -1
  117. package/dist/src/format.js +1 -1
  118. package/dist/src/gesture-plan-types.d.ts +1 -1
  119. package/dist/src/gesture-plan.js +1 -1
  120. package/dist/src/gesture-runtime.js +1 -1
  121. package/dist/src/harmonyos.js +1 -1
  122. package/dist/src/helper.js +2 -2
  123. package/dist/src/human-control-contract.js +1 -1
  124. package/dist/src/human-control.js +1 -1
  125. package/dist/src/index.d.ts +7 -3
  126. package/dist/src/index.js +1 -1
  127. package/dist/src/input-actions.js +1 -1
  128. package/dist/src/input-actions2.js +1 -1
  129. package/dist/src/install-artifact-facade.js +1 -1
  130. package/dist/src/install-source-network-transport.js +1 -1
  131. package/dist/src/install-source2.js +1 -1
  132. package/dist/src/interaction-positionals.js +1 -1
  133. package/dist/src/interaction-ref-policy.js +1 -1
  134. package/dist/src/interaction2.js +1 -1
  135. package/dist/src/interactor-operation-binding.js +1 -1
  136. package/dist/src/interactor.js +4 -4
  137. package/dist/src/interactor2.js +1 -1
  138. package/dist/src/interactors.js +1 -1
  139. package/dist/src/internal/bin.js +1 -1
  140. package/dist/src/internal/daemon.js +2 -2
  141. package/dist/src/internal/png-worker.js +1 -1
  142. package/dist/src/internal/run-script-http-child.js +1 -1
  143. package/dist/src/inventory.js +1 -1
  144. package/dist/src/inventory2.js +1 -1
  145. package/dist/src/inventory3.js +1 -1
  146. package/dist/src/inventory5.js +1 -1
  147. package/dist/src/ios-snapshot-acquisition.js +1 -1
  148. package/dist/src/ios-snapshot-engine.js +1 -0
  149. package/dist/src/ios-snapshot-runtime.js +1 -1
  150. package/dist/src/lease.js +1 -1
  151. package/dist/src/limrun-download-file.js +1 -1
  152. package/dist/src/limrun-runtime-dependencies.js +1 -1
  153. package/dist/src/limrun.d.ts +16 -3
  154. package/dist/src/linux.js +1 -1
  155. package/dist/src/location-coordinates.js +1 -1
  156. package/dist/src/managed-device-scope.js +1 -1
  157. package/dist/src/mechanics.js +17 -17
  158. package/dist/src/mobile-snapshot-semantics.js +1 -1
  159. package/dist/src/multitouch-support.js +1 -1
  160. package/dist/src/native-build-cache.js +1 -0
  161. package/dist/src/observation.js +1 -1
  162. package/dist/src/overlay.js +3 -0
  163. package/dist/src/parameterized-recorded-fill.js +1 -1
  164. package/dist/src/perf-facade.js +1 -1
  165. package/dist/src/perf-runtime-operation-builder.js +1 -1
  166. package/dist/src/perf-runtime-plan.js +1 -1
  167. package/dist/src/perf-target.js +2 -2
  168. package/dist/src/perf.js +1 -1
  169. package/dist/src/physical-device-control.js +1 -1
  170. package/dist/src/platform-runtime-host.js +1 -1
  171. package/dist/src/platform-runtime-managed-owner.js +1 -1
  172. package/dist/src/platform-runtime-open-target.js +1 -1
  173. package/dist/src/platform-runtime-operation-host.js +4 -4
  174. package/dist/src/platform-runtime-runtime-hints.js +1 -1
  175. package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
  176. package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
  177. package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
  178. package/dist/src/platform-runtime.js +1 -1
  179. package/dist/src/platform-runtime2.js +1 -1
  180. package/dist/src/png-crop-bytes.js +1 -1
  181. package/dist/src/png-size.js +1 -1
  182. package/dist/src/png-worker-client.js +1 -1
  183. package/dist/src/png.js +1 -1
  184. package/dist/src/prepare-kind.js +1 -1
  185. package/dist/src/provider-session-ownership.js +1 -1
  186. package/dist/src/provider-webdriver.js +1 -1
  187. package/dist/src/proxy.js +1 -1
  188. package/dist/src/quality-warnings.js +1 -1
  189. package/dist/src/react-native.js +1 -1
  190. package/dist/src/record-runtime.js +1 -1
  191. package/dist/src/recording.js +1 -1
  192. package/dist/src/rect-center.js +1 -1
  193. package/dist/src/register-builtins.js +1 -1
  194. package/dist/src/registry.js +36 -36
  195. package/dist/src/remote-config2.js +1 -1
  196. package/dist/src/replay-divergence.js +1 -1
  197. package/dist/src/replay.js +1 -1
  198. package/dist/src/reporting.js +1 -1
  199. package/dist/src/request-admission.js +1 -1
  200. package/dist/src/request-cancel.js +1 -1
  201. package/dist/src/request-runtime-binding.js +1 -1
  202. package/dist/src/retry.js +1 -1
  203. package/dist/src/runner-cache-metadata.js +1 -1
  204. package/dist/src/runner-client.js +1 -1
  205. package/dist/src/runner-dev-tools-security.js +1 -1
  206. package/dist/src/runner-device-readiness.js +1 -1
  207. package/dist/src/runner-disposal.js +1 -1
  208. package/dist/src/runner-error-classification.js +1 -1
  209. package/dist/src/runner.js +1 -1
  210. package/dist/src/runtime-transport-hints.js +1 -1
  211. package/dist/src/runtime.js +1 -3
  212. package/dist/src/runtime10.js +2 -2
  213. package/dist/src/runtime2.js +4 -4
  214. package/dist/src/runtime3.js +1 -1
  215. package/dist/src/runtime4.js +5 -5
  216. package/dist/src/runtime5.js +1 -1
  217. package/dist/src/runtime6.js +1 -1
  218. package/dist/src/runtime7.js +1 -1
  219. package/dist/src/runtime8.js +1 -1
  220. package/dist/src/runtime9.js +1 -1
  221. package/dist/src/screen-recording-admission-ledger.js +1 -1
  222. package/dist/src/screen-recording-completion.js +1 -1
  223. package/dist/src/screen-recording-options.js +1 -1
  224. package/dist/src/screen-recording-resource-recovery.js +1 -1
  225. package/dist/src/screenshot-density.js +1 -1
  226. package/dist/src/screenshot-image.js +1 -1
  227. package/dist/src/screenshot-overlay-draw.js +1 -1
  228. package/dist/src/screenshot-runtime.js +1 -1
  229. package/dist/src/screenshot.js +1 -1
  230. package/dist/src/screenshot3.js +1 -1
  231. package/dist/src/script.js +1 -1
  232. package/dist/src/scroll-command.d.ts +13 -6
  233. package/dist/src/scroll-command.js +1 -1
  234. package/dist/src/scroll-gesture.js +1 -1
  235. package/dist/src/sdk-batch-runner.js +2 -2
  236. package/dist/src/sdk-batch.js +2 -2
  237. package/dist/src/sdk-contracts.d.ts +59 -12
  238. package/dist/src/sdk-contracts.js +2 -2
  239. package/dist/src/sdk-device.js +1 -1
  240. package/dist/src/sdk-finders.d.ts +1 -1
  241. package/dist/src/sdk-io.js +1 -1
  242. package/dist/src/sdk-remote-config.js +1 -1
  243. package/dist/src/sdk-selectors.d.ts +1 -1
  244. package/dist/src/selection.js +0 -0
  245. package/dist/src/selector-runtime.js +1 -1
  246. package/dist/src/server.js +1 -1
  247. package/dist/src/session-allocation.js +1 -1
  248. package/dist/src/session-routing.js +1 -1
  249. package/dist/src/session-runtime-admission.js +1 -1
  250. package/dist/src/session-snapshot.js +1 -1
  251. package/dist/src/session-store.js +1 -1
  252. package/dist/src/session.js +1 -1
  253. package/dist/src/session2.js +4 -4
  254. package/dist/src/settings.js +1 -1
  255. package/dist/src/settings2.js +1 -0
  256. package/dist/src/simctl.js +1 -1
  257. package/dist/src/simulator-state.js +1 -1
  258. package/dist/src/simulator.js +1 -1
  259. package/dist/src/snapshot-capture-annotations.js +1 -1
  260. package/dist/src/snapshot-desktop-projection.js +1 -1
  261. package/dist/src/snapshot-runtime-binding.js +1 -1
  262. package/dist/src/snapshot-runtime.js +1 -1
  263. package/dist/src/snapshot-state.js +1 -1
  264. package/dist/src/snapshot2.js +1 -1
  265. package/dist/src/snapshot3.js +1 -1
  266. package/dist/src/snapshot4.js +1 -1
  267. package/dist/src/src.js +1 -1
  268. package/dist/src/src4.js +1 -1
  269. package/dist/src/src7.js +1 -1
  270. package/dist/src/src8.js +1 -1
  271. package/dist/src/string-enum.js +1 -1
  272. package/dist/src/surface-snapshot.js +1 -1
  273. package/dist/src/takeover.js +1 -1
  274. package/dist/src/text-entry-focus.js +1 -1
  275. package/dist/src/tool-provider-facade.js +1 -1
  276. package/dist/src/tool-provider.js +2 -2
  277. package/dist/src/tool-provider2.js +1 -1
  278. package/dist/src/touch-runtime.js +1 -1
  279. package/dist/src/transport.js +1 -1
  280. package/dist/src/tree.js +1 -1
  281. package/dist/src/tv-remote.js +1 -1
  282. package/dist/src/type-text-runtime.js +1 -1
  283. package/dist/src/verified-file.js +1 -1
  284. package/dist/src/video.js +1 -1
  285. package/dist/src/viewport.js +1 -1
  286. package/dist/src/web.js +1 -1
  287. package/dist/src/web2.js +1 -1
  288. package/dist/src/webdriver-source.js +1 -1
  289. package/package.json +1 -1
  290. package/server.json +2 -2
  291. package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +0 -1
  292. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk +0 -0
  293. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk.sha256 +0 -1
  294. package/dist/src/absence-observation-errors.js +0 -1
  295. package/dist/src/runner-presentation.js +0 -1
  296. package/dist/src/semantic-index.js +0 -1
  297. package/dist/src/snapshot-process.js +0 -1
  298. package/dist/src/snapshot-scope.js +0 -1
@@ -11,8 +11,8 @@ extension RunnerTests {
11
11
  private func executeSnapshotDispatchedOnce(command: Command) throws -> Response {
12
12
  let preparation: SnapshotCommandPreparation = try runMainThreadWork(
13
13
  "command_preparation",
14
- timeout: mainThreadExecutionTimeout,
15
- timeoutError: mainThreadExecutionTimeoutError
14
+ timeout: Self.mainThreadExecutionTimeout,
15
+ timeoutError: Self.mainThreadExecutionTimeoutError
16
16
  ) { () -> SnapshotCommandPreparation in
17
17
  switch try self.prepareActiveCommandContextSafely(command: command, routeToSpringboard: false) {
18
18
  case .response(let response):
@@ -36,6 +36,7 @@ extension RunnerTests {
36
36
  }
37
37
  }
38
38
 
39
+ @MainActor
39
40
  private func prepareActiveCommandContextSafely(
40
41
  command: Command,
41
42
  routeToSpringboard: Bool
@@ -125,9 +126,9 @@ extension RunnerTests {
125
126
  try runMainThreadWork(
126
127
  "post_snapshot_delay_mark",
127
128
  timeout: 1,
128
- timeoutError: mainThreadExecutionTimeoutError
129
+ timeoutError: Self.mainThreadExecutionTimeoutError
129
130
  ) {
130
- self.needsPostSnapshotInteractionDelay = true
131
+ self.mainOwned.needsPostSnapshotInteractionDelay = true
131
132
  }
132
133
  } catch {
133
134
  NSLog("AGENT_DEVICE_RUNNER_POST_SNAPSHOT_DELAY_MARK_FAILED=%@", String(describing: error))
@@ -24,11 +24,11 @@ enum SnapshotCapturePhase: Equatable {
24
24
  }
25
25
 
26
26
  struct SnapshotPhaseTimer {
27
- private let now: () -> Date
27
+ private let now: @Sendable () -> Date
28
28
  private var acquisitionSeconds: TimeInterval = 0
29
29
  private var presentationSeconds: TimeInterval = 0
30
30
 
31
- init(now: @escaping () -> Date = { Date() }) {
31
+ init(now: @escaping @Sendable () -> Date = { Date() }) {
32
32
  self.now = now
33
33
  }
34
34
 
@@ -14,15 +14,12 @@ enum RunnerAccessibilityHealth: String, Equatable {
14
14
 
15
15
  enum SynthesizedKeyboardPolicy: String, Equatable, Hashable {
16
16
  case never
17
- case whenAccessibilityHealthy
18
17
  case requiredWhenAvailable
19
18
 
20
19
  func allowsProbe(accessibilityHealth: RunnerAccessibilityHealth) -> Bool {
21
20
  switch self {
22
21
  case .never:
23
22
  return false
24
- case .whenAccessibilityHealthy:
25
- return accessibilityHealth == .healthy
26
23
  case .requiredWhenAvailable:
27
24
  return accessibilityHealth != .unavailable
28
25
  }
@@ -63,7 +60,6 @@ struct SynthesizedCoordinateContext {
63
60
 
64
61
  let resolvedWindow: XCUIElement
65
62
  let keyboardPolicy: SynthesizedKeyboardPolicy
66
- let fallbackPolicy: SynthesizedFallbackPolicy
67
63
  let accessibilityHealth: RunnerAccessibilityHealth
68
64
 
69
65
  func withReferenceFrame(_ frame: CGRect) -> SynthesizedCoordinateContext {
@@ -71,15 +67,10 @@ struct SynthesizedCoordinateContext {
71
67
  referenceFrame: frame,
72
68
  resolvedWindow: resolvedWindow,
73
69
  keyboardPolicy: keyboardPolicy,
74
- fallbackPolicy: fallbackPolicy,
75
70
  accessibilityHealth: accessibilityHealth
76
71
  )
77
72
  }
78
73
 
79
- var allowsXCTestCoordinateFallback: Bool {
80
- fallbackPolicy.allowsXCTestCoordinateFallback(accessibilityHealth: accessibilityHealth)
81
- }
82
-
83
74
  var allowsKeyboardProbe: Bool {
84
75
  keyboardPolicy.allowsProbe(accessibilityHealth: accessibilityHealth)
85
76
  }
@@ -115,24 +106,64 @@ func shouldProbeCoordinateTapTextInput(xCTestChannelPenalized: Bool) -> Bool {
115
106
  !xCTestChannelPenalized
116
107
  }
117
108
 
118
- func sequenceHasSynthesizedCoordinateStep(_ steps: [SequenceStep]) -> Bool {
119
- steps.contains { step in
120
- step.synthesized == true && step.kind == "tap"
121
- }
109
+
110
+ func synthesizedPolicyKind(forSequenceStep step: SequenceStep) -> SynthesizedGesturePolicyKind? {
111
+ step.synthesized == true && step.kind == "tap" ? .coordinateTap : nil
112
+ }
113
+
114
+
115
+ enum SynthesizedGestureAttempt {
116
+ case performed(timing: (gestureStartUptimeMs: Double, gestureEndUptimeMs: Double))
117
+
118
+ case xctestFallback(message: String, hint: String?)
119
+
120
+ case refused(
121
+ timing: (gestureStartUptimeMs: Double, gestureEndUptimeMs: Double),
122
+ message: String,
123
+ hint: String?
124
+ )
122
125
  }
123
126
 
124
127
  extension RunnerTests {
128
+ @MainActor
125
129
  func synthesizedSequenceCoordinateContext(
126
130
  steps: [SequenceStep],
127
131
  app: XCUIApplication
128
132
  ) -> SynthesizedCoordinateContext? {
129
- guard sequenceHasSynthesizedCoordinateStep(steps) else { return nil }
130
- return synthesizedCoordinateContext(
131
- app: app,
132
- policy: synthesizedGesturePolicy(.synthesizedDrag)
133
+ guard let kind = steps.lazy.compactMap(synthesizedPolicyKind(forSequenceStep:)).first else {
134
+ return nil
135
+ }
136
+ return synthesizedCoordinateContext(app: app, policy: synthesizedGesturePolicy(kind))
137
+ }
138
+
139
+
140
+
141
+ @MainActor
142
+ func performSynthesizedGesture(
143
+ _ app: XCUIApplication,
144
+ kind: SynthesizedGesturePolicyKind,
145
+ context: SynthesizedCoordinateContext?,
146
+ synthesize: () -> RunnerInteractionOutcome
147
+ ) -> SynthesizedGestureAttempt {
148
+ let (timing, outcome) = performGesture(app, idleTimeout: false, synthesize)
149
+ guard case .unsupported(let message, let hint) = outcome else {
150
+ logSynthesizedGesturePolicyDecision(kind: kind, context: context, fallbackAttempted: false)
151
+ return .performed(timing: timing)
152
+ }
153
+ let fallbackAllowed = synthesizedGesturePolicy(kind).fallbackPolicy.allowsXCTestCoordinateFallback(
154
+ accessibilityHealth: context?.accessibilityHealth ?? mainOwned.accessibilityHealth
155
+ )
156
+ logSynthesizedGesturePolicyDecision(
157
+ kind: kind,
158
+ context: context,
159
+ fallbackAttempted: fallbackAllowed
133
160
  )
161
+ return fallbackAllowed
162
+ ? .xctestFallback(message: message, hint: hint)
163
+ : .refused(timing: timing, message: message, hint: hint)
134
164
  }
135
165
 
166
+ @MainActor
136
167
  func logSynthesizedGesturePolicyDecision(
137
168
  kind: SynthesizedGesturePolicyKind,
138
169
  context: SynthesizedCoordinateContext?,
@@ -162,11 +193,12 @@ extension RunnerTests {
162
193
  return "AGENT_DEVICE_RUNNER_SYNTHESIZED_GESTURE_POLICY kind=\(kind.rawValue)"
163
194
  + " context=unavailable fallbackAttempted=\(fallbackAttempted)"
164
195
  }
196
+ let fallbackPolicy = synthesizedGesturePolicy(kind).fallbackPolicy
165
197
  return "AGENT_DEVICE_RUNNER_SYNTHESIZED_GESTURE_POLICY kind=\(kind.rawValue)"
166
198
  + " axHealth=\(context.accessibilityHealth.rawValue) frameSource=window"
167
199
  + " keyboardPolicy=\(context.keyboardPolicy.rawValue)"
168
- + " fallbackPolicy=\(context.fallbackPolicy.rawValue)"
169
- + " fallbackAllowed=\(context.allowsXCTestCoordinateFallback)"
200
+ + " fallbackPolicy=\(fallbackPolicy.rawValue)"
201
+ + " fallbackAllowed=\(fallbackPolicy.allowsXCTestCoordinateFallback(accessibilityHealth: context.accessibilityHealth))"
170
202
  + " fallbackAttempted=\(fallbackAttempted)"
171
203
  }
172
204
  }
@@ -2,6 +2,7 @@ import XCTest
2
2
  import AgentDeviceSnapshotPresentation
3
3
 
4
4
  extension RunnerTests {
5
+ @MainActor
5
6
  func synthesizedDragAt(
6
7
  app: XCUIApplication,
7
8
  x: Double,
@@ -89,6 +90,7 @@ extension RunnerTests {
89
90
  #endif
90
91
  }
91
92
 
93
+ @MainActor
92
94
  func synthesizedTapAt(
93
95
  app: XCUIApplication,
94
96
  x: Double,
@@ -276,6 +278,7 @@ extension RunnerTests {
276
278
  #endif
277
279
  }
278
280
 
281
+ @MainActor
279
282
  func axFreeSynthesizedDragPlan(
280
283
  app: XCUIApplication,
281
284
  x: Double,
@@ -364,12 +367,13 @@ extension RunnerTests {
364
367
  )
365
368
  }
366
369
 
370
+ @MainActor
367
371
  func synthesizedCoordinateContext(
368
372
  app: XCUIApplication,
369
373
  policy: SynthesizedGesturePolicy
370
374
  ) -> SynthesizedCoordinateContext? {
371
375
  #if os(iOS)
372
- let health = runnerAccessibilityHealth
376
+ let health = mainOwned.accessibilityHealth
373
377
  let resolved = resolveRunnerWindow(app: app)
374
378
  guard let window = resolved.window else {
375
379
  return nil
@@ -384,7 +388,6 @@ extension RunnerTests {
384
388
  referenceFrame: referenceFrame,
385
389
  resolvedWindow: window,
386
390
  keyboardPolicy: policy.keyboardPolicy,
387
- fallbackPolicy: policy.fallbackPolicy,
388
391
  accessibilityHealth: health
389
392
  )
390
393
  #else
@@ -82,11 +82,11 @@ extension RunnerTests {
82
82
  text: String,
83
83
  delaySeconds: Double
84
84
  ) -> [SynthesizedReplacementStep] {
85
- let characters = Array(text)
86
- guard delaySeconds > 0, characters.count > 1 else {
85
+ guard synthesizedReplacementIsSpaced(characterCount: text.count, delaySeconds: delaySeconds)
86
+ else {
87
87
  return [SynthesizedReplacementStep(text: text, replacesExistingText: true)]
88
88
  }
89
- return characters.enumerated().map { index, character in
89
+ return Array(text).enumerated().map { index, character in
90
90
  SynthesizedReplacementStep(
91
91
  text: String(character),
92
92
  replacesExistingText: index == 0
@@ -94,11 +94,86 @@ extension RunnerTests {
94
94
  }
95
95
  }
96
96
 
97
+
98
+
99
+ static func synthesizedReplacementIsSpaced(characterCount: Int, delaySeconds: Double) -> Bool {
100
+ delaySeconds > 0 && characterCount > 1
101
+ }
102
+
103
+
104
+
105
+
106
+ enum SynthesizedDeliveryBudget {
107
+
108
+ static var characterInterval: TimeInterval {
109
+ 1.0 / Double(RunnerSynthesizedTextEntry.typingSpeedCharactersPerSecond())
110
+ }
111
+
112
+
113
+
114
+
115
+
116
+
117
+ static func projectedSeconds(
118
+ textLength: Int,
119
+ delaySeconds: TimeInterval,
120
+ typeWarmup: Bool = false
121
+ ) -> TimeInterval {
122
+ let spaced = synthesizedReplacementIsSpaced(characterCount: textLength, delaySeconds: delaySeconds)
123
+ let warmupSplit = typeWarmup && textLength > 1 && !spaced
124
+ let calls = spaced ? textLength : (warmupSplit ? 2 : 1)
125
+ return Double(textLength) * characterInterval
126
+ + Double(calls) * TextEntryTiming.synthesizeCallOverhead
127
+ + Double(calls - 1) * delaySeconds
128
+ + (warmupSplit ? TextEntryTiming.pollInterval : 0)
129
+ }
130
+
131
+ static func exceeds(
132
+ textLength: Int,
133
+ delaySeconds: TimeInterval,
134
+ typeWarmup: Bool = false
135
+ ) -> Bool {
136
+ projectedSeconds(textLength: textLength, delaySeconds: delaySeconds, typeWarmup: typeWarmup)
137
+ > TextEntryTiming.synthesizedDeliveryCeiling
138
+ }
139
+
140
+
141
+ static func maxTextLength(delaySeconds: TimeInterval) -> Int {
142
+ var length = 1
143
+ while !exceeds(textLength: length + 1, delaySeconds: delaySeconds) {
144
+ length += 1
145
+ }
146
+ return length
147
+ }
148
+ }
149
+
150
+ @MainActor
97
151
  func runSynthesizedReplacementRoute(
98
152
  _ request: SynthesizedReplacementRequest
99
153
  ) -> SynthesizedReplacementRouteOutcome {
100
154
  #if os(iOS)
101
155
  NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_ROUTE route=synthesized-first-responder-replacement")
156
+ if SynthesizedDeliveryBudget.exceeds(
157
+ textLength: request.text.count,
158
+ delaySeconds: request.delaySeconds
159
+ ) {
160
+ NSLog(
161
+ "AGENT_DEVICE_RUNNER_TEXT_ENTRY_ROUTE route=synthesized-first-responder-replacement "
162
+ + "reason=delivery-budget-refused chars=%d budgetChars=%d",
163
+ request.text.count,
164
+ SynthesizedDeliveryBudget.maxTextLength(delaySeconds: request.delaySeconds)
165
+ )
166
+ return .completed(
167
+ TextEntryResult(
168
+ verified: nil,
169
+ repaired: false,
170
+ expectedText: request.text,
171
+ observedText: nil,
172
+ textEntryRoute: "synthesized-first-responder-replacement",
173
+ failure: .synthesisBudgetExceeded
174
+ )
175
+ )
176
+ }
102
177
  let steps = Self.synthesizedReplacementSteps(
103
178
  text: request.text,
104
179
  delaySeconds: request.delaySeconds
@@ -270,11 +345,4 @@ extension RunnerTests {
270
345
  ) -> Bool {
271
346
  repairMode == .replacement && hasX && hasY && xCTestChannelPenalized
272
347
  }
273
-
274
- static func shouldFallbackFromSynthesizedTextEntryFocus(
275
- _ outcome: RunnerInteractionOutcome
276
- ) -> Bool {
277
- if case .unsupported = outcome { return true }
278
- return false
279
- }
280
348
  }
@@ -8,6 +8,7 @@ extension RunnerTests {
8
8
  case notFocused = "TEXT_INPUT_NOT_FOCUSED"
9
9
  case synthesisUnavailable = "TEXT_INPUT_SYNTHESIS_UNAVAILABLE"
10
10
  case commitNotObserved = "TEXT_INPUT_COMMIT_NOT_OBSERVED"
11
+ case synthesisBudgetExceeded = "TEXT_INPUT_SYNTHESIS_BUDGET_EXCEEDED"
11
12
 
12
13
  var message: String {
13
14
  switch self {
@@ -17,6 +18,8 @@ extension RunnerTests {
17
18
  return "Reliable text synthesis is unavailable while the software keyboard is hidden."
18
19
  case .commitNotObserved:
19
20
  return "The runner could not confirm the typed text reached the field."
21
+ case .synthesisBudgetExceeded:
22
+ return "The text is longer than one runner command can type at this pace."
20
23
  }
21
24
  }
22
25
 
@@ -27,7 +30,13 @@ extension RunnerTests {
27
30
  case .synthesisUnavailable:
28
31
  return "Show the software keyboard, then retry type."
29
32
  case .commitNotObserved:
30
- return "The field may hold none, part, or all of the text. Run snapshot -i and inspect the field: if it already matches, continue; otherwise retry fill with the full text quoted and --delay-ms 80. Do not use type, which appends to whatever committed."
33
+ return "The field may hold none, part, or all of the text. Run snapshot -i and inspect the field: if it already matches, continue; otherwise retry fill with the full text quoted and --delay-ms \(TextEntryTiming.recoveryDelayMilliseconds). Do not use type, which appends to whatever committed."
34
+ case .synthesisBudgetExceeded:
35
+ let recoveryDelay = TextEntryTiming.recoveryDelayMilliseconds
36
+ let recoveryBudget = SynthesizedDeliveryBudget.maxTextLength(
37
+ delaySeconds: Double(recoveryDelay) / 1000
38
+ )
39
+ return "Fill at most \(SynthesizedDeliveryBudget.maxTextLength(delaySeconds: 0)) characters at a time without --delay-ms and append the rest with separate type commands, keeping each command inside that budget. --delay-ms lowers the budget, because each character then gets its own synthesize call and each gap between characters pays the delay: \(recoveryBudget) characters at --delay-ms \(recoveryDelay). A longer timeout does not help: this route is chosen when the accessibility channel is already degraded, and the pace is what makes the text long."
31
40
  }
32
41
  }
33
42
  }
@@ -51,8 +60,29 @@ extension RunnerTests {
51
60
  static let synthesizedCommitStallTimeout: TimeInterval = 3.0
52
61
 
53
62
 
54
-
55
63
  static let synthesizedCommitCeiling: TimeInterval = 10.0
64
+
65
+
66
+ static let synthesizedReplacementFocusAllowance: TimeInterval = 2.0
67
+
68
+
69
+
70
+
71
+ static let synthesizedDeliveryCeiling: TimeInterval = RunnerTests.mainThreadExecutionTimeout
72
+ - synthesizedReplacementFocusAllowance
73
+ - synthesizedCommitCeiling
74
+
75
+
76
+
77
+
78
+
79
+ static let synthesizedAcknowledgeWindowSeconds: TimeInterval = 0.04
80
+
81
+
82
+
83
+ static let synthesizeCallOverhead: TimeInterval = 0.15
84
+
85
+ static let recoveryDelayMilliseconds = 80
56
86
  static let synthesizedCommitPollInterval: TimeInterval = 0.2
57
87
  }
58
88
 
@@ -6,6 +6,7 @@ import XCTest
6
6
 
7
7
 
8
8
  extension RunnerTests {
9
+ @MainActor
9
10
  func rememberTextEntryTap(_ element: XCUIElement?) {
10
11
  guard let element, isTextEntryElement(element) else {
11
12
  clearRememberedTextEntryTap()
@@ -13,8 +14,8 @@ extension RunnerTests {
13
14
  }
14
15
  textEntryTapWitness = TextEntryTapWitness(
15
16
  element: element,
16
- bundleId: currentBundleId,
17
- processIdentifier: currentAppProcessIdentifier
17
+ bundleId: mainOwned.bundleId,
18
+ processIdentifier: mainOwned.processIdentifier
18
19
  )
19
20
  }
20
21
 
@@ -22,6 +23,7 @@ extension RunnerTests {
22
23
  textEntryTapWitness = nil
23
24
  }
24
25
 
26
+ @MainActor
25
27
  private func rememberedTextEntryTarget() -> TextEntryTarget? {
26
28
  guard let witness = textEntryTapWitness else {
27
29
  return nil
@@ -30,8 +32,8 @@ extension RunnerTests {
30
32
 
31
33
  clearRememberedTextEntryTap()
32
34
  guard witness.matches(
33
- bundleId: currentBundleId,
34
- processIdentifier: currentAppProcessIdentifier
35
+ bundleId: mainOwned.bundleId,
36
+ processIdentifier: mainOwned.processIdentifier
35
37
  ) else {
36
38
  return nil
37
39
  }
@@ -80,6 +82,7 @@ extension RunnerTests {
80
82
  #endif
81
83
  }
82
84
 
85
+ @MainActor
83
86
  func focusTextInputForTextEntry(app: XCUIApplication, x: Double?, y: Double?) -> TextEntryTarget {
84
87
  guard let x, let y else {
85
88
  let softwareKeyboardVisible = isKeyboardVisible(app: app)
@@ -3,6 +3,7 @@ import XCTest
3
3
 
4
4
 
5
5
  extension RunnerTests {
6
+ @MainActor
6
7
  func typeTextReliably(
7
8
  app: XCUIApplication,
8
9
  target: TextEntryTarget,
@@ -162,6 +163,28 @@ extension RunnerTests {
162
163
  return (currentTarget, nil)
163
164
  } else if activeTarget.prefersFocusedElement && isKeyboardVisible(app: app) {
164
165
  #if os(iOS)
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+ if SynthesizedDeliveryBudget.exceeds(
175
+ textLength: text.count,
176
+ delaySeconds: delaySeconds,
177
+ typeWarmup: repairMode != .none
178
+ ) {
179
+ textEntryRoute = "xctest-application-fallback"
180
+ NSLog(
181
+ "AGENT_DEVICE_RUNNER_TEXT_ENTRY_ROUTE route=xctest-application-fallback "
182
+ + "reason=delivery-budget chars=%d",
183
+ value.count
184
+ )
185
+ app.typeText(value)
186
+ return (resolveTextEntryElement(app: app, target: activeTarget), nil)
187
+ }
165
188
  textEntryRoute = "synthesized-first-responder"
166
189
  NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_ROUTE route=synthesized-first-responder")
167
190
  let action = synthesizer.enterText(
@@ -33,11 +33,7 @@ extension RunnerTests {
33
33
  let combined = buffer + data
34
34
  if let body = self.parseRequest(data: combined) {
35
35
  self.handleRequestBody(body) { [weak self] result in
36
- self?.sendResponse(result.data, over: connection) { [weak self] in
37
- if result.shouldFinish {
38
- self?.finish()
39
- }
40
- }
36
+ self?.sendResult(result, over: connection)
41
37
  }
42
38
  } else {
43
39
  self.receiveRequest(connection: connection, buffer: combined)
@@ -45,10 +41,21 @@ extension RunnerTests {
45
41
  }
46
42
  }
47
43
 
44
+ private func sendResult(
45
+ _ result: (data: Data, shouldFinish: Bool),
46
+ over connection: NWConnection
47
+ ) {
48
+ sendResponse(result.data, over: connection) { [weak self] in
49
+ if result.shouldFinish {
50
+ self?.finish()
51
+ }
52
+ }
53
+ }
54
+
48
55
  private func sendResponse(
49
56
  _ response: Data,
50
57
  over connection: NWConnection,
51
- afterSend: @escaping () -> Void = {}
58
+ afterSend: @escaping @Sendable () -> Void = {}
52
59
  ) {
53
60
  connection.send(content: response, isComplete: true, completion: .contentProcessed { error in
54
61
  if let error {
@@ -89,7 +96,7 @@ extension RunnerTests {
89
96
 
90
97
  private func handleRequestBody(
91
98
  _ body: Data,
92
- completion: @escaping ((data: Data, shouldFinish: Bool)) -> Void
99
+ completion: @escaping @Sendable ((data: Data, shouldFinish: Bool)) -> Void
93
100
  ) {
94
101
  guard String(data: body, encoding: .utf8) != nil else {
95
102
  completion((
@@ -187,7 +194,7 @@ extension RunnerTests {
187
194
 
188
195
  func enqueueAccepted(
189
196
  command: Command,
190
- completion: @escaping (Result<Response, Error>) -> Void
197
+ completion: @escaping @Sendable (Result<Response, Error>) -> Void
191
198
  ) {
192
199
  commandJournal.accept(command: command)
193
200
  commandExecutionQueue.async {
@@ -202,7 +209,7 @@ extension RunnerTests {
202
209
 
203
210
  func attachToInFlightCommandIfNeeded(
204
211
  command: Command,
205
- completion: @escaping ((data: Data, shouldFinish: Bool)) -> Void
212
+ completion: @escaping @Sendable ((data: Data, shouldFinish: Bool)) -> Void
206
213
  ) -> Bool {
207
214
  guard let commandId = command.commandId?.trimmedNonEmpty else { return false }
208
215
  inFlightCommandLock.lock()
@@ -226,7 +233,7 @@ extension RunnerTests {
226
233
  result: (data: Data, shouldFinish: Bool),
227
234
  completion: ((data: Data, shouldFinish: Bool)) -> Void
228
235
  ) {
229
- var waiters: [((data: Data, shouldFinish: Bool)) -> Void] = []
236
+ var waiters: [@Sendable ((data: Data, shouldFinish: Bool)) -> Void] = []
230
237
  if let commandId = command.commandId?.trimmedNonEmpty {
231
238
  inFlightCommandLock.lock()
232
239
  inFlightCommandIds.remove(commandId)
@@ -52,23 +52,22 @@ extension RunnerTests {
52
52
  }
53
53
 
54
54
  func elementHasFocus(_ element: XCUIElement) -> Bool {
55
- var focused = false
56
- _ = RunnerObjCExceptionCatcher.catchException({
57
- if let value = (element as NSObject).value(forKey: "hasFocus") as? Bool {
58
- focused = value
59
- }
60
- })
61
- return focused
55
+ return focusBool(element as NSObject)
62
56
  }
63
57
 
64
- func activateElement(app: XCUIApplication, element: XCUIElement, action: String) -> RunnerInteractionOutcome {
58
+ func activateElement(
59
+ app: XCUIApplication,
60
+ element: XCUIElement,
61
+ action: String,
62
+ resolvedFrame: CGRect? = nil
63
+ ) -> RunnerInteractionOutcome {
65
64
  if let outcome = selectFocusedTvElement(app: app, element: element, action: action) {
66
65
  return outcome
67
66
  }
68
67
  #if os(tvOS)
69
68
  return performElementTap(element)
70
69
  #else
71
- let frame = element.frame
70
+ let frame = resolvedFrame ?? element.frame
72
71
  if !frame.isEmpty {
73
72
 
74
73
 
@@ -2,6 +2,7 @@ import XCTest
2
2
  import AgentDeviceSnapshotPresentation
3
3
 
4
4
  extension RunnerTests {
5
+ @MainActor
5
6
  func executeTypeCommand(activeApp: XCUIApplication, command: Command) -> Response {
6
7
  guard let text = command.text else {
7
8
  return Response(ok: false, error: ErrorPayload(message: "type requires text"))
@@ -18,7 +19,7 @@ extension RunnerTests {
18
19
  : nil
19
20
  let focusStartedAt = Date()
20
21
  #if os(iOS)
21
- let xCTestChannelPenalized = isSnapshotXCTestChannelPenalized(bundleId: currentBundleId)
22
+ let xCTestChannelPenalized = isSnapshotXCTestChannelPenalized(bundleId: mainOwned.bundleId)
22
23
  var resolvedCoordinateTarget: TextEntryTarget?
23
24
  if Self.shouldUseResolvedCoordinateTextEntryRoute(
24
25
  repairMode: textEntryMode,
@@ -31,27 +32,20 @@ extension RunnerTests {
31
32
  app: activeApp,
32
33
  policy: synthesizedGesturePolicy(policyKind)
33
34
  )
34
- let (_, outcome) = performGesture(activeApp, idleTimeout: false) {
35
+ switch performSynthesizedGesture(activeApp, kind: policyKind, context: context, synthesize: {
35
36
  synthesizedTapAt(app: activeApp, x: x, y: y, context: context)
36
- }
37
- if Self.shouldFallbackFromSynthesizedTextEntryFocus(outcome) {
38
- logSynthesizedGesturePolicyDecision(
39
- kind: policyKind,
40
- context: context,
41
- fallbackAttempted: true
42
- )
43
- } else {
44
- logSynthesizedGesturePolicyDecision(
45
- kind: policyKind,
46
- context: context,
47
- fallbackAttempted: false
48
- )
37
+ }) {
38
+ case .performed:
49
39
  resolvedCoordinateContext = context
50
40
  resolvedCoordinateTarget = TextEntryTarget(
51
41
  element: nil,
52
42
  refreshPoint: CGPoint(x: x, y: y),
53
43
  prefersFocusedElement: false
54
44
  )
45
+ case .xctestFallback:
46
+ break
47
+ case .refused(_, let message, let hint):
48
+ return unsupportedResponse(message: message, hint: hint)
55
49
  }
56
50
  }
57
51
  #else