agent-device 0.21.19 → 0.21.21
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/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.19.apk → agent-device-android-ime-helper-0.21.21.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.21.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.19.manifest.json → agent-device-android-ime-helper-0.21.21.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.21.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.19.manifest.json → agent-device-android-snapshot-helper-0.21.21.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AppWindowScreenshot.swift +73 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/BackgroundInteraction.swift +557 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/GhostCursor.swift +141 -0
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/SnapshotTraversal.swift +107 -3
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +136 -22
- package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/BackgroundInteractionTests.swift +88 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +133 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +10 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +36 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +28 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +14 -16
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +67 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +6 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +7 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +21 -7
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +121 -17
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +179 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryConfirmation.swift +119 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +8 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +23 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +59 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +112 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +25 -12
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +6 -1
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +43 -13
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +20 -5
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +2 -15
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +10 -25
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +1 -18
- package/dist/src/adapter.js +1 -1
- package/dist/src/adb-executor.js +2 -2
- package/dist/src/adb-failure.js +1 -1
- package/dist/src/adb-transport.js +1 -1
- package/dist/src/agent-browser-lifecycle.js +1 -1
- package/dist/src/agent-browser-process-record.js +1 -1
- package/dist/src/agent-browser-provider.js +1 -1
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.js +1 -1
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/alert.js +1 -0
- package/dist/src/android-adb.d.ts +12 -0
- package/dist/src/android-input-ownership.js +1 -1
- package/dist/src/app-backend.js +1 -0
- package/dist/src/app-catalog.js +1 -1
- package/dist/src/app-deployment-resolution.js +1 -1
- package/dist/src/app-inventory.js +1 -1
- package/dist/src/app-launch.js +2 -2
- package/dist/src/app-lifecycle.js +2 -2
- package/dist/src/app-lifecycle2.js +1 -1
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/app-log-session-resource.js +1 -0
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/apple-runner-platform.js +1 -1
- package/dist/src/application-lifecycle-interaction.js +1 -1
- package/dist/src/archive.js +2 -2
- package/dist/src/artifact-download.js +1 -1
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/back-mode.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/boot-diagnostics.js +1 -1
- package/dist/src/browser-launch.js +1 -1
- package/dist/src/cache.js +1 -1
- package/dist/src/capabilities.js +1 -1
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +317 -323
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +4 -4
- package/dist/src/click-button.js +1 -1
- package/dist/src/client-metro-companion.js +1 -1
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-options.js +3 -0
- package/dist/src/client-types.d.ts +101 -6
- package/dist/src/clipboard-shell-response.js +1 -1
- package/dist/src/{scroll-command.d.ts → cloud-artifacts.d.ts} +249 -240
- package/dist/src/code-signature-cache.js +1 -1
- package/dist/src/code-signature.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-tools.js +2 -2
- package/dist/src/command.js +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/connection-runtime.js +1 -1
- package/dist/src/connection.js +5 -5
- package/dist/src/contracts.d.ts +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/daemon-artifacts.js +1 -0
- package/dist/src/daemon-client-lease-beat.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-client-liveness-probe.js +1 -0
- package/dist/src/daemon-client-transport.js +1 -1
- package/dist/src/daemon-http.js +1 -0
- package/dist/src/daemon-policy-file.js +1 -1
- package/dist/src/daemon-registration-owner.js +1 -0
- package/dist/src/daemon-registration.js +1 -1
- package/dist/src/daemon-resolution.js +1 -1
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +2 -2
- package/dist/src/debug-symbols-facade.js +3 -3
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -1
- package/dist/src/device-inventory-context.js +1 -1
- package/dist/src/device-readiness-runtime.js +1 -1
- package/dist/src/device-release.js +1 -1
- package/dist/src/device-rotation.js +1 -1
- package/dist/src/device-selection-resolver.js +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/device-shell.js +1 -1
- package/dist/src/device.js +1 -1
- package/dist/src/device2.js +1 -3
- package/dist/src/device3.js +3 -0
- package/dist/src/devicectl.js +1 -1
- package/dist/src/diagnostics.js +3 -3
- package/dist/src/dispatch-resolve.js +4 -1
- package/dist/src/display-inventory.js +1 -1
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/doctor2.js +1 -1
- package/dist/src/durable-capture-resource.js +1 -0
- package/dist/src/engine-eval-script.js +1 -1
- package/dist/src/error.js +1 -1
- package/dist/src/exec.js +1 -1
- package/dist/src/file.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/generic-settle.js +1 -1
- package/dist/src/generic.js +1 -1
- package/dist/src/gesture-admission.js +1 -1
- package/dist/src/gesture-plan.js +1 -1
- package/dist/src/gesture-runtime.js +1 -1
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/hdc.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/host-file.js +1 -1
- package/dist/src/host.js +1 -1
- package/dist/src/human-control-contract.js +1 -1
- package/dist/src/human-control.js +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -1
- package/dist/src/input-actions2.js +2 -2
- package/dist/src/install-artifact-facade.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/install-source.d.ts +5 -0
- package/dist/src/install-source2.js +1 -1
- package/dist/src/instance-client.js +1 -0
- package/dist/src/interaction-positionals.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-binding.js +1 -1
- package/dist/src/interactor.js +5 -5
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +1 -2
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.js +1 -1
- package/dist/src/inventory.js +4 -4
- package/dist/src/inventory2.js +1 -1
- package/dist/src/inventory3.js +1 -1
- package/dist/src/inventory5.js +1 -1
- package/dist/src/ios-client.js +4 -30
- package/dist/src/ios-settings.js +1 -0
- package/dist/src/ios-snapshot-engine.js +1 -1
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/launch-confirmation.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease-registry-scope.js +1 -0
- package/dist/src/lease-scope.js +1 -1
- package/dist/src/lease.js +1 -1
- package/dist/src/legacy-xctest-device-set.js +1 -1
- package/dist/src/limrun-download-file.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +78 -44
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/load.js +1 -0
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/macos-facade.js +1 -1
- package/dist/src/managed-device-scope.js +1 -1
- package/dist/src/mechanics.js +16 -16
- package/dist/src/observation.js +1 -1
- package/dist/src/observe-until.js +1 -1
- package/dist/src/overlay.js +2 -2
- package/dist/src/owner-identity.js +3 -3
- package/dist/src/path-resolution.js +1 -1
- package/dist/src/perf-facade.js +1 -1
- package/dist/src/perf-runtime-operation-builder.js +1 -1
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +1 -1
- package/dist/src/perf.js +1 -1
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-android-adb-host.js +1 -1
- package/dist/src/platform-runtime-app-log-process.js +1 -1
- package/dist/src/platform-runtime-host.js +1 -1
- package/dist/src/platform-runtime-managed-owner.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +2 -2
- package/dist/src/platform-runtime-runtime-hints.js +2 -2
- package/dist/src/platform-runtime-screen-recording-android-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-runner-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-apple-simulator-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-output-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -1
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/plugins.d.ts +9 -0
- package/dist/src/plugins.js +1 -0
- package/dist/src/plugins2.js +2 -0
- package/dist/src/png-crop-bytes.js +1 -1
- package/dist/src/png-size.js +1 -1
- package/dist/src/png-worker-client.js +1 -1
- package/dist/src/png.js +1 -1
- package/dist/src/prepare-kind.js +1 -1
- package/dist/src/process.js +1 -1
- package/dist/src/project-runtime.js +1 -1
- package/dist/src/provider-credential-fingerprint.js +1 -0
- package/dist/src/provider-device-admission.js +1 -1
- package/dist/src/provider-device-runtimes.js +1 -0
- package/dist/src/provider-limrun-credentials.js +1 -0
- package/dist/src/provider-profile-fields.js +1 -0
- package/dist/src/provider-session-ownership.js +2 -2
- package/dist/src/provider-webdriver.js +2 -1
- package/dist/src/providers.js +1 -1
- package/dist/src/proxy.js +1 -1
- package/dist/src/quality-warnings.js +1 -1
- package/dist/src/react-native.js +1 -1
- package/dist/src/record-runtime.js +1 -1
- package/dist/src/record-trace.js +1 -1
- package/dist/src/recording.js +1 -1
- package/dist/src/rect-center.js +1 -1
- package/dist/src/register-builtins.js +1 -1
- package/dist/src/registry.js +52 -36
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +1 -1
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +5 -5
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-cancel.js +1 -1
- package/dist/src/request-cancellation.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- package/dist/src/result-serialization.js +1 -1
- package/dist/src/retry.js +1 -1
- package/dist/src/runner-artifact-manifest.js +1 -1
- package/dist/src/runner-cache-metadata.js +3 -3
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-dev-tools-security.js +1 -1
- package/dist/src/runner-device-readiness.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-error-classification.js +2 -2
- package/dist/src/runner-exchange.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-session-types.js +1 -1
- package/dist/src/runner-start-budget.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime-admission.js +1 -1
- package/dist/src/runtime-transport-hints.js +1 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/runtime10.js +2 -2
- package/dist/src/runtime2.js +3 -3
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +5 -5
- package/dist/src/runtime5.js +1 -1
- package/dist/src/runtime6.js +1 -1
- package/dist/src/runtime7.js +1 -1
- package/dist/src/runtime8.js +1 -1
- package/dist/src/runtime9.js +1 -1
- package/dist/src/screen-recording-admission-ledger.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -1
- package/dist/src/screen-recording-options.js +1 -1
- package/dist/src/screen-recording-resource-recovery.js +1 -1
- package/dist/src/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-image.js +1 -1
- package/dist/src/screenshot-result.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot3.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/scroll-gesture.js +1 -1
- package/dist/src/sdk-batch-runner.js +2 -2
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +47 -2
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +37 -8
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.d.ts +2 -2
- package/dist/src/selectors.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-allocation.js +1 -1
- package/dist/src/session-artifact-paths.js +1 -1
- package/dist/src/session-repair-tombstone.js +1 -1
- package/dist/src/session-routing.js +1 -1
- package/dist/src/session-runtime-admission.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session-stream.js +27 -0
- package/dist/src/session.js +1 -1
- package/dist/src/session2.js +5 -5
- package/dist/src/settings.js +1 -1
- package/dist/src/settings2.js +1 -1
- package/dist/src/simctl-settings-facade.js +1 -0
- package/dist/src/simctl-settings.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-boot.js +1 -1
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-diagnostics.js +1 -1
- package/dist/src/snapshot-runtime-binding.js +1 -1
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-state.js +1 -1
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -1
- package/dist/src/src.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/src8.js +2 -2
- package/dist/src/store.js +1 -0
- package/dist/src/string-enum.js +1 -1
- package/dist/src/surface-snapshot.js +1 -1
- package/dist/src/takeover.js +1 -1
- package/dist/src/target-evidence.js +1 -1
- package/dist/src/telemetry.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider.js +3 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -1
- package/dist/src/toolchain-probe.js +2 -2
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/touch-runtime2.js +1 -1
- package/dist/src/transport.js +2 -2
- package/dist/src/tv-remote.js +1 -1
- package/dist/src/type-text-runtime.js +1 -1
- package/dist/src/update-check.js +1 -1
- package/dist/src/vars.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/video.js +1 -1
- package/dist/src/viewport.js +1 -1
- package/dist/src/web.js +1 -1
- package/dist/src/web2.js +1 -1
- package/dist/src/webdriver-source.js +1 -1
- package/package.json +5 -1
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.19.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.19.apk.sha256 +0 -1
- package/dist/src/api.js +0 -3
- package/dist/src/daemon-process.js +0 -1
- package/dist/src/multitouch-support.js +0 -1
- package/dist/src/parameterized-recorded-fill.js +0 -1
- package/dist/src/runner-startup-transport.js +0 -1
- package/dist/src/runner-xctestrun.js +0 -1
- package/dist/src/session-store.js +0 -4
|
@@ -5,7 +5,7 @@ final class TextInputProbeIssues {
|
|
|
5
5
|
var count = 0
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
enum TextInputProbeFailure: String {
|
|
8
|
+
enum TextInputProbeFailure: String, Error {
|
|
9
9
|
case recordedIssue = "text_input_probe_recorded_issue"
|
|
10
10
|
case exception = "text_input_probe_exception"
|
|
11
11
|
}
|
|
@@ -38,7 +38,60 @@ extension RunnerTests {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
func coordinateTapTextInputIdentityAt(app: XCUIApplication, x: Double, y: Double) -> TextInputAtPoint? {
|
|
44
|
+
let probed = containingTextInputProbeIssues(fallback: nil) { shouldStop -> TextInputAtPoint? in
|
|
45
|
+
guard let element = queryTextInputs(app: app, point: CGPoint(x: x, y: y), shouldStop: shouldStop).first,
|
|
46
|
+
case .input(let identity) = probeTextEntryInput(element)
|
|
47
|
+
else {
|
|
48
|
+
return nil
|
|
49
|
+
}
|
|
50
|
+
return TextInputAtPoint(element: element, identity: identity)
|
|
51
|
+
}
|
|
52
|
+
guard case .success(let input) = probed else { return nil }
|
|
53
|
+
return input
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
func textInputStillResolves(_ input: TextInputAtPoint) -> Bool {
|
|
59
|
+
let probed = containingTextInputProbeIssues(fallback: false) { _ in
|
|
60
|
+
input.element.exists && probeTextEntryInput(input.element) == .input(input.identity)
|
|
61
|
+
}
|
|
62
|
+
guard case .success(let resolves) = probed else { return false }
|
|
63
|
+
return resolves
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
func clearedFieldRead(app: XCUIApplication, target: TextEntryTarget) -> ClearedFieldRead {
|
|
69
|
+
let probed = containingTextInputProbeIssues(fallback: ClearedFieldRead.unavailable) { _ in
|
|
70
|
+
guard let input = resolveTextEntryElement(app: app, target: target) else { return .unavailable }
|
|
71
|
+
if input.elementType == .secureTextField { return .unreadable }
|
|
72
|
+
return editableTextValue(for: input, treatingPlaceholderAsEmpty: true).map { .text($0) } ?? .unavailable
|
|
73
|
+
}
|
|
74
|
+
guard case .success(let read) = probed else { return .unavailable }
|
|
75
|
+
return read
|
|
76
|
+
}
|
|
77
|
+
|
|
41
78
|
func probeTextInputs(app: XCUIApplication, point: CGPoint) -> TextInputProbeOutcome {
|
|
79
|
+
switch containingTextInputProbeIssues(fallback: [], { shouldStop in
|
|
80
|
+
queryTextInputs(app: app, point: point, shouldStop: shouldStop)
|
|
81
|
+
}) {
|
|
82
|
+
case .success(let elements):
|
|
83
|
+
return elements.isEmpty ? .absent : .matches(elements)
|
|
84
|
+
case .failure(let failure):
|
|
85
|
+
return .unavailable(failure)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
private func containingTextInputProbeIssues<T>(
|
|
92
|
+
fallback: T,
|
|
93
|
+
_ probe: (_ shouldStop: () -> Bool) -> T
|
|
94
|
+
) -> Result<T, TextInputProbeFailure> {
|
|
42
95
|
precondition(Thread.isMainThread)
|
|
43
96
|
let issues = TextInputProbeIssues()
|
|
44
97
|
suppressedIssueLock.lock()
|
|
@@ -50,12 +103,12 @@ extension RunnerTests {
|
|
|
50
103
|
textInputProbeIssues = previous
|
|
51
104
|
suppressedIssueLock.unlock()
|
|
52
105
|
}
|
|
53
|
-
let (
|
|
54
|
-
|
|
106
|
+
let (value, exception) = catchingObjCException(fallback: fallback) {
|
|
107
|
+
probe({ self.hasTextInputProbeIssues(issues) })
|
|
55
108
|
}
|
|
56
|
-
if hasTextInputProbeIssues(issues) { return .
|
|
57
|
-
if exception != nil { return .
|
|
58
|
-
return
|
|
109
|
+
if hasTextInputProbeIssues(issues) { return .failure(.recordedIssue) }
|
|
110
|
+
if exception != nil { return .failure(.exception) }
|
|
111
|
+
return .success(value)
|
|
59
112
|
}
|
|
60
113
|
|
|
61
114
|
private func hasTextInputProbeIssues(_ scope: TextInputProbeIssues) -> Bool {
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift
CHANGED
|
@@ -117,6 +117,7 @@ extension RunnerTests {
|
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
var entryBaseline: TextEntryObservation?
|
|
120
121
|
if repairMode == .replacement {
|
|
121
122
|
guard let replacementTarget = initialTarget else {
|
|
122
123
|
logTextEntryPhase(commandId: commandId, phase: "total", startedAt: totalStartedAt, chars: text.count, mode: repairMode)
|
|
@@ -134,6 +135,7 @@ extension RunnerTests {
|
|
|
134
135
|
mode: repairMode
|
|
135
136
|
)
|
|
136
137
|
}
|
|
138
|
+
entryBaseline = textEntryObservation(for: replacementTarget)
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
|
|
@@ -194,7 +196,7 @@ extension RunnerTests {
|
|
|
194
196
|
textEntryRoute = "xctest-element"
|
|
195
197
|
currentTarget.typeText(value)
|
|
196
198
|
return (currentTarget, nil)
|
|
197
|
-
} else if activeTarget.prefersFocusedElement && isKeyboardVisible(app: app) {
|
|
199
|
+
} else if activeTarget.boundIdentity == nil && activeTarget.prefersFocusedElement && isKeyboardVisible(app: app) {
|
|
198
200
|
#if os(iOS)
|
|
199
201
|
|
|
200
202
|
|
|
@@ -344,7 +346,8 @@ extension RunnerTests {
|
|
|
344
346
|
app: app,
|
|
345
347
|
target: activeTarget,
|
|
346
348
|
expectedText: expectedText,
|
|
347
|
-
repairMode: repairMode
|
|
349
|
+
repairMode: repairMode,
|
|
350
|
+
baseline: entryBaseline
|
|
348
351
|
)
|
|
349
352
|
logTextEntryPhase(
|
|
350
353
|
commandId: commandId,
|
|
@@ -390,14 +393,40 @@ extension RunnerTests {
|
|
|
390
393
|
app: XCUIApplication,
|
|
391
394
|
target: TextEntryTarget,
|
|
392
395
|
expectedText: String?,
|
|
393
|
-
repairMode: TextTypingRepairMode
|
|
396
|
+
repairMode: TextTypingRepairMode,
|
|
397
|
+
baseline: TextEntryObservation?
|
|
394
398
|
) -> TextEntryResult {
|
|
399
|
+
if target.boundIdentity != nil, resolveTextEntryElement(app: app, target: target) == nil {
|
|
400
|
+
guard boundTextEntryInputIsGone(app: app, target: target) else {
|
|
401
|
+
return TextEntryResult(
|
|
402
|
+
verified: nil,
|
|
403
|
+
repaired: false,
|
|
404
|
+
expectedText: expectedText,
|
|
405
|
+
observedText: nil,
|
|
406
|
+
failure: .commitNotObserved
|
|
407
|
+
)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_INPUT_REMOVED_AFTER_DELIVERY")
|
|
412
|
+
return TextEntryResult(verified: nil, repaired: false, expectedText: expectedText, observedText: nil)
|
|
413
|
+
}
|
|
395
414
|
let initialResult = verifyTextEntry(
|
|
396
415
|
app: app,
|
|
397
416
|
target: target,
|
|
398
417
|
expectedText: expectedText,
|
|
399
418
|
repaired: false
|
|
400
419
|
)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
if let unconfirmed = settledUnconfirmedTextEntry(
|
|
423
|
+
app: app,
|
|
424
|
+
target: target,
|
|
425
|
+
result: initialResult,
|
|
426
|
+
baseline: baseline
|
|
427
|
+
) {
|
|
428
|
+
return unconfirmed
|
|
429
|
+
}
|
|
401
430
|
#if os(iOS)
|
|
402
431
|
guard initialResult.verified == false,
|
|
403
432
|
let expectedText = initialResult.expectedText
|
|
@@ -417,6 +446,15 @@ extension RunnerTests {
|
|
|
417
446
|
repaired: false
|
|
418
447
|
)
|
|
419
448
|
}
|
|
449
|
+
guard Self.textEntryRepairCanTarget(boundIdentity: target.boundIdentity) else {
|
|
450
|
+
NSLog("AGENT_DEVICE_RUNNER_TEXT_ENTRY_REPAIR_REFUSED reason=unidentified-input")
|
|
451
|
+
return verifyTextEntry(
|
|
452
|
+
app: app,
|
|
453
|
+
target: target,
|
|
454
|
+
expectedText: expectedText,
|
|
455
|
+
repaired: false
|
|
456
|
+
)
|
|
457
|
+
}
|
|
420
458
|
|
|
421
459
|
guard let repairTarget = resolveTextEntryElement(app: app, target: target) else {
|
|
422
460
|
return initialResult
|
|
@@ -429,17 +467,83 @@ extension RunnerTests {
|
|
|
429
467
|
)
|
|
430
468
|
clearTextInput(repairTarget)
|
|
431
469
|
repairTarget.typeText(expectedText)
|
|
432
|
-
|
|
470
|
+
let repairedTarget = target.withElement(repairTarget)
|
|
471
|
+
let repairedResult = verifyTextEntry(
|
|
433
472
|
app: app,
|
|
434
|
-
target:
|
|
473
|
+
target: repairedTarget,
|
|
435
474
|
expectedText: expectedText,
|
|
436
475
|
repaired: true
|
|
437
476
|
)
|
|
477
|
+
return settledUnconfirmedTextEntry(
|
|
478
|
+
app: app,
|
|
479
|
+
target: repairedTarget,
|
|
480
|
+
result: repairedResult,
|
|
481
|
+
baseline: baseline
|
|
482
|
+
) ?? repairedResult
|
|
438
483
|
#else
|
|
439
484
|
return initialResult
|
|
440
485
|
#endif
|
|
441
486
|
}
|
|
442
487
|
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
private func settledUnconfirmedTextEntry(
|
|
491
|
+
app: XCUIApplication,
|
|
492
|
+
target: TextEntryTarget,
|
|
493
|
+
result: TextEntryResult,
|
|
494
|
+
baseline: TextEntryObservation?
|
|
495
|
+
) -> TextEntryResult? {
|
|
496
|
+
guard result.verified == false, let requested = result.expectedText, let baseline else {
|
|
497
|
+
return nil
|
|
498
|
+
}
|
|
499
|
+
func observe() -> TextEntryObservation? {
|
|
500
|
+
textEntryObservation(for: resolveTextEntryElement(app: app, target: target))
|
|
501
|
+
}
|
|
502
|
+
func evidence(_ observed: TextEntryObservation?) -> TextEntryUnconfirmedEvidence? {
|
|
503
|
+
Self.unconfirmedTextEntryEvidence(requested: requested, baseline: baseline, observed: observed)
|
|
504
|
+
}
|
|
505
|
+
let moveDeadline = Date().addingTimeInterval(TextEntryTiming.unconfirmedSettleCeiling)
|
|
506
|
+
var latest = observe()
|
|
507
|
+
while let unmoved = latest, unmoved.isSettled(with: baseline), Date() < moveDeadline {
|
|
508
|
+
sleepFor(TextEntryTiming.pollInterval)
|
|
509
|
+
latest = observe()
|
|
510
|
+
}
|
|
511
|
+
guard evidence(latest) != nil else {
|
|
512
|
+
return nil
|
|
513
|
+
}
|
|
514
|
+
let ceiling = Date().addingTimeInterval(TextEntryTiming.unconfirmedSettleCeiling)
|
|
515
|
+
var stableSince = Date()
|
|
516
|
+
while Date().timeIntervalSince(stableSince) < TextEntryTiming.verificationStabilityWindow {
|
|
517
|
+
guard Date() < ceiling else {
|
|
518
|
+
return nil
|
|
519
|
+
}
|
|
520
|
+
sleepFor(TextEntryTiming.pollInterval)
|
|
521
|
+
let next = observe()
|
|
522
|
+
if let next, let settled = latest, next.isSettled(with: settled) {
|
|
523
|
+
latest = next
|
|
524
|
+
continue
|
|
525
|
+
}
|
|
526
|
+
latest = next
|
|
527
|
+
stableSince = Date()
|
|
528
|
+
}
|
|
529
|
+
guard let unconfirmed = evidence(latest) else {
|
|
530
|
+
return nil
|
|
531
|
+
}
|
|
532
|
+
NSLog(
|
|
533
|
+
"AGENT_DEVICE_RUNNER_TEXT_ENTRY_UNCONFIRMED expectedLength=%d observedLength=%d repaired=%d",
|
|
534
|
+
requested.count,
|
|
535
|
+
unconfirmed.after.count,
|
|
536
|
+
result.repaired ? 1 : 0
|
|
537
|
+
)
|
|
538
|
+
return TextEntryResult(
|
|
539
|
+
verified: nil,
|
|
540
|
+
repaired: result.repaired,
|
|
541
|
+
expectedText: requested,
|
|
542
|
+
observedText: unconfirmed.after,
|
|
543
|
+
unconfirmed: unconfirmed
|
|
544
|
+
)
|
|
545
|
+
}
|
|
546
|
+
|
|
443
547
|
private func verifyTextEntry(
|
|
444
548
|
app: XCUIApplication,
|
|
445
549
|
target: TextEntryTarget,
|
|
@@ -503,18 +607,10 @@ extension RunnerTests {
|
|
|
503
607
|
if observedText == expectedText {
|
|
504
608
|
return true
|
|
505
609
|
}
|
|
506
|
-
guard
|
|
610
|
+
guard element?.elementType != .textView else {
|
|
507
611
|
return false
|
|
508
612
|
}
|
|
509
|
-
|
|
510
|
-
while hasTextEntrySubmitSuffix(submittedText) {
|
|
511
|
-
submittedText.removeLast()
|
|
512
|
-
}
|
|
513
|
-
return observedText == submittedText
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
private func hasTextEntrySubmitSuffix(_ text: String) -> Bool {
|
|
517
|
-
text.hasSuffix("\n") || text.hasSuffix("\r")
|
|
613
|
+
return observedText == Self.textEntryRequestWithoutSubmitKeys(expectedText)
|
|
518
614
|
}
|
|
519
615
|
|
|
520
616
|
private func expectedTextEntryValue(
|
|
@@ -611,13 +707,6 @@ extension RunnerTests {
|
|
|
611
707
|
guard missingCharacterCount <= max(2, expectedText.count / 4) else {
|
|
612
708
|
return false
|
|
613
709
|
}
|
|
614
|
-
|
|
615
|
-
for character in observedText {
|
|
616
|
-
guard let matchIndex = expectedText[expectedIndex...].firstIndex(of: character) else {
|
|
617
|
-
return false
|
|
618
|
-
}
|
|
619
|
-
expectedIndex = expectedText.index(after: matchIndex)
|
|
620
|
-
}
|
|
621
|
-
return true
|
|
710
|
+
return Self.isOrderedSubsequence(observedText, of: expectedText)
|
|
622
711
|
}
|
|
623
712
|
}
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift
CHANGED
|
@@ -27,6 +27,8 @@ extension RunnerTests {
|
|
|
27
27
|
hasY: command.y != nil,
|
|
28
28
|
xCTestChannelPenalized: xCTestChannelPenalized
|
|
29
29
|
), let x = command.x, let y = command.y {
|
|
30
|
+
|
|
31
|
+
let inputAtPoint = coordinateTapTextInputIdentityAt(app: activeApp, x: x, y: y)
|
|
30
32
|
let policyKind = SynthesizedGesturePolicyKind.coordinateTap
|
|
31
33
|
let context = synthesizedCoordinateContext(
|
|
32
34
|
app: activeApp,
|
|
@@ -40,7 +42,8 @@ extension RunnerTests {
|
|
|
40
42
|
resolvedCoordinateTarget = TextEntryTarget(
|
|
41
43
|
element: nil,
|
|
42
44
|
refreshPoint: CGPoint(x: x, y: y),
|
|
43
|
-
prefersFocusedElement: false
|
|
45
|
+
prefersFocusedElement: false,
|
|
46
|
+
inputAtRefreshPoint: inputAtPoint
|
|
44
47
|
)
|
|
45
48
|
case .xctestFallback:
|
|
46
49
|
break
|
|
@@ -120,17 +123,27 @@ extension RunnerTests {
|
|
|
120
123
|
|
|
121
124
|
frame = .zero
|
|
122
125
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
maestroNonHittableCoordinateFallbackUsed: maestroNonHittableCoordinateFallbackUsed,
|
|
132
|
-
textEntryRoute: textResult.textEntryRoute
|
|
133
|
-
)
|
|
126
|
+
var data = DataPayload(
|
|
127
|
+
message: textResult.repaired ? "typed after repair" : "typed",
|
|
128
|
+
x: point.map { Double($0.x) },
|
|
129
|
+
y: point.map { Double($0.y) },
|
|
130
|
+
referenceWidth: frame.isEmpty ? nil : Double(frame.width),
|
|
131
|
+
referenceHeight: frame.isEmpty ? nil : Double(frame.height),
|
|
132
|
+
maestroNonHittableCoordinateFallbackUsed: maestroNonHittableCoordinateFallbackUsed,
|
|
133
|
+
textEntryRoute: textResult.textEntryRoute
|
|
134
134
|
)
|
|
135
|
+
if let unconfirmed = textResult.unconfirmed {
|
|
136
|
+
data.verification = "unconfirmed"
|
|
137
|
+
data.requested = unconfirmed.requested
|
|
138
|
+
data.before = unconfirmed.before
|
|
139
|
+
data.after = unconfirmed.after
|
|
140
|
+
data.target = TextEntryVerificationTargetPayload(
|
|
141
|
+
resourceId: unconfirmed.target.identifier,
|
|
142
|
+
className: unconfirmed.target.elementType,
|
|
143
|
+
packageName: command.appBundleId,
|
|
144
|
+
rect: SnapshotRect(unconfirmed.target.frame)
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
return Response(ok: true, data: data)
|
|
135
148
|
}
|
|
136
149
|
}
|
|
@@ -89,9 +89,14 @@ func makeRecordingExporter(
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
let defaultRecordingExportTimeoutSeconds: Double = 120
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
92
96
|
|
|
93
97
|
func runRecordingExport(
|
|
94
98
|
_ exporter: AVAssetExportSession,
|
|
99
|
+
timeoutSeconds: Double = defaultRecordingExportTimeoutSeconds,
|
|
95
100
|
timeoutMessage: String,
|
|
96
101
|
failureMessage: String
|
|
97
102
|
) throws {
|
|
@@ -99,7 +104,7 @@ func runRecordingExport(
|
|
|
99
104
|
exporter.exportAsynchronously {
|
|
100
105
|
semaphore.signal()
|
|
101
106
|
}
|
|
102
|
-
if semaphore.wait(timeout: .now() +
|
|
107
|
+
if semaphore.wait(timeout: .now() + timeoutSeconds) == .timedOut {
|
|
103
108
|
exporter.cancelExport()
|
|
104
109
|
throw RecordingScriptError.exportFailed(timeoutMessage)
|
|
105
110
|
}
|
|
@@ -88,7 +88,10 @@ func run() throws {
|
|
|
88
88
|
let renderSize = resolvedRenderSize(for: sourceVideoTrack)
|
|
89
89
|
let videoComposition = AVMutableVideoComposition()
|
|
90
90
|
videoComposition.renderSize = renderSize
|
|
91
|
-
videoComposition.frameDuration = resolvedFrameDuration(
|
|
91
|
+
videoComposition.frameDuration = resolvedFrameDuration(
|
|
92
|
+
for: sourceVideoTrack,
|
|
93
|
+
maximumFrameRate: parsedArgs.maximumFrameRate
|
|
94
|
+
)
|
|
92
95
|
|
|
93
96
|
let instruction = AVMutableVideoCompositionInstruction()
|
|
94
97
|
instruction.timeRange = fullRange
|
|
@@ -145,6 +148,7 @@ func run() throws {
|
|
|
145
148
|
)
|
|
146
149
|
try runRecordingExport(
|
|
147
150
|
exporter,
|
|
151
|
+
timeoutSeconds: parsedArgs.timeoutSeconds,
|
|
148
152
|
timeoutMessage: "Touch overlay export timed out.",
|
|
149
153
|
failureMessage: "Touch overlay export failed."
|
|
150
154
|
)
|
|
@@ -157,10 +161,15 @@ func run() throws {
|
|
|
157
161
|
|
|
158
162
|
func parseArguments(
|
|
159
163
|
_ arguments: [String]
|
|
160
|
-
) throws -> (
|
|
164
|
+
) throws -> (
|
|
165
|
+
inputPath: String, outputPath: String, eventsPath: String, timeoutSeconds: Double,
|
|
166
|
+
maximumFrameRate: Int32
|
|
167
|
+
) {
|
|
161
168
|
var inputPath: String?
|
|
162
169
|
var outputPath: String?
|
|
163
170
|
var eventsPath: String?
|
|
171
|
+
var timeoutSeconds = defaultRecordingExportTimeoutSeconds
|
|
172
|
+
var maximumFrameRate = maximumCompositedFrameRate
|
|
164
173
|
var index = 0
|
|
165
174
|
|
|
166
175
|
while index < arguments.count {
|
|
@@ -185,6 +194,20 @@ func parseArguments(
|
|
|
185
194
|
throw RecordingScriptError.invalidArgs("--quality must be one of: medium, high")
|
|
186
195
|
}
|
|
187
196
|
index += 2
|
|
197
|
+
case "--timeout-ms":
|
|
198
|
+
let rawValue = try recordingOptionValue(arguments, nextIndex, "--timeout-ms")
|
|
199
|
+
guard let milliseconds = Double(rawValue), milliseconds > 0 else {
|
|
200
|
+
throw RecordingScriptError.invalidArgs("--timeout-ms must be a positive number")
|
|
201
|
+
}
|
|
202
|
+
timeoutSeconds = milliseconds / 1000
|
|
203
|
+
index += 2
|
|
204
|
+
case "--max-fps":
|
|
205
|
+
let rawValue = try recordingOptionValue(arguments, nextIndex, "--max-fps")
|
|
206
|
+
guard let framesPerSecond = Int32(rawValue), framesPerSecond > 0 else {
|
|
207
|
+
throw RecordingScriptError.invalidArgs("--max-fps must be a positive integer")
|
|
208
|
+
}
|
|
209
|
+
maximumFrameRate = min(framesPerSecond, maximumCompositedFrameRate)
|
|
210
|
+
index += 2
|
|
188
211
|
default:
|
|
189
212
|
throw RecordingScriptError.invalidArgs("Unknown argument: \(argument)")
|
|
190
213
|
}
|
|
@@ -192,10 +215,10 @@ func parseArguments(
|
|
|
192
215
|
|
|
193
216
|
guard let inputPath, let outputPath, let eventsPath else {
|
|
194
217
|
throw RecordingScriptError.invalidArgs(
|
|
195
|
-
"Usage: recording-overlay.swift --input <video> --output <video> --events <json> [--quality <medium|high>]"
|
|
218
|
+
"Usage: recording-overlay.swift --input <video> --output <video> --events <json> [--quality <medium|high>] [--timeout-ms <ms>] [--max-fps <n>]"
|
|
196
219
|
)
|
|
197
220
|
}
|
|
198
|
-
return (inputPath, outputPath, eventsPath)
|
|
221
|
+
return (inputPath, outputPath, eventsPath, timeoutSeconds, maximumFrameRate)
|
|
199
222
|
}
|
|
200
223
|
|
|
201
224
|
|
|
@@ -329,19 +352,26 @@ func frameMeanLuma(_ image: CGImage) -> Double? {
|
|
|
329
352
|
return total / Double(count)
|
|
330
353
|
}
|
|
331
354
|
|
|
332
|
-
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
let maximumCompositedFrameRate: Int32 = 30
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
func resolvedFrameDuration(for track: AVAssetTrack, maximumFrameRate: Int32) -> CMTime {
|
|
368
|
+
let shortest = CMTime(value: 1, timescale: maximumFrameRate)
|
|
333
369
|
let minFrameDuration = track.minFrameDuration
|
|
334
370
|
if minFrameDuration.isValid && !minFrameDuration.isIndefinite && minFrameDuration.seconds > 0 {
|
|
335
|
-
return minFrameDuration
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
let nominalFrameRate = track.nominalFrameRate
|
|
339
|
-
if nominalFrameRate > 0 {
|
|
340
|
-
let timescale = Int32(max(1, round(nominalFrameRate)))
|
|
341
|
-
return CMTime(value: 1, timescale: timescale)
|
|
371
|
+
return CMTimeMaximum(minFrameDuration, shortest)
|
|
342
372
|
}
|
|
343
373
|
|
|
344
|
-
return
|
|
374
|
+
return shortest
|
|
345
375
|
}
|
|
346
376
|
|
|
347
377
|
func overlayPoint(event: GestureEvent, x: Double, y: Double, renderSize: CGSize) -> CGPoint {
|
|
@@ -29,7 +29,7 @@ public struct SnapshotRect: Codable, Equatable {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
public struct RawAXNode: Equatable {
|
|
32
|
-
public
|
|
32
|
+
public private(set) var index: Int
|
|
33
33
|
public let type: String
|
|
34
34
|
public let label: String?
|
|
35
35
|
public let identifier: String?
|
|
@@ -42,10 +42,10 @@ public struct RawAXNode: Equatable {
|
|
|
42
42
|
public let selected: Bool?
|
|
43
43
|
/// Geometric actionability; `nil` when the capture has no viewport box to decide it against.
|
|
44
44
|
public var hittable: Bool?
|
|
45
|
-
public
|
|
46
|
-
public
|
|
47
|
-
public
|
|
48
|
-
public
|
|
45
|
+
public private(set) var depth: Int
|
|
46
|
+
public private(set) var parentIndex: Int?
|
|
47
|
+
public private(set) var hiddenContentAbove: Bool?
|
|
48
|
+
public private(set) var hiddenContentBelow: Bool?
|
|
49
49
|
public var actions: [String]?
|
|
50
50
|
|
|
51
51
|
public init(
|
|
@@ -91,6 +91,21 @@ public struct RawAXNode: Equatable {
|
|
|
91
91
|
return updated
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
func reindexed(index: Int, depth: Int, parentIndex: Int?) -> RawAXNode {
|
|
95
|
+
var updated = self
|
|
96
|
+
updated.index = index
|
|
97
|
+
updated.depth = depth
|
|
98
|
+
updated.parentIndex = parentIndex
|
|
99
|
+
return updated
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func addingHiddenContentHints(above: Bool, below: Bool) -> RawAXNode {
|
|
103
|
+
var updated = self
|
|
104
|
+
updated.hiddenContentAbove = hiddenContentAbove == true || above ? true : nil
|
|
105
|
+
updated.hiddenContentBelow = hiddenContentBelow == true || below ? true : nil
|
|
106
|
+
return updated
|
|
107
|
+
}
|
|
108
|
+
|
|
94
109
|
public var hasSemanticContent: Bool {
|
|
95
110
|
[label, identifier, value].contains {
|
|
96
111
|
!($0?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)
|
|
@@ -134,23 +134,10 @@ extension SnapshotPresentation {
|
|
|
134
134
|
return nodes.enumerated().map { offset, node in
|
|
135
135
|
let raw = node.raw
|
|
136
136
|
return SnapshotPresentationNode(
|
|
137
|
-
raw:
|
|
137
|
+
raw: raw.reindexed(
|
|
138
138
|
index: offset,
|
|
139
|
-
type: raw.type,
|
|
140
|
-
label: raw.label,
|
|
141
|
-
identifier: raw.identifier,
|
|
142
|
-
value: raw.value,
|
|
143
|
-
placeholder: raw.placeholder,
|
|
144
|
-
rect: raw.rect,
|
|
145
|
-
enabled: raw.enabled,
|
|
146
|
-
focused: raw.focused,
|
|
147
|
-
selected: raw.selected,
|
|
148
|
-
hittable: raw.hittable,
|
|
149
139
|
depth: max(0, raw.depth - depthOffset),
|
|
150
|
-
parentIndex: raw.parentIndex.flatMap { indexMap[$0] }
|
|
151
|
-
hiddenContentAbove: raw.hiddenContentAbove,
|
|
152
|
-
hiddenContentBelow: raw.hiddenContentBelow,
|
|
153
|
-
actions: raw.actions
|
|
140
|
+
parentIndex: raw.parentIndex.flatMap { indexMap[$0] }
|
|
154
141
|
),
|
|
155
142
|
effectiveRect: node.effectiveRect
|
|
156
143
|
)
|
|
@@ -191,33 +191,18 @@ public enum SnapshotVisibilityFold {
|
|
|
191
191
|
if decision.isIncluded {
|
|
192
192
|
let outIndex = kept.count
|
|
193
193
|
let outDepth = keptDepth + 1
|
|
194
|
+
var projected = node.reindexed(index: outIndex, depth: outDepth, parentIndex: keptIndex)
|
|
195
|
+
projected.hittable = node.parentIndex == nil
|
|
196
|
+
? false
|
|
197
|
+
: clippedHittability(
|
|
198
|
+
source: node.hittable,
|
|
199
|
+
enabled: node.enabled,
|
|
200
|
+
clippedFrame: decision.effectiveFrame,
|
|
201
|
+
viewport: viewport
|
|
202
|
+
)
|
|
194
203
|
kept.append(
|
|
195
204
|
SnapshotPresentationNode(
|
|
196
|
-
raw:
|
|
197
|
-
index: outIndex,
|
|
198
|
-
type: node.type,
|
|
199
|
-
label: node.label,
|
|
200
|
-
identifier: node.identifier,
|
|
201
|
-
value: node.value,
|
|
202
|
-
placeholder: node.placeholder,
|
|
203
|
-
rect: node.rect,
|
|
204
|
-
enabled: node.enabled,
|
|
205
|
-
focused: node.focused,
|
|
206
|
-
selected: node.selected,
|
|
207
|
-
hittable: node.parentIndex == nil
|
|
208
|
-
? false
|
|
209
|
-
: clippedHittability(
|
|
210
|
-
source: node.hittable,
|
|
211
|
-
enabled: node.enabled,
|
|
212
|
-
clippedFrame: decision.effectiveFrame,
|
|
213
|
-
viewport: viewport
|
|
214
|
-
),
|
|
215
|
-
depth: outDepth,
|
|
216
|
-
parentIndex: keptIndex,
|
|
217
|
-
hiddenContentAbove: node.hiddenContentAbove,
|
|
218
|
-
hiddenContentBelow: node.hiddenContentBelow,
|
|
219
|
-
actions: node.actions
|
|
220
|
-
),
|
|
205
|
+
raw: projected,
|
|
221
206
|
effectiveRect: SnapshotGeometry.snapshotRect(
|
|
222
207
|
from: decision.effectiveFrame,
|
|
223
208
|
reportedFrame: rect
|
|
@@ -73,24 +73,7 @@ extension SnapshotVisibilityFold {
|
|
|
73
73
|
let node = presentationNode.raw
|
|
74
74
|
guard let hint = hints[node.index] else { return presentationNode }
|
|
75
75
|
return SnapshotPresentationNode(
|
|
76
|
-
raw:
|
|
77
|
-
index: node.index,
|
|
78
|
-
type: node.type,
|
|
79
|
-
label: node.label,
|
|
80
|
-
identifier: node.identifier,
|
|
81
|
-
value: node.value,
|
|
82
|
-
placeholder: node.placeholder,
|
|
83
|
-
rect: node.rect,
|
|
84
|
-
enabled: node.enabled,
|
|
85
|
-
focused: node.focused,
|
|
86
|
-
selected: node.selected,
|
|
87
|
-
hittable: node.hittable,
|
|
88
|
-
depth: node.depth,
|
|
89
|
-
parentIndex: node.parentIndex,
|
|
90
|
-
hiddenContentAbove: node.hiddenContentAbove == true || hint.above ? true : nil,
|
|
91
|
-
hiddenContentBelow: node.hiddenContentBelow == true || hint.below ? true : nil,
|
|
92
|
-
actions: node.actions
|
|
93
|
-
),
|
|
76
|
+
raw: node.addingHiddenContentHints(above: hint.above, below: hint.below),
|
|
94
77
|
effectiveRect: presentationNode.effectiveRect
|
|
95
78
|
)
|
|
96
79
|
}
|