agent-device 0.20.10 → 0.21.1
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/README.md +2 -2
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.10.apk → agent-device-android-ime-helper-0.21.1.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.1.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.10.manifest.json → agent-device-android-ime-helper-0.21.1.manifest.json} +4 -4
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.1.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.1.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.10.manifest.json → agent-device-android-snapshot-helper-0.21.1.manifest.json} +6 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/AudioProbe.swift +35 -33
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +6 -1
- package/apple/snapshot-bridge/LICENSE.idb +23 -0
- package/apple/snapshot-bridge/README.md +106 -0
- package/apple/snapshot-bridge/SnapshotBridge.m +286 -0
- package/apple/snapshot-bridge/SnapshotBridgeCapture.h +25 -0
- package/apple/snapshot-bridge/SnapshotBridgeCapture.m +138 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.h +34 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +411 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +58 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.h +12 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAXSnapshotBridge.m +20 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAlertVerification.swift +36 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSelectorMatchPolicy.swift +15 -15
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerStringNormalization.swift +8 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +12 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +100 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +72 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +63 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +677 -83
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +35 -92
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AlertObservation.swift +124 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +39 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +1058 -213
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +296 -14
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Exceptions.swift +10 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +309 -149
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +101 -42
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +24 -17
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +124 -199
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +71 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXElementTypes.swift +12 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +211 -78
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +30 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +254 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +206 -22
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +465 -494
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +168 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +802 -247
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationInvariant.swift +19 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +185 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +83 -5
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +156 -34
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +5 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +35 -318
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +206 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryReadiness.swift +158 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +28 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputProbe.swift +101 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +56 -23
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +56 -27
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +30 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +126 -80
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/RecordingExportSupport.swift +111 -0
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +47 -86
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +32 -79
- package/dist/apple/snapshot-presentation/Package.swift +21 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotGeometry.swift +56 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotModels.swift +259 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentation.swift +153 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationFailure.swift +27 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationInvariant.swift +91 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotPresentationProjection.swift +161 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotScopePolicy.swift +53 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFold.swift +242 -0
- package/dist/apple/snapshot-presentation/Sources/AgentDeviceSnapshotPresentation/SnapshotVisibilityFoldProjection.swift +97 -0
- package/dist/src/adapter.js +1 -0
- package/dist/src/adb-executor.js +2 -0
- package/dist/src/adb-failure.js +1 -0
- package/dist/src/adb-host.js +1 -0
- package/dist/src/adb.js +1 -0
- package/dist/src/agent-browser-lifecycle.js +1 -0
- package/dist/src/agent-browser-process-record.js +1 -0
- package/dist/src/agent-browser-provider.js +1 -0
- package/dist/src/agent-browser-tool.js +1 -1
- package/dist/src/agent-device-client.js +2 -2
- package/dist/src/ai-sdk.d.ts +2 -2
- package/dist/src/ai-sdk.js +1 -1
- package/dist/src/alert-contract.js +1 -0
- package/dist/src/alert-runtime.js +1 -0
- package/dist/src/android-adb.d.ts +27 -19
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-input-ownership.js +1 -0
- package/dist/src/android-system-chrome.js +1 -0
- package/dist/src/android.js +1 -1
- package/dist/src/api.js +11 -0
- package/dist/src/app-catalog.js +1 -0
- package/dist/src/app-deployment-resolution.js +2 -0
- package/dist/src/app-helpers.js +1 -1
- package/dist/src/app-inventory-contract.js +1 -0
- package/dist/src/app-inventory.js +1 -0
- package/dist/src/app-launch.js +2 -0
- package/dist/src/app-lifecycle-facade.js +1 -0
- package/dist/src/app-lifecycle.js +3 -6
- package/dist/src/app-lifecycle2.js +2 -2
- package/dist/src/app-lifecycle3.js +1 -0
- package/dist/src/app-log-files.js +1 -1
- package/dist/src/app-log-reconnect.js +1 -1
- package/dist/src/app-log-runtime.js +1 -4
- package/dist/src/app-log-runtime2.js +4 -0
- package/dist/src/app-parsers.js +4 -0
- package/dist/src/app-resolution-cache.js +1 -0
- package/dist/src/app-resolution-facade.js +1 -0
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/app-state.js +1 -2
- package/dist/src/apple-runner-platform.js +1 -0
- package/dist/src/application-lifecycle-interaction.js +1 -0
- package/dist/src/application-lifecycle-runtime.js +1 -0
- package/dist/src/apps-simctl.js +1 -0
- package/dist/src/archive.js +4 -0
- package/dist/src/artifact-download.js +1 -0
- package/dist/src/artifacts.d.ts +6 -2
- package/dist/src/artifacts.js +1 -1
- package/dist/src/async-lifecycle.js +1 -0
- package/dist/src/audio-probe-result.js +1 -0
- package/dist/src/audio-probe-runtime.js +1 -0
- package/dist/src/audio-probe-support.js +1 -0
- package/dist/src/auth-session.js +1 -1
- package/dist/src/auth.js +1 -1
- package/dist/src/backend-snapshot-options.js +1 -1
- package/dist/src/{url.js → base-url.js} +1 -1
- package/dist/src/boot-diagnostics.js +2 -2
- package/dist/src/byte-limit-stream.js +1 -1
- package/dist/src/capabilities.js +1 -0
- package/dist/src/capture.js +1 -0
- package/dist/src/catalog.js +1 -0
- package/dist/src/cli-command-aliases.js +1 -0
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +74 -51
- package/dist/src/cli-output.js +1 -1
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +4 -6
- package/dist/src/click-button.js +1 -0
- package/dist/src/client-metro-companion.js +1 -0
- package/dist/src/client-metro.js +1 -1
- package/dist/src/client-types.d.ts +280 -242
- package/dist/src/clipboard.js +1 -0
- package/dist/src/code-signature-cache.js +1 -0
- package/dist/src/code-signature.js +1 -0
- package/dist/src/color.js +1 -0
- package/dist/src/command-metadata.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-surface.js +1 -1
- package/dist/src/command-tools.js +2 -2
- package/dist/src/command.js +1 -0
- package/dist/src/compatibility-policy.js +1 -0
- package/dist/src/config.js +1 -1
- package/dist/src/config2.js +1 -0
- 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-client-lifecycle.js +1 -0
- package/dist/src/daemon-process.js +1 -0
- package/dist/src/daemon-registration.js +1 -0
- package/dist/src/daemon-shutdown-report.js +1 -1
- package/dist/src/daemon.js +2 -2
- package/dist/src/debug-symbols-facade.js +5 -0
- package/dist/src/deploy-result-target.js +1 -0
- package/dist/src/device-claim-inspection.js +1 -1
- package/dist/src/device-claim-rule.js +1 -0
- package/dist/src/device-input-state.d.ts +190 -3
- package/dist/src/device-inventory-context.js +1 -0
- package/dist/src/device-isolation.js +1 -0
- package/dist/src/device-release.js +1 -0
- package/dist/src/device-rotation.js +1 -0
- package/dist/src/device-selection-resolver.js +1 -0
- package/dist/src/device-session.js +1 -0
- package/dist/src/device.js +1 -1
- package/dist/src/device2.js +3 -2
- package/dist/src/diagnostics.js +3 -0
- package/dist/src/diagnostics2.js +1 -0
- package/dist/src/dispatch-resolve.js +1 -0
- package/dist/src/doctor-facade.js +1 -0
- package/dist/src/doctor-output.js +1 -0
- package/dist/src/doctor.js +1 -0
- package/dist/src/doctor2.js +1 -0
- package/dist/src/doctor3.js +1 -0
- package/dist/src/durable-resource.js +1 -0
- package/dist/src/entities.js +1 -1
- package/dist/src/error.js +2 -0
- package/dist/src/exec.js +1 -0
- package/dist/src/file.js +1 -0
- package/dist/src/find.js +1 -1
- package/dist/src/finders.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 -0
- package/dist/src/gesture-plan-types.js +1 -0
- package/dist/src/gesture-plan.js +1 -0
- package/dist/src/gesture-runtime.js +1 -0
- 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 -0
- package/dist/src/human-control-contract.js +1 -0
- package/dist/src/human-control.js +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/input-actions.js +1 -4
- package/dist/src/input-actions2.js +2 -1
- package/dist/src/install-artifact-facade.js +1 -0
- package/dist/src/install-source-network-transport.js +1 -0
- package/dist/src/install-source.d.ts +3 -10
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-positionals.js +1 -0
- package/dist/src/interaction-ref-policy.js +1 -0
- package/dist/src/interaction.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-catalog.js +1 -0
- package/dist/src/interactor-types.js +1 -0
- package/dist/src/interactor.js +6 -2
- package/dist/src/interactor2.js +1 -1
- package/dist/src/interactors.js +1 -1
- package/dist/src/internal/bin.d.ts +1 -1
- package/dist/src/internal/bin.js +1 -2
- package/dist/src/internal/companion-tunnel.d.ts +1 -1
- package/dist/src/internal/companion-tunnel.js +1 -1
- package/dist/src/internal/daemon.d.ts +1 -1
- package/dist/src/internal/daemon.js +2 -4
- package/dist/src/internal/png-worker.d.ts +4 -4
- package/dist/src/internal/png-worker.js +1 -1
- package/dist/src/internal/run-script-http-child.d.ts +4 -0
- package/dist/src/internal/run-script-http-child.js +1 -0
- package/dist/src/internal/update-check-entry.d.ts +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/inventory6.js +1 -1
- package/dist/src/ios-client.js +16 -0
- package/dist/src/ios-snapshot-acquisition.js +1 -0
- package/dist/src/ios-snapshot-adapter.js +1 -0
- package/dist/src/ios-snapshot-planning.js +1 -0
- package/dist/src/ios-snapshot-runtime.js +1 -0
- package/dist/src/ios-system-surface.js +1 -0
- package/dist/src/json.js +1 -0
- package/dist/src/keyboard-actions.js +1 -0
- package/dist/src/launch-console.js +1 -0
- package/dist/src/lease-context.js +1 -1
- package/dist/src/lease-scope.js +1 -0
- package/dist/src/lease.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +1610 -7
- package/dist/src/limrun.js +1 -1
- package/dist/src/linux.js +1 -1
- package/dist/src/local-interactor-operation-set.js +1 -0
- package/dist/src/location-coordinates.js +1 -1
- package/dist/src/logcat.js +1 -1
- package/dist/src/macos-facade.js +1 -0
- package/dist/src/managed-device-scope.js +1 -0
- package/dist/src/mechanics.js +19 -0
- package/dist/src/metro.d.ts +4 -2
- package/dist/src/metro.js +1 -1
- package/dist/src/metro2.js +1 -1
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/multitouch-support.js +1 -0
- package/dist/src/numeric.js +1 -0
- package/dist/src/observability.js +1 -1
- package/dist/src/observation.js +2 -0
- package/dist/src/open-target-resolution.js +1 -0
- package/dist/src/output-path.js +1 -1
- package/dist/src/owner-identity.js +3 -1
- package/dist/src/parameterized-recorded-fill.js +1 -0
- package/dist/src/parser.js +1 -1
- package/dist/src/perf-facade.js +2 -0
- package/dist/src/perf-process-identity.js +1 -0
- package/dist/src/perf-runtime-operation-builder.js +1 -0
- package/dist/src/perf-runtime-plan.js +1 -0
- package/dist/src/perf-runtime.js +1 -0
- package/dist/src/perf.js +1 -4
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/physical-device-facade.js +1 -0
- package/dist/src/platform-request-scope.js +1 -0
- package/dist/src/platform-runtime-android-adb-host.js +1 -0
- package/dist/src/platform-runtime-android-mechanics.js +1 -0
- package/dist/src/platform-runtime-app-log-android-transport.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 -0
- package/dist/src/platform-runtime-network-web-transport.js +1 -1
- package/dist/src/platform-runtime-open-target.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +4 -4
- 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-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-apple-transport.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-harmony-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-process-host.js +1 -0
- package/dist/src/platform-runtime-screen-recording-web-host.js +1 -1
- package/dist/src/platform-runtime-unavailable.js +1 -0
- package/dist/src/platform-runtime.js +1 -1
- package/dist/src/platform-runtime2.js +1 -1
- package/dist/src/plist.js +1 -1
- package/dist/src/png-worker-contract.js +1 -1
- package/dist/src/prepare-kind.js +1 -0
- package/dist/src/process-exit.js +1 -1
- package/dist/src/process.js +1 -0
- package/dist/src/provider-device-runtime.js +1 -0
- package/dist/src/provider-session-ownership.js +2 -0
- package/dist/src/provider-webdriver.js +1 -1
- package/dist/src/provider.js +1 -1
- package/dist/src/providers.js +1 -0
- package/dist/src/proxy.js +2 -2
- package/dist/src/react-native-overlay.js +1 -0
- 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/rect-center.js +1 -0
- package/dist/src/register-builtins.js +1 -0
- package/dist/src/registry.js +40 -28
- package/dist/src/remote-config2.js +1 -1
- package/dist/src/replay-divergence.js +2 -0
- package/dist/src/replay.js +2 -2
- package/dist/src/reporting.js +8 -7
- package/dist/src/request-admission.js +1 -0
- package/dist/src/request-cancel.js +1 -0
- package/dist/src/request-cancellation.js +1 -0
- package/dist/src/request-progress-protocol.js +1 -0
- package/dist/src/request-providers.js +1 -0
- package/dist/src/request-runtime-binding.js +1 -0
- package/dist/src/request.js +1 -0
- package/dist/src/result-serialization.js +1 -0
- package/dist/src/retry.js +1 -0
- package/dist/src/rolldown-runtime.js +1 -1
- package/dist/src/runner-cache-metadata.js +2 -0
- package/dist/src/runner-client.js +1 -1
- package/dist/src/runner-disposal.js +1 -1
- package/dist/src/runner-operations-facade.js +1 -0
- package/dist/src/runner-owner-facade.js +1 -0
- package/dist/src/runner-owner-state.js +1 -0
- package/dist/src/runner-presentation.js +1 -0
- package/dist/src/runner.js +1 -0
- package/dist/src/{runtime-transport.js → runtime-transport-hints.js} +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime2.js +4 -4
- package/dist/src/runtime3.js +1 -1
- package/dist/src/runtime4.js +5 -3
- 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/scoped-provider.js +1 -1
- package/dist/src/screen-recording-completion.js +1 -0
- package/dist/src/screen-recording-live-handle.js +1 -0
- package/dist/src/screen-recording-options.js +1 -0
- package/dist/src/screen-recording-resource-recovery.js +1 -0
- package/dist/src/screen-recording-runtime.js +1 -0
- package/dist/src/screenshot-density.js +1 -1
- package/dist/src/screenshot-result.js +1 -6
- package/dist/src/screenshot-runtime.js +1 -0
- package/dist/src/screenshot.js +1 -1
- package/dist/src/screenshot2.js +1 -0
- package/dist/src/screenshot3.js +5 -0
- package/dist/src/script.js +1 -0
- package/dist/src/scroll-command.js +1 -0
- package/dist/src/scroll-gesture.js +1 -0
- package/dist/src/scroll-indicator.js +1 -0
- package/dist/src/sdk-batch-runner.d.ts +23 -6
- package/dist/src/sdk-batch-runner.js +2 -3
- package/dist/src/sdk-batch.js +2 -0
- package/dist/src/sdk-contracts.d.ts +170 -41
- package/dist/src/sdk-contracts.js +2 -2
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-finders.d.ts +1 -1
- package/dist/src/sdk-finders.js +1 -1
- package/dist/src/sdk-io.js +1 -1
- package/dist/src/sdk-remote-config.d.ts +1 -1
- package/dist/src/sdk-remote-config.js +1 -1
- package/dist/src/sdk-selectors.d.ts +524 -140
- package/dist/src/sdk-selectors.js +1 -1
- package/dist/src/selection.js +1 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/selectors.js +1 -1
- package/dist/src/semantic-index.js +1 -0
- package/dist/src/server.js +4 -4
- package/dist/src/session-allocation.js +1 -0
- package/dist/src/session-artifact-paths.js +1 -0
- package/dist/src/session-observation.js +1 -0
- package/dist/src/session-paths.js +1 -0
- package/dist/src/session-repair-tombstone.js +1 -0
- package/dist/src/session-routing.js +1 -0
- package/dist/src/session-runtime-admission.js +1 -0
- package/dist/src/session-snapshot.js +1 -0
- package/dist/src/session-store.js +4 -0
- package/dist/src/session-target-evidence.js +1 -1
- package/dist/src/session2.js +5 -27
- package/dist/src/settings.js +1 -0
- package/dist/src/shared.js +2 -2
- package/dist/src/simctl-facade.js +1 -0
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-facade.js +1 -0
- package/dist/src/simulator.js +1 -1
- package/dist/src/snapshot-capture-annotations.js +1 -0
- package/dist/src/snapshot-desktop-projection.js +1 -0
- package/dist/src/snapshot-diagnostics.js +1 -0
- package/dist/src/snapshot-process.js +1 -0
- package/dist/src/snapshot-quality-backend-capabilities.js +1 -0
- package/dist/src/snapshot-quality-verdict.js +1 -0
- package/dist/src/snapshot-runtime-binding.js +1 -0
- package/dist/src/snapshot-runtime.js +1 -1
- package/dist/src/snapshot-scope.js +1 -1
- package/dist/src/snapshot-state.js +1 -0
- package/dist/src/snapshot.js +1 -8
- package/dist/src/snapshot2.js +1 -1
- package/dist/src/snapshot3.js +1 -1
- package/dist/src/snapshot4.js +1 -0
- package/dist/src/src.js +1 -1
- package/dist/src/src2.js +1 -1
- package/dist/src/src3.js +1 -2
- package/dist/src/src4.js +1 -1
- package/dist/src/src5.js +1 -0
- package/dist/src/src6.js +1 -0
- package/dist/src/src7.js +2 -0
- package/dist/src/src8.js +115 -0
- package/dist/src/startup-recovery-fence.js +1 -0
- package/dist/src/status-markers.js +1 -0
- package/dist/src/string-enum.js +1 -1
- package/dist/src/success-text.js +1 -0
- package/dist/src/surface-snapshot.js +1 -0
- package/dist/src/surface-snapshot2.js +1 -0
- package/dist/src/takeover.js +5 -0
- package/dist/src/tool-provider-facade.js +1 -0
- package/dist/src/tool-provider.js +4 -3
- package/dist/src/tool-provider2.js +1 -1
- package/dist/src/tool-provider3.js +1 -1
- package/dist/src/toolchain-probe.js +2 -0
- package/dist/src/touch-reference-frame.js +1 -0
- package/dist/src/touch-runtime.js +1 -0
- package/dist/src/transport.js +3 -0
- package/dist/src/tree.js +1 -0
- package/dist/src/ttl-memo.js +1 -0
- package/dist/src/tv-remote.js +1 -0
- package/dist/src/type-text-runtime.js +1 -0
- package/dist/src/undici.js +99 -0
- package/dist/src/update-check.js +1 -1
- package/dist/src/verified-file.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/video.js +2 -2
- package/dist/src/web.js +2 -1
- package/dist/src/web2.js +1 -0
- package/dist/src/webdriver-ios-snapshot.js +1 -0
- package/dist/src/webdriver-source.js +1 -0
- package/dist/src/window-state.js +1 -0
- package/linux/atspi-dump.py +54 -9
- package/package.json +58 -35
- package/server.json +9 -3
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.10.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.10.apk.sha256 +0 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CoordinateTextEntryTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+FlatSnapshotFiltering.swift +0 -168
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+LifecycleCacheTests.swift +0 -6
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+RecordingTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SelectorMatchPolicyTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentation.swift +0 -183
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotPresentationTests.swift +0 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTraversalIdentityTests.swift +0 -4
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryPolicyTests.swift +0 -4
- package/dist/src/appearance.js +0 -1
- package/dist/src/apps.js +0 -5
- package/dist/src/audio-probe.js +0 -1
- package/dist/src/cli-grammar.js +0 -1
- package/dist/src/command-catalog.js +0 -1
- package/dist/src/debug-symbols.js +0 -5
- package/dist/src/device-input-state.js +0 -2
- package/dist/src/device-ready.js +0 -1
- package/dist/src/dispatch.js +0 -1
- package/dist/src/handler-utils.js +0 -1
- package/dist/src/helper-package-install.js +0 -1
- package/dist/src/host-process.js +0 -3
- package/dist/src/ime-lifecycle.js +0 -2
- package/dist/src/ime-recovery-marker.js +0 -1
- package/dist/src/input-actions3.js +0 -1
- package/dist/src/install-artifact.js +0 -1
- package/dist/src/install-artifact2.js +0 -1
- package/dist/src/interaction-common.js +0 -1
- package/dist/src/interaction-runtime.js +0 -1
- package/dist/src/interaction-snapshot.js +0 -1
- package/dist/src/manifest.js +0 -1
- package/dist/src/method-scope.js +0 -1
- package/dist/src/png-resize.js +0 -1
- package/dist/src/process-lock.js +0 -1
- package/dist/src/runner-lease.js +0 -1
- package/dist/src/runner-sequence.js +0 -1
- package/dist/src/script-source-bundle.js +0 -16
- package/dist/src/sdk-android-adb.d.ts +0 -245
- package/dist/src/sdk-android-adb.js +0 -4
- package/dist/src/sdk.js +0 -1
- package/dist/src/setting-state.js +0 -1
- package/dist/src/shell-quote.js +0 -1
- package/dist/src/snapshot-session.js +0 -1
- package/dist/src/timing-safe-equal.js +0 -1
- package/dist/src/unsupported-interactor.js +0 -1
- package/dist/src/verdict.js +0 -1
- /package/dist/src/{recording-telemetry.js → telemetry.js} +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#import "SnapshotBridgeCapture.h"
|
|
2
|
+
|
|
3
|
+
static NSString *const attributesKey = @"UIAccessibilitySnapshotKeyAttributes";
|
|
4
|
+
static NSString *const childrenKey = @"UIAccessibilitySnapshotKeyChildren";
|
|
5
|
+
static NSString *const childCountKey = @"UIAccessibilitySnapshotKeyChildrenCount";
|
|
6
|
+
static NSString *const elementKey = @"UIAccessibilitySnapshotKeyElement";
|
|
7
|
+
static const NSUInteger maximumRequests = 32;
|
|
8
|
+
|
|
9
|
+
@interface SnapshotTreeCapture : NSObject
|
|
10
|
+
@property(nonatomic, copy) SnapshotElementReader reader;
|
|
11
|
+
@property(nonatomic) NSUInteger acceptedDepth;
|
|
12
|
+
@property(nonatomic) NSUInteger remainingNodes;
|
|
13
|
+
@property(nonatomic) NSUInteger maximumNodes;
|
|
14
|
+
@property(nonatomic) NSUInteger requests;
|
|
15
|
+
@property(nonatomic) NSUInteger rejected;
|
|
16
|
+
@property(nonatomic) BOOL truncated;
|
|
17
|
+
- (nullable NSDictionary *)read:(id)element depth:(NSUInteger)depth error:(NSError **)error;
|
|
18
|
+
- (nullable NSDictionary *)materialize:(NSDictionary *)tree depth:(NSUInteger)depth nativeLevels:(NSUInteger)nativeLevels error:(NSError **)error;
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation SnapshotTreeCapture
|
|
22
|
+
- (nullable NSDictionary *)read:(id)element depth:(NSUInteger)depth error:(NSError **)error
|
|
23
|
+
{
|
|
24
|
+
NSUInteger attemptDepth = MIN(depth, self.acceptedDepth);
|
|
25
|
+
for (NSUInteger retries = 0;; retries++) {
|
|
26
|
+
if (self.requests >= maximumRequests) {
|
|
27
|
+
if (error) *error = [NSError errorWithDomain:@"agent-device.snapshot" code:1
|
|
28
|
+
userInfo:@{NSLocalizedDescriptionKey: @"snapshot continuation request budget exhausted"}];
|
|
29
|
+
return nil;
|
|
30
|
+
}
|
|
31
|
+
self.requests++;
|
|
32
|
+
NSError *failure = nil;
|
|
33
|
+
id tree = self.reader(element, attemptDepth, MIN(self.maximumNodes, self.remainingNodes + 1), &failure);
|
|
34
|
+
if (tree) return tree;
|
|
35
|
+
NSNumber *nativeCode = failure.userInfo[@"accessibility-error"];
|
|
36
|
+
BOOL rejected = ([nativeCode isKindOfClass:NSNumber.class] && nativeCode.integerValue == -25201) ||
|
|
37
|
+
([failure.domain isEqualToString:@"com.apple.dt.xctest.automation-support.error"] && failure.code == 5);
|
|
38
|
+
if (rejected) self.rejected++;
|
|
39
|
+
if (!rejected || attemptDepth <= 1 || retries >= 2) {
|
|
40
|
+
if (error) *error = failure;
|
|
41
|
+
return nil;
|
|
42
|
+
}
|
|
43
|
+
attemptDepth = MAX(1, attemptDepth / 2);
|
|
44
|
+
self.acceptedDepth = attemptDepth;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
- (nullable NSDictionary *)materialize:(NSDictionary *)tree depth:(NSUInteger)depth nativeLevels:(NSUInteger)nativeLevels error:(NSError **)error
|
|
49
|
+
{
|
|
50
|
+
if (![tree isKindOfClass:NSDictionary.class] ||
|
|
51
|
+
![tree[attributesKey] isKindOfClass:NSDictionary.class] ||
|
|
52
|
+
![tree[childrenKey] isKindOfClass:NSArray.class]) {
|
|
53
|
+
if (error) *error = [NSError errorWithDomain:@"agent-device.snapshot" code:2
|
|
54
|
+
userInfo:@{NSLocalizedDescriptionKey: @"malformed snapshot continuation"}];
|
|
55
|
+
return nil;
|
|
56
|
+
}
|
|
57
|
+
if (self.remainingNodes == 0) {
|
|
58
|
+
self.truncated = YES;
|
|
59
|
+
return nil;
|
|
60
|
+
}
|
|
61
|
+
self.remainingNodes--;
|
|
62
|
+
NSArray *children = tree[childrenKey];
|
|
63
|
+
NSNumber *childCount = tree[childCountKey];
|
|
64
|
+
BOOL knownChildCount = [childCount isKindOfClass:NSNumber.class] && childCount.doubleValue >= 0 &&
|
|
65
|
+
childCount.doubleValue == (double)childCount.unsignedIntegerValue;
|
|
66
|
+
if (nativeLevels <= 1 && !knownChildCount && depth <= 1) self.truncated = YES;
|
|
67
|
+
if (depth > 1 && nativeLevels <= 1 && !knownChildCount) {
|
|
68
|
+
if (error) *error = [NSError errorWithDomain:@"agent-device.snapshot" code:6
|
|
69
|
+
userInfo:@{NSLocalizedDescriptionKey: @"snapshot boundary child count unavailable"}];
|
|
70
|
+
return nil;
|
|
71
|
+
}
|
|
72
|
+
BOOL withheld = knownChildCount && childCount.unsignedIntegerValue > children.count;
|
|
73
|
+
if (depth <= 1 || self.remainingNodes == 0) {
|
|
74
|
+
self.truncated |= children.count > 0 || withheld;
|
|
75
|
+
if (children.count == 0) return tree;
|
|
76
|
+
NSMutableDictionary *bounded = [tree mutableCopy];
|
|
77
|
+
bounded[childrenKey] = @[];
|
|
78
|
+
return bounded;
|
|
79
|
+
}
|
|
80
|
+
if (withheld && children.count < self.remainingNodes) {
|
|
81
|
+
id element = tree[elementKey];
|
|
82
|
+
if (!element) {
|
|
83
|
+
if (error) *error = [NSError errorWithDomain:@"agent-device.snapshot" code:3
|
|
84
|
+
userInfo:@{NSLocalizedDescriptionKey: @"snapshot continuation element unavailable"}];
|
|
85
|
+
return nil;
|
|
86
|
+
}
|
|
87
|
+
NSDictionary *continuation = [self read:element depth:depth error:error];
|
|
88
|
+
if (!continuation) return nil;
|
|
89
|
+
nativeLevels = MIN(depth, self.acceptedDepth);
|
|
90
|
+
children = continuation[childrenKey];
|
|
91
|
+
if (![children isKindOfClass:NSArray.class] || children.count < MIN(childCount.unsignedIntegerValue, self.remainingNodes)) {
|
|
92
|
+
if (error) *error = [NSError errorWithDomain:@"agent-device.snapshot" code:4
|
|
93
|
+
userInfo:@{NSLocalizedDescriptionKey: @"snapshot continuation children unavailable"}];
|
|
94
|
+
return nil;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (withheld && children.count < childCount.unsignedIntegerValue) self.truncated = YES;
|
|
98
|
+
NSMutableArray *materialized = nil;
|
|
99
|
+
NSUInteger index = 0;
|
|
100
|
+
for (NSDictionary *child in children) {
|
|
101
|
+
if (self.remainingNodes == 0) {
|
|
102
|
+
self.truncated = YES;
|
|
103
|
+
if (!materialized) materialized = [[children subarrayWithRange:NSMakeRange(0, index)] mutableCopy];
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
NSDictionary *node = [self materialize:child depth:depth - 1 nativeLevels:(nativeLevels > 0 ? nativeLevels - 1 : 0) error:error];
|
|
107
|
+
if (!node) return nil;
|
|
108
|
+
if (node != child && !materialized) materialized = [[children subarrayWithRange:NSMakeRange(0, index)] mutableCopy];
|
|
109
|
+
[materialized addObject:node];
|
|
110
|
+
index++;
|
|
111
|
+
}
|
|
112
|
+
if (!materialized && children == tree[childrenKey]) return tree;
|
|
113
|
+
NSMutableDictionary *result = [tree mutableCopy];
|
|
114
|
+
result[childrenKey] = materialized ?: children;
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
@end
|
|
118
|
+
|
|
119
|
+
NSDictionary *captureSnapshotTree(id element, NSUInteger maxDepth, NSUInteger maxNodes,
|
|
120
|
+
NSUInteger nativeLevelsHint, SnapshotElementReader reader,
|
|
121
|
+
BOOL *truncated, SnapshotCaptureRecovery *recovery, NSError **error)
|
|
122
|
+
{
|
|
123
|
+
SnapshotTreeCapture *capture = [SnapshotTreeCapture new];
|
|
124
|
+
capture.reader = reader;
|
|
125
|
+
capture.acceptedDepth = nativeLevelsHint > 0 ? MIN(maxDepth + 1, nativeLevelsHint) : maxDepth + 1;
|
|
126
|
+
capture.remainingNodes = maxNodes;
|
|
127
|
+
capture.maximumNodes = maxNodes;
|
|
128
|
+
NSDictionary *tree = [capture read:element depth:maxDepth + 1 error:error];
|
|
129
|
+
NSDictionary *result = tree ? [capture materialize:tree depth:maxDepth + 1 nativeLevels:capture.acceptedDepth error:error] : nil;
|
|
130
|
+
*truncated = capture.truncated;
|
|
131
|
+
if (recovery) {
|
|
132
|
+
recovery->requests = capture.requests;
|
|
133
|
+
recovery->rejected = capture.rejected;
|
|
134
|
+
recovery->continuations = capture.requests - capture.rejected - (tree ? 1 : 0);
|
|
135
|
+
recovery->acceptedLevels = tree ? capture.acceptedDepth : 0;
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
extern NSString *const kProtocolVersionKey;
|
|
6
|
+
extern NSString *const kSourceVersionKey;
|
|
7
|
+
extern NSString *const kRequestIdKey;
|
|
8
|
+
extern NSString *const kSourceVersion;
|
|
9
|
+
extern const NSUInteger kProtocolVersion;
|
|
10
|
+
extern const uint32_t kMaximumFrameBytes;
|
|
11
|
+
extern const NSUInteger kMaximumDepth;
|
|
12
|
+
extern const NSUInteger kMaximumNodes;
|
|
13
|
+
extern const NSUInteger kMaximumDurationMs;
|
|
14
|
+
|
|
15
|
+
NSDictionary *failureResponse(NSString *requestId,
|
|
16
|
+
NSString *kind,
|
|
17
|
+
NSString *code,
|
|
18
|
+
NSString *message);
|
|
19
|
+
|
|
20
|
+
@interface BridgeRuntime : NSObject
|
|
21
|
+
- (nullable instancetype)initWithError:(NSString *_Nullable *_Nullable)error;
|
|
22
|
+
- (nullable NSDictionary *)snapshotForProcess:(pid_t)pid
|
|
23
|
+
maxDepth:(NSUInteger)maxDepth
|
|
24
|
+
maxNodes:(NSUInteger)maxNodes
|
|
25
|
+
nativeLevelsHint:(NSUInteger)nativeLevelsHint
|
|
26
|
+
requestId:(NSString *)requestId
|
|
27
|
+
generation:(NSString *)generation
|
|
28
|
+
maxDurationMs:(NSUInteger)maxDurationMs
|
|
29
|
+
error:(NSDictionary *_Nullable *_Nonnull)error;
|
|
30
|
+
@end
|
|
31
|
+
|
|
32
|
+
BridgeRuntime *_Nullable sharedRuntime(NSString *_Nullable *_Nullable error);
|
|
33
|
+
|
|
34
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The private Simulator AX reader is adapted from Meta Platforms, Inc. idb v1.5.2
|
|
3
|
+
* SimulatorFrameworkBridge/AccessibilityService.m and AccessibilityRuntime.m.
|
|
4
|
+
* See LICENSE.idb for the upstream notice and license.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#import "SnapshotBridgeRuntime.h"
|
|
8
|
+
#import "SnapshotBridgeCapture.h"
|
|
9
|
+
|
|
10
|
+
#import <CoreGraphics/CoreGraphics.h>
|
|
11
|
+
#import <objc/message.h>
|
|
12
|
+
#import <objc/runtime.h>
|
|
13
|
+
|
|
14
|
+
#import <dlfcn.h>
|
|
15
|
+
#import <signal.h>
|
|
16
|
+
#import <unistd.h>
|
|
17
|
+
|
|
18
|
+
NSString *const kProtocolVersionKey = @"protocolVersion";
|
|
19
|
+
NSString *const kSourceVersionKey = @"sourceVersion";
|
|
20
|
+
NSString *const kRequestIdKey = @"requestId";
|
|
21
|
+
NSString *const kSourceVersion = @"agent-device-simulator-ax-v1.5.5";
|
|
22
|
+
const NSUInteger kProtocolVersion = 1;
|
|
23
|
+
const uint32_t kMaximumFrameBytes = 16 * 1024 * 1024;
|
|
24
|
+
const NSUInteger kMaximumDepth = 128;
|
|
25
|
+
const NSUInteger kMaximumNodes = 10000;
|
|
26
|
+
const NSUInteger kMaximumDurationMs = 120000;
|
|
27
|
+
|
|
28
|
+
static NSString *const kAttributeElementType = @"XC_kAXXCAttributeElementType";
|
|
29
|
+
static NSString *const kAttributeElementBaseType = @"XC_kAXXCAttributeElementBaseType";
|
|
30
|
+
static NSString *const kAttributeLabel = @"XC_kAXXCAttributeLabel";
|
|
31
|
+
static NSString *const kAttributeValue = @"XC_kAXXCAttributeValue";
|
|
32
|
+
static NSString *const kAttributeIdentifier = @"XC_kAXXCAttributeIdentifier";
|
|
33
|
+
static NSString *const kAttributeFrame = @"XC_kAXXCAttributeFrame";
|
|
34
|
+
static NSString *const kAttributeAutomationType = @"XC_kAXXCAttributeAutomationType";
|
|
35
|
+
static NSString *const kAttributeChildren = @"XC_kAXXCAttributeChildren";
|
|
36
|
+
static NSString *const kSnapshotAttributes = @"UIAccessibilitySnapshotKeyAttributes";
|
|
37
|
+
static NSString *const kSnapshotChildren = @"UIAccessibilitySnapshotKeyChildren";
|
|
38
|
+
static NSString *const kXctAutomationSupportPath =
|
|
39
|
+
@"/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework/XCTAutomationSupport";
|
|
40
|
+
static NSString *const kAxRuntimePath =
|
|
41
|
+
@"/System/Library/PrivateFrameworks/AXRuntime.framework/AXRuntime";
|
|
42
|
+
static NSString *const kAccessibilityErrorKey = @"accessibility-error";
|
|
43
|
+
|
|
44
|
+
typedef NSDictionary<NSString *, id> *_Nullable (*DefaultSnapshotParametersFn)(void);
|
|
45
|
+
typedef NSArray<NSNumber *> *_Nullable (*AttributeNumbersForNamesFn)(NSArray<NSString *> *names);
|
|
46
|
+
typedef uint32_t (*AXValueGetTypeFn)(const void *value);
|
|
47
|
+
typedef Boolean (*AXValueGetValueFn)(const void *value, uint32_t type, void *out);
|
|
48
|
+
typedef bool (*AutomationEnabledFn)(void);
|
|
49
|
+
|
|
50
|
+
@interface XCTAccessibilityFramework : NSObject
|
|
51
|
+
- (instancetype)initForRemoteAccess;
|
|
52
|
+
- (nullable id)userTestingSnapshotForElement:(id)element
|
|
53
|
+
options:(NSDictionary<NSString *, id> *)options
|
|
54
|
+
error:(NSError **)error;
|
|
55
|
+
@end
|
|
56
|
+
|
|
57
|
+
@interface XCAccessibilityElement : NSObject
|
|
58
|
+
- (nullable void *)AXUIElement;
|
|
59
|
+
@end
|
|
60
|
+
|
|
61
|
+
@protocol XCAccessibilityElementFactory <NSObject>
|
|
62
|
+
+ (nullable XCAccessibilityElement *)elementWithProcessIdentifier:(pid_t)pid;
|
|
63
|
+
@end
|
|
64
|
+
|
|
65
|
+
@protocol AXForegroundElement <NSObject>
|
|
66
|
+
+ (nullable id<AXForegroundElement>)primaryApp;
|
|
67
|
+
- (pid_t)pid;
|
|
68
|
+
@end
|
|
69
|
+
|
|
70
|
+
static NSNumber *finiteNumber(double value)
|
|
71
|
+
{
|
|
72
|
+
return isfinite(value) ? @(value) : nil;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static NSDictionary *_Nullable rectDictionary(CGRect rect)
|
|
76
|
+
{
|
|
77
|
+
NSNumber *x = finiteNumber(rect.origin.x);
|
|
78
|
+
NSNumber *y = finiteNumber(rect.origin.y);
|
|
79
|
+
NSNumber *width = finiteNumber(rect.size.width);
|
|
80
|
+
NSNumber *height = finiteNumber(rect.size.height);
|
|
81
|
+
if (!x || !y || !width || !height) {
|
|
82
|
+
return nil;
|
|
83
|
+
}
|
|
84
|
+
return @{ @"X" : x, @"Y" : y, @"Width" : width, @"Height" : height };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@interface SnapshotWatchdogState : NSObject
|
|
88
|
+
@property(atomic) BOOL completed;
|
|
89
|
+
@end
|
|
90
|
+
|
|
91
|
+
@implementation SnapshotWatchdogState
|
|
92
|
+
@end
|
|
93
|
+
|
|
94
|
+
static dispatch_source_t startRequestWatchdog(NSUInteger durationMs, SnapshotWatchdogState *state)
|
|
95
|
+
{
|
|
96
|
+
dispatch_source_t watchdog = dispatch_source_create(
|
|
97
|
+
DISPATCH_SOURCE_TYPE_TIMER,
|
|
98
|
+
0,
|
|
99
|
+
0,
|
|
100
|
+
dispatch_get_global_queue(QOS_CLASS_UTILITY, 0));
|
|
101
|
+
dispatch_source_set_timer(
|
|
102
|
+
watchdog,
|
|
103
|
+
dispatch_time(DISPATCH_TIME_NOW, (uint64_t)durationMs * NSEC_PER_MSEC),
|
|
104
|
+
DISPATCH_TIME_FOREVER,
|
|
105
|
+
0);
|
|
106
|
+
dispatch_source_set_event_handler(watchdog, ^{
|
|
107
|
+
if (!state.completed) kill(getpid(), SIGKILL);
|
|
108
|
+
});
|
|
109
|
+
dispatch_resume(watchdog);
|
|
110
|
+
return watchdog;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogState *state)
|
|
114
|
+
{
|
|
115
|
+
state.completed = YES;
|
|
116
|
+
dispatch_source_cancel(watchdog);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@implementation BridgeRuntime {
|
|
120
|
+
XCTAccessibilityFramework *_framework;
|
|
121
|
+
Class<XCAccessibilityElementFactory> _elementClass;
|
|
122
|
+
DefaultSnapshotParametersFn _defaultSnapshotParameters;
|
|
123
|
+
AttributeNumbersForNamesFn _attributeNumbersForNames;
|
|
124
|
+
AXValueGetTypeFn _valueGetType;
|
|
125
|
+
AXValueGetValueFn _valueGetValue;
|
|
126
|
+
AutomationEnabledFn _automationEnabled;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
- (nullable instancetype)initWithError:(NSString *_Nullable *_Nullable)error
|
|
130
|
+
{
|
|
131
|
+
self = [super init];
|
|
132
|
+
if (!self) return nil;
|
|
133
|
+
|
|
134
|
+
dlopen(kAxRuntimePath.UTF8String, RTLD_NOW);
|
|
135
|
+
dlopen(kXctAutomationSupportPath.UTF8String, RTLD_NOW);
|
|
136
|
+
|
|
137
|
+
Class frameworkClass = objc_lookUpClass("XCTAccessibilityFramework");
|
|
138
|
+
_elementClass = (Class<XCAccessibilityElementFactory>)objc_lookUpClass("XCAccessibilityElement");
|
|
139
|
+
if (!frameworkClass || !_elementClass) {
|
|
140
|
+
if (error) *error = @"XCTAutomationSupport accessibility classes are unavailable";
|
|
141
|
+
return nil;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
_framework = [(XCTAccessibilityFramework *)[frameworkClass alloc] initForRemoteAccess];
|
|
145
|
+
if (!_framework || ![_framework respondsToSelector:@selector(userTestingSnapshotForElement:options:error:)]) {
|
|
146
|
+
if (error) *error = @"XCTAccessibilityFramework snapshot API is unavailable";
|
|
147
|
+
return nil;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
_defaultSnapshotParameters = (DefaultSnapshotParametersFn)dlsym(RTLD_DEFAULT, "XCTDefaultSnapshotParameters");
|
|
151
|
+
_attributeNumbersForNames = (AttributeNumbersForNamesFn)dlsym(
|
|
152
|
+
RTLD_DEFAULT, "XCAXAccessibilityAttributesForStringAttributes");
|
|
153
|
+
_valueGetType = (AXValueGetTypeFn)dlsym(RTLD_DEFAULT, "AXValueGetType");
|
|
154
|
+
_valueGetValue = (AXValueGetValueFn)dlsym(RTLD_DEFAULT, "AXValueGetValue");
|
|
155
|
+
_automationEnabled = (AutomationEnabledFn)dlsym(RTLD_DEFAULT, "_AXSAutomationEnabled");
|
|
156
|
+
if (!_defaultSnapshotParameters || !_attributeNumbersForNames || !_valueGetType || !_valueGetValue) {
|
|
157
|
+
if (error) *error = @"AX snapshot conversion functions are unavailable";
|
|
158
|
+
return nil;
|
|
159
|
+
}
|
|
160
|
+
return self;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
- (BOOL)assertAutomationMode:(BOOL)wanted
|
|
164
|
+
{
|
|
165
|
+
Class settingsClass = NSClassFromString(@"AXSettings");
|
|
166
|
+
SEL sharedInstance = NSSelectorFromString(@"sharedInstance");
|
|
167
|
+
SEL setter = NSSelectorFromString(@"setAutomationEnabled:");
|
|
168
|
+
if (settingsClass && [settingsClass respondsToSelector:sharedInstance]) {
|
|
169
|
+
id settings = ((id (*)(id, SEL))objc_msgSend)(settingsClass, sharedInstance);
|
|
170
|
+
if ([settings respondsToSelector:setter]) {
|
|
171
|
+
((void (*)(id, SEL, BOOL))objc_msgSend)(settings, setter, wanted);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return _automationEnabled != NULL && _automationEnabled();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
- (BOOL)isPrimaryForegroundProcess:(pid_t)pid
|
|
178
|
+
{
|
|
179
|
+
Class<AXForegroundElement> elementClass = (Class<AXForegroundElement>)objc_lookUpClass("AXElement");
|
|
180
|
+
if (![elementClass respondsToSelector:@selector(primaryApp)]) return NO;
|
|
181
|
+
id<AXForegroundElement> application = [elementClass primaryApp];
|
|
182
|
+
return [application respondsToSelector:@selector(pid)] && [application pid] == pid;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
- (nullable id)jsonValue:(id)value name:(NSString *)name
|
|
186
|
+
{
|
|
187
|
+
if (!value || value == [NSNull null]) return nil;
|
|
188
|
+
if ([value isKindOfClass:NSString.class] || [value isKindOfClass:NSNumber.class]) return value;
|
|
189
|
+
|
|
190
|
+
const void *raw = (__bridge const void *)value;
|
|
191
|
+
if (_valueGetType(raw) == 3) {
|
|
192
|
+
CGRect rect = CGRectZero;
|
|
193
|
+
if (_valueGetValue(raw, 3, &rect)) return rectDictionary(rect);
|
|
194
|
+
}
|
|
195
|
+
if ([name isEqualToString:kAttributeFrame]) return nil;
|
|
196
|
+
return nil;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
- (nullable NSDictionary *)nodeFromSnapshot:(id)snapshot
|
|
200
|
+
namesByNumber:(NSDictionary<NSNumber *, NSString *> *)namesByNumber
|
|
201
|
+
depth:(NSUInteger)depth
|
|
202
|
+
maxDepth:(NSUInteger)maxDepth
|
|
203
|
+
maxNodes:(NSUInteger)maxNodes
|
|
204
|
+
count:(NSUInteger *)count
|
|
205
|
+
truncated:(BOOL *)truncated
|
|
206
|
+
malformed:(BOOL *)malformed
|
|
207
|
+
{
|
|
208
|
+
if (![snapshot isKindOfClass:NSDictionary.class]) {
|
|
209
|
+
*malformed = YES;
|
|
210
|
+
return nil;
|
|
211
|
+
}
|
|
212
|
+
if (*count >= maxNodes) {
|
|
213
|
+
*truncated = YES;
|
|
214
|
+
return nil;
|
|
215
|
+
}
|
|
216
|
+
(*count)++;
|
|
217
|
+
|
|
218
|
+
NSDictionary *attributes = ((NSDictionary *)snapshot)[kSnapshotAttributes];
|
|
219
|
+
if (![attributes isKindOfClass:NSDictionary.class]) {
|
|
220
|
+
*malformed = YES;
|
|
221
|
+
return nil;
|
|
222
|
+
}
|
|
223
|
+
NSMutableDictionary *node = [NSMutableDictionary dictionary];
|
|
224
|
+
for (NSNumber *number in attributes) {
|
|
225
|
+
NSString *name = namesByNumber[number];
|
|
226
|
+
if (!name || [name isEqualToString:kAttributeChildren]) continue;
|
|
227
|
+
id safe = [self jsonValue:attributes[number] name:name];
|
|
228
|
+
if (safe) node[name] = safe;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
NSArray *children = ((NSDictionary *)snapshot)[kSnapshotChildren];
|
|
232
|
+
if (![children isKindOfClass:NSArray.class]) {
|
|
233
|
+
*malformed = YES;
|
|
234
|
+
return nil;
|
|
235
|
+
}
|
|
236
|
+
NSMutableArray *builtChildren = [NSMutableArray array];
|
|
237
|
+
if (depth >= maxDepth) {
|
|
238
|
+
if (children.count > 0) *truncated = YES;
|
|
239
|
+
} else {
|
|
240
|
+
for (id child in children) {
|
|
241
|
+
NSDictionary *built = [self nodeFromSnapshot:child
|
|
242
|
+
namesByNumber:namesByNumber
|
|
243
|
+
depth:depth + 1
|
|
244
|
+
maxDepth:maxDepth
|
|
245
|
+
maxNodes:maxNodes
|
|
246
|
+
count:count
|
|
247
|
+
truncated:truncated
|
|
248
|
+
malformed:malformed];
|
|
249
|
+
if (built) [builtChildren addObject:built];
|
|
250
|
+
if (*malformed) return nil;
|
|
251
|
+
if (*truncated) break;
|
|
252
|
+
if (*count >= maxNodes) {
|
|
253
|
+
if (builtChildren.count < children.count) *truncated = YES;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
node[kAttributeChildren] = builtChildren;
|
|
259
|
+
return node;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
- (nullable NSDictionary *)snapshotForProcess:(pid_t)pid
|
|
263
|
+
maxDepth:(NSUInteger)maxDepth
|
|
264
|
+
maxNodes:(NSUInteger)maxNodes
|
|
265
|
+
nativeLevelsHint:(NSUInteger)nativeLevelsHint
|
|
266
|
+
requestId:(NSString *)requestId
|
|
267
|
+
generation:(NSString *)generation
|
|
268
|
+
maxDurationMs:(NSUInteger)maxDurationMs
|
|
269
|
+
error:(NSDictionary *_Nullable *_Nonnull)error
|
|
270
|
+
{
|
|
271
|
+
SnapshotWatchdogState *watchdogState = [SnapshotWatchdogState new];
|
|
272
|
+
dispatch_source_t watchdog = startRequestWatchdog(maxDurationMs, watchdogState);
|
|
273
|
+
XCAccessibilityElement *root = [_elementClass elementWithProcessIdentifier:pid];
|
|
274
|
+
if (!root) {
|
|
275
|
+
if (error) *error = failureResponse(requestId, @"application_unavailable", @"application-element-missing", @"application element is unavailable");
|
|
276
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
277
|
+
return nil;
|
|
278
|
+
}
|
|
279
|
+
void *raw = [root AXUIElement];
|
|
280
|
+
if (!raw) {
|
|
281
|
+
if (error) *error = failureResponse(requestId, @"application_unavailable", @"application-element-missing", @"application element is unavailable");
|
|
282
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
283
|
+
return nil;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
NSArray<NSString *> *names = @[
|
|
287
|
+
kAttributeElementType,
|
|
288
|
+
kAttributeElementBaseType,
|
|
289
|
+
kAttributeLabel,
|
|
290
|
+
kAttributeValue,
|
|
291
|
+
kAttributeIdentifier,
|
|
292
|
+
kAttributeFrame,
|
|
293
|
+
kAttributeAutomationType,
|
|
294
|
+
kAttributeChildren,
|
|
295
|
+
];
|
|
296
|
+
NSArray<NSNumber *> *numbers = _attributeNumbersForNames(names);
|
|
297
|
+
if (![numbers isKindOfClass:NSArray.class] || numbers.count != names.count) {
|
|
298
|
+
if (error) *error = failureResponse(requestId, @"reader_unavailable", @"attribute-vocabulary-mismatch", @"AX attribute vocabulary is incompatible");
|
|
299
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
300
|
+
return nil;
|
|
301
|
+
}
|
|
302
|
+
NSMutableDictionary<NSNumber *, NSString *> *namesByNumber = [NSMutableDictionary dictionary];
|
|
303
|
+
[numbers enumerateObjectsUsingBlock:^(NSNumber *number, NSUInteger index, BOOL *stop) {
|
|
304
|
+
(void)stop;
|
|
305
|
+
if ([number isKindOfClass:NSNumber.class]) namesByNumber[number] = names[index];
|
|
306
|
+
}];
|
|
307
|
+
NSMutableDictionary *options = [_defaultSnapshotParameters() mutableCopy];
|
|
308
|
+
if (!options) options = [NSMutableDictionary dictionary];
|
|
309
|
+
options[@"attributes"] = numbers;
|
|
310
|
+
options[@"maxDepth"] = @(maxDepth);
|
|
311
|
+
options[@"maxChildren"] = @(maxNodes);
|
|
312
|
+
options[@"maxArrayCount"] = @(maxNodes);
|
|
313
|
+
BOOL automationEnabled = [self assertAutomationMode:YES];
|
|
314
|
+
NSError *runtimeError = nil;
|
|
315
|
+
id snapshot = nil;
|
|
316
|
+
BOOL acquisitionTruncated = NO;
|
|
317
|
+
SnapshotCaptureRecovery recovery = {0, 0, 0, 0};
|
|
318
|
+
@try {
|
|
319
|
+
if (![self isPrimaryForegroundProcess:pid]) {
|
|
320
|
+
if (error) *error = failureResponse(requestId, @"unsupported", @"foreground-owner-unverified", @"target app is not the primary foreground accessibility owner");
|
|
321
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
322
|
+
return nil;
|
|
323
|
+
}
|
|
324
|
+
snapshot = captureSnapshotTree((__bridge id)raw, maxDepth, maxNodes, nativeLevelsHint,
|
|
325
|
+
^id(id element, NSUInteger depth, NSUInteger nodes, NSError **captureError) {
|
|
326
|
+
if (![self isPrimaryForegroundProcess:pid]) {
|
|
327
|
+
if (captureError) *captureError = [NSError errorWithDomain:@"agent-device.snapshot" code:5
|
|
328
|
+
userInfo:@{NSLocalizedDescriptionKey: @"foreground owner changed during continuation"}];
|
|
329
|
+
return nil;
|
|
330
|
+
}
|
|
331
|
+
NSMutableDictionary *bounded = [options mutableCopy];
|
|
332
|
+
bounded[@"maxDepth"] = @(depth);
|
|
333
|
+
bounded[@"maxChildren"] = @(nodes);
|
|
334
|
+
bounded[@"maxArrayCount"] = @(nodes);
|
|
335
|
+
return [_framework userTestingSnapshotForElement:element options:bounded error:captureError];
|
|
336
|
+
}, &acquisitionTruncated, &recovery, &runtimeError);
|
|
337
|
+
if (![self isPrimaryForegroundProcess:pid]) {
|
|
338
|
+
if (error) *error = failureResponse(requestId, @"unsupported", @"foreground-owner-changed", @"foreground accessibility ownership changed during acquisition");
|
|
339
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
340
|
+
return nil;
|
|
341
|
+
}
|
|
342
|
+
} @catch (NSException *exception) {
|
|
343
|
+
if (error) *error = failureResponse(requestId, @"reader_unavailable", @"private-api-exception", exception.reason ?: @"AX snapshot raised an exception");
|
|
344
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
345
|
+
return nil;
|
|
346
|
+
}
|
|
347
|
+
if (!snapshot && [runtimeError.domain isEqualToString:@"agent-device.snapshot"]) {
|
|
348
|
+
BOOL exhausted = runtimeError.code == 1;
|
|
349
|
+
if (error) *error = failureResponse(requestId, exhausted ? @"reader_unavailable" : @"malformed_tree",
|
|
350
|
+
exhausted ? @"continuation-budget-exhausted" : @"snapshot-tree-malformed", runtimeError.localizedDescription);
|
|
351
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
352
|
+
return nil;
|
|
353
|
+
}
|
|
354
|
+
if (!snapshot) {
|
|
355
|
+
NSNumber *axError = runtimeError.userInfo[kAccessibilityErrorKey];
|
|
356
|
+
NSInteger code = [axError respondsToSelector:@selector(integerValue)] ? axError.integerValue : runtimeError.code;
|
|
357
|
+
NSString *kind = code == -25216 ? @"application_not_responding" : @"application_unavailable";
|
|
358
|
+
NSString *message = runtimeError.localizedDescription ?: @"AX snapshot returned no tree";
|
|
359
|
+
if (error) *error = failureResponse(requestId, kind, code == -25216 ? @"application-timeout" : @"application-server-unavailable", message);
|
|
360
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
361
|
+
return nil;
|
|
362
|
+
}
|
|
363
|
+
BOOL truncated = NO;
|
|
364
|
+
BOOL malformed = NO;
|
|
365
|
+
NSUInteger count = 0;
|
|
366
|
+
NSDictionary *tree = [self nodeFromSnapshot:snapshot
|
|
367
|
+
namesByNumber:namesByNumber
|
|
368
|
+
depth:0
|
|
369
|
+
maxDepth:maxDepth
|
|
370
|
+
maxNodes:maxNodes
|
|
371
|
+
count:&count
|
|
372
|
+
truncated:&truncated
|
|
373
|
+
malformed:&malformed];
|
|
374
|
+
if (!tree) {
|
|
375
|
+
if (error) *error = failureResponse(requestId, @"malformed_tree", malformed ? @"snapshot-tree-malformed" : @"snapshot-root-invalid", malformed ? @"AX snapshot contained a malformed node" : @"AX snapshot did not contain a materialized root node");
|
|
376
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
377
|
+
return nil;
|
|
378
|
+
}
|
|
379
|
+
finishRequestWatchdog(watchdog, watchdogState);
|
|
380
|
+
return @{
|
|
381
|
+
kProtocolVersionKey : @(kProtocolVersion),
|
|
382
|
+
kSourceVersionKey : kSourceVersion,
|
|
383
|
+
kRequestIdKey : requestId ?: @"",
|
|
384
|
+
@"generation" : generation ?: @"",
|
|
385
|
+
@"ok" : @YES,
|
|
386
|
+
@"pid" : @(pid),
|
|
387
|
+
@"tree" : tree,
|
|
388
|
+
@"truncated" : @((BOOL)(truncated || acquisitionTruncated)),
|
|
389
|
+
@"automationEnabled" : @(automationEnabled),
|
|
390
|
+
@"recovery" : @{
|
|
391
|
+
@"requests" : @(recovery.requests),
|
|
392
|
+
@"rejected" : @(recovery.rejected),
|
|
393
|
+
@"continuations" : @(recovery.continuations),
|
|
394
|
+
@"acceptedLevels" : @(recovery.acceptedLevels),
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
@end
|
|
399
|
+
BridgeRuntime *sharedRuntime(NSString **error)
|
|
400
|
+
{
|
|
401
|
+
static BridgeRuntime *runtime;
|
|
402
|
+
static dispatch_once_t once;
|
|
403
|
+
static NSString *setupError;
|
|
404
|
+
dispatch_once(&once, ^{
|
|
405
|
+
NSString *localError = nil;
|
|
406
|
+
runtime = [[BridgeRuntime alloc] initWithError:&localError];
|
|
407
|
+
setupError = [localError copy];
|
|
408
|
+
});
|
|
409
|
+
if (!runtime && error) *error = setupError ?: @"AX bridge runtime is unavailable";
|
|
410
|
+
return runtime;
|
|
411
|
+
}
|
|
@@ -58,10 +58,62 @@ int main(int argc, const char *argv[]) {
|
|
|
58
58
|
#import <UIKit/UIKit.h>
|
|
59
59
|
|
|
60
60
|
@interface AgentDeviceRunnerViewController : UIViewController
|
|
61
|
+
@property(nonatomic, strong) UILabel *alertActionStatus;
|
|
62
|
+
@property(nonatomic, assign) NSUInteger firstAlertActions;
|
|
63
|
+
@property(nonatomic, assign) NSUInteger replacementAlertActions;
|
|
64
|
+
@property(nonatomic, assign) BOOL alertFixtureStarted;
|
|
61
65
|
@end
|
|
62
66
|
|
|
63
67
|
@implementation AgentDeviceRunnerViewController
|
|
64
68
|
|
|
69
|
+
#if TARGET_OS_IOS
|
|
70
|
+
- (void)updateAlertActionStatus {
|
|
71
|
+
self.alertActionStatus.text = [NSString stringWithFormat:@"First actions: %lu; replacement actions: %lu",
|
|
72
|
+
(unsigned long)self.firstAlertActions,
|
|
73
|
+
(unsigned long)self.replacementAlertActions];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (void)presentAlertFixtureReplacement:(BOOL)replacement {
|
|
77
|
+
NSArray<NSString *> *arguments = NSProcessInfo.processInfo.arguments;
|
|
78
|
+
BOOL sameTitle = [arguments containsObject:@"--agent-device-alert-same-title"];
|
|
79
|
+
BOOL sameBody = [arguments containsObject:@"--agent-device-alert-same-body"];
|
|
80
|
+
NSString *title = replacement && !sameTitle ? @"Next confirmation" : @"First confirmation";
|
|
81
|
+
NSString *body = replacement && !sameBody ? @"Second request" : @"First request";
|
|
82
|
+
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
|
|
83
|
+
message:body
|
|
84
|
+
preferredStyle:UIAlertControllerStyleAlert];
|
|
85
|
+
__weak UIAlertController *weakAlert = alert;
|
|
86
|
+
for (NSString *buttonTitle in @[@"Cancel", @"OK"]) {
|
|
87
|
+
UIAlertActionStyle style = [buttonTitle isEqualToString:@"Cancel"]
|
|
88
|
+
? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
|
|
89
|
+
[alert addAction:[UIAlertAction actionWithTitle:buttonTitle style:style handler:^(UIAlertAction *action) {
|
|
90
|
+
(void)action;
|
|
91
|
+
if (replacement) {
|
|
92
|
+
self.replacementAlertActions += 1;
|
|
93
|
+
} else {
|
|
94
|
+
self.firstAlertActions += 1;
|
|
95
|
+
}
|
|
96
|
+
[self updateAlertActionStatus];
|
|
97
|
+
if (!replacement) {
|
|
98
|
+
[weakAlert dismissViewControllerAnimated:NO completion:^{
|
|
99
|
+
[self presentAlertFixtureReplacement:YES];
|
|
100
|
+
}];
|
|
101
|
+
}
|
|
102
|
+
}]];
|
|
103
|
+
}
|
|
104
|
+
[self presentViewController:alert animated:NO completion:nil];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
- (void)viewDidAppear:(BOOL)animated {
|
|
108
|
+
[super viewDidAppear:animated];
|
|
109
|
+
if (!self.alertFixtureStarted &&
|
|
110
|
+
[NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-replacement-regression"]) {
|
|
111
|
+
self.alertFixtureStarted = YES;
|
|
112
|
+
[self presentAlertFixtureReplacement:NO];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
#endif
|
|
116
|
+
|
|
65
117
|
- (void)agentDeviceTextEntryDidChange:(UITextField *)textField {
|
|
66
118
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-disappear-after-input"] &&
|
|
67
119
|
textField.text.length > 0) {
|
|
@@ -88,6 +140,12 @@ int main(int argc, const char *argv[]) {
|
|
|
88
140
|
|
|
89
141
|
// Keep the fixture behind a launch argument so normal runner snapshots remain unchanged.
|
|
90
142
|
#if TARGET_OS_IOS
|
|
143
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-replacement-regression"]) {
|
|
144
|
+
self.alertActionStatus = label;
|
|
145
|
+
label.accessibilityIdentifier = @"agent-device-alert-actions";
|
|
146
|
+
[self updateAlertActionStatus];
|
|
147
|
+
}
|
|
148
|
+
|
|
91
149
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-regression"]) {
|
|
92
150
|
UITextField *textField = [[UITextField alloc] init];
|
|
93
151
|
textField.accessibilityIdentifier = @"agent-device-hardware-keyboard-input";
|