agent-device 0.21.11 → 0.21.13
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.11.apk → agent-device-android-ime-helper-0.21.13.apk} +0 -0
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.13.apk.sha256 +1 -0
- package/android/ime-helper/dist/{agent-device-android-ime-helper-0.21.11.manifest.json → agent-device-android-ime-helper-0.21.13.manifest.json} +4 -4
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.11.apk → agent-device-android-snapshot-helper-0.21.13.apk} +0 -0
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.13.apk.sha256 +1 -0
- package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.21.11.manifest.json → agent-device-android-snapshot-helper-0.21.13.manifest.json} +6 -6
- package/apple/fold-helper/Fold.m +97 -0
- package/apple/macos-helper/Package.swift +3 -6
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/main.swift +3 -8
- package/apple/macos-helper/Tests/AgentDeviceMacOSHelperTests/ScreenshotResponseTests.swift +15 -0
- package/apple/snapshot-bridge/SnapshotBridgeRuntime.m +47 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/AgentDeviceRunnerApp.m +99 -42
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner/Info.plist +23 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +17 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAppScreenCapture.swift +21 -13
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerScrollViewportPolicy.swift +1 -162
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.h +0 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSynthesizedGesture.m +0 -56
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerSystemSurfaceHostPolicy.swift +0 -48
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift +0 -50
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +22 -568
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +21 -9
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+BlockingSystemModalResolution.swift +0 -36
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandDispatch.swift +630 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +18 -2236
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandJournal.swift +1 -338
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Environment.swift +0 -12
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+GestureExecution.swift +165 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +0 -24
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +0 -142
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +90 -39
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+MainThreadWork.swift +78 -106
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +23 -2
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +147 -95
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+PrivateAXPresentation.swift +0 -209
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +86 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollDragExecution.swift +287 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +1 -200
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +0 -185
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +75 -285
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotAcquisition.swift +23 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotBackendCapabilities.swift +0 -78
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +83 -578
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCaptureTarget.swift +106 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotExecution.swift +142 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotTiming.swift +49 -78
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedCommitDeadline.swift +0 -44
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +27 -97
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedInteraction.swift +1 -11
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedTextEntry.swift +11 -87
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +2 -10
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntry.swift +1 -1
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextEntryFocus.swift +0 -35
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextInputCandidatePolicy.swift +0 -31
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TextTyping.swift +2 -18
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Transport.swift +34 -52
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TvRemote.swift +0 -22
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+TypeExecution.swift +142 -0
- package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +22 -6
- package/dist/apple/runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +140 -20
- package/dist/src/absence-observation-errors.js +1 -1
- package/dist/src/adapter.js +1 -1
- package/dist/src/agent-device-client.js +1 -1
- package/dist/src/alert-runtime.js +1 -1
- package/dist/src/android-adb.d.ts +1 -1
- package/dist/src/app-launch.js +2 -2
- package/dist/src/app-log-runtime2.js +3 -3
- package/dist/src/app-resolution.js +2 -2
- package/dist/src/back-mode.js +1 -1
- package/dist/src/capture-disclosure.js +1 -1
- package/dist/src/capture.js +1 -1
- package/dist/src/cli-config.js +1 -1
- package/dist/src/cli-help.js +10 -7
- package/dist/src/cli-runner.js +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/client-types.d.ts +5 -8
- package/dist/src/code-signature.js +1 -1
- package/dist/src/command-schema.js +3 -3
- package/dist/src/command-tools.js +3 -3
- package/dist/src/connection.js +1 -1
- package/dist/src/daemon-client-lifecycle.js +1 -1
- package/dist/src/daemon-resolution.js +1 -1
- package/dist/src/device-claim-rule.js +2 -2
- package/dist/src/device-input-state.d.ts +1 -1
- package/dist/src/device-rotation.js +1 -1
- package/dist/src/device-session.js +1 -1
- package/dist/src/devicectl.js +1 -1
- package/dist/src/display-inventory.js +1 -1
- package/dist/src/doctor-facade.js +1 -1
- package/dist/src/find.js +1 -1
- package/dist/src/gesture-plan-types.d.ts +38 -0
- package/dist/src/harmonyos.js +1 -1
- package/dist/src/helper.js +2 -2
- package/dist/src/host.js +1 -1
- package/dist/src/install-source-network-transport.js +1 -1
- package/dist/src/install-source2.js +1 -1
- package/dist/src/interaction-ref-policy.js +1 -1
- package/dist/src/interaction2.js +1 -1
- package/dist/src/interactor-operation-catalog.js +1 -1
- package/dist/src/interactor.js +4 -4
- package/dist/src/interactor2.js +1 -1
- package/dist/src/internal/bin.js +1 -1
- package/dist/src/internal/daemon.js +2 -2
- package/dist/src/inventory2.js +1 -1
- package/dist/src/ios-snapshot-acquisition.js +1 -1
- package/dist/src/ios-snapshot-runtime.js +1 -1
- package/dist/src/limrun-runtime-dependencies.js +1 -1
- package/dist/src/limrun.d.ts +435 -4
- package/dist/src/linux.js +1 -1
- package/dist/src/local-interactor-operation-set.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 +4 -4
- package/dist/src/mobile-snapshot-semantics.js +1 -1
- package/dist/src/perf-facade.js +1 -2
- package/dist/src/perf-runtime-plan.js +1 -1
- package/dist/src/perf-target.js +2 -0
- package/dist/src/physical-device-apps.js +1 -0
- package/dist/src/physical-device-control.js +1 -1
- package/dist/src/platform-request-scope.js +1 -1
- package/dist/src/platform-runtime-operation-host.js +1 -1
- package/dist/src/platform-runtime-screen-recording-finalizer-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/provider-webdriver.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/registry.js +35 -35
- package/dist/src/request-admission.js +1 -1
- package/dist/src/request-runtime-binding.js +1 -1
- 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 +3 -0
- package/dist/src/runner-operations-facade.js +1 -1
- package/dist/src/runner-presentation.js +1 -1
- package/dist/src/runner.js +1 -1
- package/dist/src/runtime.js +3 -3
- package/dist/src/runtime10.js +1 -1
- package/dist/src/runtime2.js +2 -2
- 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-resource-recovery.js +1 -1
- package/dist/src/screen-recording-transport.js +1 -1
- package/dist/src/screenshot-runtime.js +1 -1
- package/dist/src/screenshot3.js +1 -1
- package/dist/src/script.js +1 -1
- package/dist/src/scroll-command.d.ts +377 -0
- package/dist/src/scroll-command.js +1 -1
- package/dist/src/sdk-batch.js +2 -2
- package/dist/src/sdk-contracts.d.ts +9 -0
- package/dist/src/sdk-device.js +1 -1
- package/dist/src/sdk-selectors.d.ts +23 -715
- package/dist/src/selection.js +0 -0
- package/dist/src/selector-runtime.js +1 -1
- package/dist/src/semantic-index.js +1 -1
- package/dist/src/server.js +1 -1
- package/dist/src/session-observation.js +1 -1
- package/dist/src/session-snapshot.js +1 -1
- package/dist/src/session2.js +2 -2
- package/dist/src/simctl-facade.js +1 -1
- package/dist/src/simctl.js +1 -1
- package/dist/src/simulator-facade.js +1 -1
- package/dist/src/simulator-state.js +1 -1
- package/dist/src/simulator.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/snapshot4.js +1 -1
- package/dist/src/src7.js +1 -1
- package/dist/src/text-entry-focus.js +1 -1
- package/dist/src/tool-provider.js +1 -1
- package/dist/src/touch-runtime.js +1 -1
- package/dist/src/tree.js +1 -1
- package/dist/src/update-check.js +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/web2.js +1 -1
- package/package.json +4 -2
- package/server.json +2 -2
- package/android/ime-helper/dist/agent-device-android-ime-helper-0.21.11.apk.sha256 +0 -1
- package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.21.11.apk.sha256 +0 -1
- package/apple/macos-helper/Sources/AgentDeviceMacOSDeviceHub/DeviceHubPose.swift +0 -47
- package/apple/macos-helper/Sources/AgentDeviceMacOSDeviceHub/DeviceHubWindowInventory.swift +0 -65
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubPose.swift +0 -225
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubSidebar.swift +0 -57
- package/apple/macos-helper/Sources/AgentDeviceMacOSHelper/DeviceHubWindowDiscovery.swift +0 -108
- package/apple/macos-helper/Tests/AgentDeviceMacOSDeviceHubTests/DeviceHubPoseTests.swift +0 -30
- package/apple/macos-helper/Tests/AgentDeviceMacOSDeviceHubTests/DeviceHubWindowInventoryTests.swift +0 -65
- package/dist/src/app-inventory.d.ts +0 -4
- package/dist/src/apps-simctl.js +0 -1
- package/dist/src/cloud-artifacts.d.ts +0 -61
- package/dist/src/runner-contract.js +0 -3
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8388dc7a3c3f18aca7322cc50bc4f3ff769d426733746a764f45b56d50a0f267 agent-device-android-ime-helper-0.21.13.apk
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-ime-helper",
|
|
3
|
-
"version": "0.21.
|
|
4
|
-
"assetName": "agent-device-android-ime-helper-0.21.
|
|
5
|
-
"sha256": "
|
|
3
|
+
"version": "0.21.13",
|
|
4
|
+
"assetName": "agent-device-android-ime-helper-0.21.13.apk",
|
|
5
|
+
"sha256": "8388dc7a3c3f18aca7322cc50bc4f3ff769d426733746a764f45b56d50a0f267",
|
|
6
6
|
"packageName": "com.callstack.agentdevice.imehelper",
|
|
7
|
-
"versionCode":
|
|
7
|
+
"versionCode": 21013,
|
|
8
8
|
"serviceComponent": "com.callstack.agentdevice.imehelper/.TestInputMethodService",
|
|
9
9
|
"broadcastProtocol": "android-ime-helper-v1"
|
|
10
10
|
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
e07b556384093a04be99af068b6493e0b0a66e7e7cf09264da4fe60f75f2d164 agent-device-android-snapshot-helper-0.21.13.apk
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "android-snapshot-helper",
|
|
3
|
-
"version": "0.21.
|
|
4
|
-
"releaseTag": "v0.21.
|
|
5
|
-
"assetName": "agent-device-android-snapshot-helper-0.21.
|
|
3
|
+
"version": "0.21.13",
|
|
4
|
+
"releaseTag": "v0.21.13",
|
|
5
|
+
"assetName": "agent-device-android-snapshot-helper-0.21.13.apk",
|
|
6
6
|
"apkUrl": null,
|
|
7
|
-
"sha256": "
|
|
8
|
-
"checksumName": "agent-device-android-snapshot-helper-0.21.
|
|
7
|
+
"sha256": "e07b556384093a04be99af068b6493e0b0a66e7e7cf09264da4fe60f75f2d164",
|
|
8
|
+
"checksumName": "agent-device-android-snapshot-helper-0.21.13.apk.sha256",
|
|
9
9
|
"packageName": "com.callstack.agentdevice.snapshothelper",
|
|
10
|
-
"versionCode":
|
|
10
|
+
"versionCode": 21013,
|
|
11
11
|
"instrumentationRunner": "com.callstack.agentdevice.snapshothelper/.SnapshotInstrumentation",
|
|
12
12
|
"minSdk": 23,
|
|
13
13
|
"targetSdk": 36,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <mach/mach_time.h>
|
|
3
|
+
#import <math.h>
|
|
4
|
+
|
|
5
|
+
// Private simulator HID entry points; the host verifies the resulting hinge independently.
|
|
6
|
+
extern CFDataRef IOCFSerialize(CFTypeRef object, CFOptionFlags options);
|
|
7
|
+
extern CFTypeRef IOHIDEventCreateVendorDefinedEvent(CFAllocatorRef allocator, uint64_t timestamp,
|
|
8
|
+
uint32_t usagePage, uint32_t usage, uint32_t version, const uint8_t *data,
|
|
9
|
+
CFIndex length, uint32_t options);
|
|
10
|
+
extern CFTypeRef IOHIDEventSystemClientCreate(CFAllocatorRef allocator);
|
|
11
|
+
extern void IOHIDEventSystemClientDispatchEvent(CFTypeRef client, CFTypeRef event);
|
|
12
|
+
|
|
13
|
+
static BOOL sendAngle(CFTypeRef client, double angle) {
|
|
14
|
+
NSDictionary *payload = @{
|
|
15
|
+
@"provider": @"com.apple.Virtualization.VirtualMachines",
|
|
16
|
+
@"source": @"hinge-slider-control", @"type": @"range", @"value": @(angle),
|
|
17
|
+
};
|
|
18
|
+
CFDataRef data = IOCFSerialize((__bridge CFTypeRef)payload, 1);
|
|
19
|
+
if (!data) return NO;
|
|
20
|
+
CFTypeRef event = IOHIDEventCreateVendorDefinedEvent(kCFAllocatorDefault,
|
|
21
|
+
mach_absolute_time(), 0xff61, 0x5b, 0, CFDataGetBytePtr(data), CFDataGetLength(data), 0);
|
|
22
|
+
if (event) IOHIDEventSystemClientDispatchEvent(client, event);
|
|
23
|
+
CFRelease(data);
|
|
24
|
+
if (!event) return NO;
|
|
25
|
+
CFRelease(event);
|
|
26
|
+
return YES;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static BOOL validNumber(id value) {
|
|
30
|
+
return [value isKindOfClass:NSNumber.class] &&
|
|
31
|
+
CFGetTypeID((__bridge CFTypeRef)value) != CFBooleanGetTypeID() && isfinite([value doubleValue]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static NSArray *readFrames(NSString *argument) {
|
|
35
|
+
NSNumber *preset = (@{@"closed": @0, @"half-open": @130, @"open": @180})[argument];
|
|
36
|
+
if (preset) return @[@{@"atMs": @0, @"angle": preset}];
|
|
37
|
+
id frames = [NSJSONSerialization JSONObjectWithData:[argument dataUsingEncoding:NSUTF8StringEncoding]
|
|
38
|
+
options:0 error:NULL];
|
|
39
|
+
if (![frames isKindOfClass:NSArray.class] || [frames count] < 2 || [frames count] > 64) return nil;
|
|
40
|
+
double previous = -1;
|
|
41
|
+
for (id frame in frames) {
|
|
42
|
+
if (![frame isKindOfClass:NSDictionary.class] || [frame count] != 2 ||
|
|
43
|
+
!validNumber(frame[@"atMs"]) || !validNumber(frame[@"angle"])) return nil;
|
|
44
|
+
double time = [frame[@"atMs"] doubleValue], angle = [frame[@"angle"] doubleValue];
|
|
45
|
+
if (time < 0 || time > 60000 || floor(time) != time || time <= previous ||
|
|
46
|
+
(previous == -1 && time != 0) || angle < 0 || angle > 180) return nil;
|
|
47
|
+
previous = time;
|
|
48
|
+
}
|
|
49
|
+
return frames;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static double angleAtTime(NSArray *frames, double elapsed) {
|
|
53
|
+
NSUInteger segment = 0;
|
|
54
|
+
while (segment + 1 < frames.count && [frames[segment + 1][@"atMs"] doubleValue] <= elapsed) segment++;
|
|
55
|
+
double angle = [frames[segment][@"angle"] doubleValue];
|
|
56
|
+
if (segment + 1 < frames.count) {
|
|
57
|
+
double from = [frames[segment][@"atMs"] doubleValue];
|
|
58
|
+
double to = [frames[segment + 1][@"atMs"] doubleValue];
|
|
59
|
+
angle += ([frames[segment + 1][@"angle"] doubleValue] - angle) * (elapsed - from) / (to - from);
|
|
60
|
+
}
|
|
61
|
+
return angle;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static BOOL runFrames(CFTypeRef client, NSArray *frames) {
|
|
65
|
+
mach_timebase_info_data_t clock;
|
|
66
|
+
mach_timebase_info(&clock);
|
|
67
|
+
uint64_t start = mach_absolute_time();
|
|
68
|
+
double duration = [frames.lastObject[@"atMs"] doubleValue];
|
|
69
|
+
double elapsed = 0;
|
|
70
|
+
while (YES) {
|
|
71
|
+
@autoreleasepool {
|
|
72
|
+
if (!sendAngle(client, angleAtTime(frames, elapsed))) return NO;
|
|
73
|
+
}
|
|
74
|
+
if (elapsed >= duration) return YES;
|
|
75
|
+
double now = (mach_absolute_time() - start) * clock.numer / (double)clock.denom / 1e6;
|
|
76
|
+
// Absolute deadlines skip missed frames instead of extending the user's timeline.
|
|
77
|
+
double next = fmin(duration, (floor(now * 60 / 1000) + 1) * 1000 / 60);
|
|
78
|
+
mach_wait_until(start + (uint64_t)(next * 1e6 * clock.denom / clock.numer));
|
|
79
|
+
elapsed = fmin(duration, (mach_absolute_time() - start) * clock.numer / (double)clock.denom / 1e6);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
int main(int argc, const char *argv[]) {
|
|
84
|
+
@autoreleasepool {
|
|
85
|
+
NSArray *frames = argc == 2 ? readFrames(@(argv[1])) : nil;
|
|
86
|
+
if (!frames) {
|
|
87
|
+
fprintf(stderr, "Expected a pose or 2-64 {atMs,angle} keyframes spanning 0 to at most 60000ms\n");
|
|
88
|
+
return 2;
|
|
89
|
+
}
|
|
90
|
+
CFTypeRef client = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
|
|
91
|
+
if (!client) return 1;
|
|
92
|
+
BOOL dispatched = runFrames(client, frames);
|
|
93
|
+
CFRelease(client);
|
|
94
|
+
if (!dispatched) fprintf(stderr, "Unable to create simulator HID event\n");
|
|
95
|
+
return dispatched ? 0 : 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -14,20 +14,17 @@ let package = Package(
|
|
|
14
14
|
.target(
|
|
15
15
|
name: "AgentDeviceMacOSInput"
|
|
16
16
|
),
|
|
17
|
-
.target(
|
|
18
|
-
name: "AgentDeviceMacOSDeviceHub"
|
|
19
|
-
),
|
|
20
17
|
.executableTarget(
|
|
21
18
|
name: "AgentDeviceMacOSHelper",
|
|
22
|
-
dependencies: ["AgentDeviceMacOSInput"
|
|
19
|
+
dependencies: ["AgentDeviceMacOSInput"]
|
|
23
20
|
),
|
|
24
21
|
.testTarget(
|
|
25
22
|
name: "AgentDeviceMacOSInputTests",
|
|
26
23
|
dependencies: ["AgentDeviceMacOSInput"]
|
|
27
24
|
),
|
|
28
25
|
.testTarget(
|
|
29
|
-
name: "
|
|
30
|
-
dependencies: ["
|
|
26
|
+
name: "AgentDeviceMacOSHelperTests",
|
|
27
|
+
dependencies: ["AgentDeviceMacOSHelper"]
|
|
31
28
|
),
|
|
32
29
|
]
|
|
33
30
|
)
|
|
@@ -75,7 +75,6 @@ struct PressResponse: Encodable {
|
|
|
75
75
|
struct ScreenshotResponse: Encodable {
|
|
76
76
|
let path: String
|
|
77
77
|
let surface: String?
|
|
78
|
-
let fullscreen: Bool
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
struct AgentDeviceMacOSHelper {
|
|
@@ -127,8 +126,6 @@ struct AgentDeviceMacOSHelper {
|
|
|
127
126
|
return try handleScreenshot(arguments: Array(arguments.dropFirst()))
|
|
128
127
|
case "audio-probe":
|
|
129
128
|
return try handleAudioProbe(arguments: Array(arguments.dropFirst()))
|
|
130
|
-
case "device-hub":
|
|
131
|
-
return try handleDeviceHub(arguments: Array(arguments.dropFirst()))
|
|
132
129
|
default:
|
|
133
130
|
throw HelperError.invalidArgs("unknown command: \(command)")
|
|
134
131
|
}
|
|
@@ -438,9 +435,8 @@ struct AgentDeviceMacOSHelper {
|
|
|
438
435
|
}
|
|
439
436
|
|
|
440
437
|
let surface = optionValue(arguments: arguments, name: "--surface")
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
return SuccessEnvelope(data: ScreenshotResponse(path: outPath, surface: surface, fullscreen: fullscreen))
|
|
438
|
+
try captureSurfaceScreenshot(surface: surface, outPath: outPath)
|
|
439
|
+
return SuccessEnvelope(data: ScreenshotResponse(path: outPath, surface: surface))
|
|
444
440
|
}
|
|
445
441
|
|
|
446
442
|
static func handleAudioProbe(arguments: [String]) throws -> any Encodable {
|
|
@@ -549,8 +545,7 @@ private func pressAtPosition(_ request: MouseClickRequest) throws {
|
|
|
549
545
|
}
|
|
550
546
|
}
|
|
551
547
|
|
|
552
|
-
private func captureSurfaceScreenshot(surface: String?, outPath: String
|
|
553
|
-
_ = fullscreen
|
|
548
|
+
private func captureSurfaceScreenshot(surface: String?, outPath: String) throws {
|
|
554
549
|
guard #available(macOS 15.2, *) else {
|
|
555
550
|
throw HelperError.commandFailed(
|
|
556
551
|
"screenshot on macOS desktop and menubar surfaces requires macOS 15.2 or newer"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
|
|
3
|
+
@testable import AgentDeviceMacOSHelper
|
|
4
|
+
|
|
5
|
+
/// `captureSurfaceScreenshot` always reads the main display, so the response describes only
|
|
6
|
+
/// what was actually captured: no field for an argument the helper does not read.
|
|
7
|
+
final class ScreenshotResponseTests: XCTestCase {
|
|
8
|
+
func testResponseNeverCarriesAFullscreenField() throws {
|
|
9
|
+
let response = ScreenshotResponse(path: "/tmp/out.png", surface: "desktop")
|
|
10
|
+
let data = try JSONEncoder().encode(response)
|
|
11
|
+
let decoded = try JSONSerialization.jsonObject(with: data) as? [String: Any]
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(Set(decoded?.keys.map { $0 } ?? []), ["path", "surface"])
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
NSString *const kProtocolVersionKey = @"protocolVersion";
|
|
19
19
|
NSString *const kSourceVersionKey = @"sourceVersion";
|
|
20
20
|
NSString *const kRequestIdKey = @"requestId";
|
|
21
|
-
NSString *const kSourceVersion = @"agent-device-simulator-ax-v1.
|
|
21
|
+
NSString *const kSourceVersion = @"agent-device-simulator-ax-v1.7.0";
|
|
22
22
|
const NSUInteger kProtocolVersion = 1;
|
|
23
23
|
const uint32_t kMaximumFrameBytes = 16 * 1024 * 1024;
|
|
24
24
|
const NSUInteger kMaximumDepth = 128;
|
|
@@ -34,8 +34,11 @@ static NSString *const kAttributeFrame = @"XC_kAXXCAttributeFrame";
|
|
|
34
34
|
static NSString *const kAttributeAutomationType = @"XC_kAXXCAttributeAutomationType";
|
|
35
35
|
static NSString *const kAttributeTraits = @"XC_kAXXCAttributeTraits";
|
|
36
36
|
static NSString *const kAttributeChildren = @"XC_kAXXCAttributeChildren";
|
|
37
|
+
static NSString *const kAttributeIsUserInteractionEnabled = @"XC_kAXXCAttributeIsUserInteractionEnabled";
|
|
38
|
+
static NSString *const kPresentationDimmingViewClass = @"UIDimmingView";
|
|
37
39
|
static NSString *const kSnapshotAttributes = @"UIAccessibilitySnapshotKeyAttributes";
|
|
38
40
|
static NSString *const kSnapshotChildren = @"UIAccessibilitySnapshotKeyChildren";
|
|
41
|
+
static NSString *const kSnapshotElement = @"UIAccessibilitySnapshotKeyElement";
|
|
39
42
|
static NSString *const kXctAutomationSupportPath =
|
|
40
43
|
@"/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework/XCTAutomationSupport";
|
|
41
44
|
static NSString *const kAxRuntimePath =
|
|
@@ -202,8 +205,35 @@ static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogSt
|
|
|
202
205
|
return nil;
|
|
203
206
|
}
|
|
204
207
|
|
|
208
|
+
/*
|
|
209
|
+
* Whether a presentation's dimming view takes touches is what separates a sheet that blocks the
|
|
210
|
+
* content under it from one resting at an undimmed detent, and nothing else in the tree says so.
|
|
211
|
+
* It is read for dimming views alone: requesting it for every node costs about half again the
|
|
212
|
+
* capture time.
|
|
213
|
+
*/
|
|
214
|
+
- (nullable NSNumber *)userInteractionEnabledForSnapshot:(NSDictionary *)snapshot
|
|
215
|
+
options:(nullable NSDictionary *)options
|
|
216
|
+
{
|
|
217
|
+
id element = snapshot[kSnapshotElement];
|
|
218
|
+
NSNumber *attribute = [options[@"attributes"] firstObject];
|
|
219
|
+
if (!element || ![attribute isKindOfClass:NSNumber.class]) return nil;
|
|
220
|
+
@try {
|
|
221
|
+
NSError *failure = nil;
|
|
222
|
+
NSDictionary *read = [_framework userTestingSnapshotForElement:element options:options error:&failure];
|
|
223
|
+
if (![read isKindOfClass:NSDictionary.class]) return nil;
|
|
224
|
+
NSDictionary *attributes = read[kSnapshotAttributes];
|
|
225
|
+
if (![attributes isKindOfClass:NSDictionary.class]) return nil;
|
|
226
|
+
id value = attributes[attribute];
|
|
227
|
+
return [value isKindOfClass:NSNumber.class] ? @([(NSNumber *)value boolValue]) : nil;
|
|
228
|
+
} @catch (NSException *exception) {
|
|
229
|
+
(void)exception;
|
|
230
|
+
return nil;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
205
234
|
- (nullable NSDictionary *)nodeFromSnapshot:(id)snapshot
|
|
206
235
|
namesByNumber:(NSDictionary<NSNumber *, NSString *> *)namesByNumber
|
|
236
|
+
interactionOptions:(nullable NSDictionary *)interactionOptions
|
|
207
237
|
depth:(NSUInteger)depth
|
|
208
238
|
maxDepth:(NSUInteger)maxDepth
|
|
209
239
|
maxNodes:(NSUInteger)maxNodes
|
|
@@ -233,6 +263,11 @@ static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogSt
|
|
|
233
263
|
id safe = [self jsonValue:attributes[number] name:name];
|
|
234
264
|
if (safe) node[name] = safe;
|
|
235
265
|
}
|
|
266
|
+
if ([node[kAttributeElementType] isEqual:kPresentationDimmingViewClass]) {
|
|
267
|
+
NSNumber *interaction = [self userInteractionEnabledForSnapshot:(NSDictionary *)snapshot
|
|
268
|
+
options:interactionOptions];
|
|
269
|
+
if (interaction) node[kAttributeIsUserInteractionEnabled] = interaction;
|
|
270
|
+
}
|
|
236
271
|
|
|
237
272
|
NSArray *children = ((NSDictionary *)snapshot)[kSnapshotChildren];
|
|
238
273
|
if (![children isKindOfClass:NSArray.class]) {
|
|
@@ -246,6 +281,7 @@ static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogSt
|
|
|
246
281
|
for (id child in children) {
|
|
247
282
|
NSDictionary *built = [self nodeFromSnapshot:child
|
|
248
283
|
namesByNumber:namesByNumber
|
|
284
|
+
interactionOptions:interactionOptions
|
|
249
285
|
depth:depth + 1
|
|
250
286
|
maxDepth:maxDepth
|
|
251
287
|
maxNodes:maxNodes
|
|
@@ -317,6 +353,15 @@ static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogSt
|
|
|
317
353
|
options[@"maxDepth"] = @(maxDepth);
|
|
318
354
|
options[@"maxChildren"] = @(maxNodes);
|
|
319
355
|
options[@"maxArrayCount"] = @(maxNodes);
|
|
356
|
+
NSArray<NSNumber *> *interactionAttribute = _attributeNumbersForNames(@[ kAttributeIsUserInteractionEnabled ]);
|
|
357
|
+
NSMutableDictionary *interactionOptions = nil;
|
|
358
|
+
if ([interactionAttribute isKindOfClass:NSArray.class] && interactionAttribute.count == 1) {
|
|
359
|
+
interactionOptions = [options mutableCopy];
|
|
360
|
+
interactionOptions[@"attributes"] = interactionAttribute;
|
|
361
|
+
interactionOptions[@"maxDepth"] = @0;
|
|
362
|
+
interactionOptions[@"maxChildren"] = @0;
|
|
363
|
+
interactionOptions[@"maxArrayCount"] = @0;
|
|
364
|
+
}
|
|
320
365
|
BOOL automationEnabled = [self assertAutomationMode:YES];
|
|
321
366
|
NSError *runtimeError = nil;
|
|
322
367
|
id snapshot = nil;
|
|
@@ -372,6 +417,7 @@ static void finishRequestWatchdog(dispatch_source_t watchdog, SnapshotWatchdogSt
|
|
|
372
417
|
NSUInteger count = 0;
|
|
373
418
|
NSDictionary *tree = [self nodeFromSnapshot:snapshot
|
|
374
419
|
namesByNumber:namesByNumber
|
|
420
|
+
interactionOptions:interactionOptions
|
|
375
421
|
depth:0
|
|
376
422
|
maxDepth:maxDepth
|
|
377
423
|
maxNodes:maxNodes
|
|
@@ -56,14 +56,24 @@ int main(int argc, const char *argv[]) {
|
|
|
56
56
|
|
|
57
57
|
#else
|
|
58
58
|
#import <UIKit/UIKit.h>
|
|
59
|
+
#if TARGET_OS_IOS
|
|
60
|
+
#import <UserNotifications/UserNotifications.h>
|
|
61
|
+
#endif
|
|
59
62
|
|
|
60
63
|
@interface AgentDeviceRunnerViewController : UIViewController
|
|
61
64
|
@property(nonatomic, strong) UILabel *alertActionStatus;
|
|
65
|
+
@property(nonatomic, strong) UILabel *alertActivationBusyAnswer;
|
|
62
66
|
@property(nonatomic, assign) NSUInteger firstAlertActions;
|
|
63
67
|
@property(nonatomic, assign) NSUInteger replacementAlertActions;
|
|
64
68
|
@property(nonatomic, assign) BOOL alertFixtureStarted;
|
|
65
69
|
@property(nonatomic, strong) NSTimer *alertActivationBusyBackstop;
|
|
70
|
+
@property(nonatomic, strong) NSTimer *alertBannerRepost;
|
|
71
|
+
@end
|
|
72
|
+
|
|
73
|
+
#if TARGET_OS_IOS
|
|
74
|
+
@interface AgentDeviceRunnerViewController () <UNUserNotificationCenterDelegate>
|
|
66
75
|
@end
|
|
76
|
+
#endif
|
|
67
77
|
|
|
68
78
|
@implementation AgentDeviceRunnerViewController
|
|
69
79
|
|
|
@@ -72,15 +82,21 @@ int main(int argc, const char *argv[]) {
|
|
|
72
82
|
// may receive an event: the app keeps reporting work in flight, which is the state that cost an alert
|
|
73
83
|
// command its whole deadline in #2546. It stops the moment an alert button is answered, since that
|
|
74
84
|
// answer is the event the runner is trying to land, and the backstop stops it even when no answer
|
|
75
|
-
// arrives so a regressed run finishes rather than waiting out XCTest's own timeout.
|
|
85
|
+
// arrives so a regressed run finishes rather than waiting out XCTest's own timeout. The test passes
|
|
86
|
+
// the backstop after `--agent-device-alert-activation-busy`, sized to outlast its whole resolution
|
|
87
|
+
// and activation budget, so a slow host cannot end the busy state before the answer lands. A layer
|
|
76
88
|
// animation on its own is not enough; only a UIView animation counts as in-flight work here.
|
|
77
|
-
static NSTimeInterval
|
|
89
|
+
static NSTimeInterval AgentDeviceAlertActivationBusyWindow(void) {
|
|
90
|
+
NSArray<NSString *> *arguments = NSProcessInfo.processInfo.arguments;
|
|
91
|
+
NSUInteger flag = [arguments indexOfObject:@"--agent-device-alert-activation-busy"];
|
|
92
|
+
return flag + 1 < arguments.count ? arguments[flag + 1].doubleValue : 0;
|
|
93
|
+
}
|
|
78
94
|
|
|
79
95
|
- (void)startAlertActivationBusy {
|
|
80
96
|
if (self.alertActivationBusyBackstop != nil) {
|
|
81
97
|
return;
|
|
82
98
|
}
|
|
83
|
-
self.alertActivationBusyBackstop = [NSTimer scheduledTimerWithTimeInterval:
|
|
99
|
+
self.alertActivationBusyBackstop = [NSTimer scheduledTimerWithTimeInterval:AgentDeviceAlertActivationBusyWindow()
|
|
84
100
|
target:self
|
|
85
101
|
selector:@selector(stopAlertActivationBusy)
|
|
86
102
|
userInfo:nil
|
|
@@ -101,6 +117,57 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
101
117
|
self.alertActivationBusyBackstop = nil;
|
|
102
118
|
}
|
|
103
119
|
|
|
120
|
+
// A banner from this app, shown over its own alert and re-posted before the previous one expires so
|
|
121
|
+
// one is on screen for as long as the first alert is unanswered. XCTest treats such a banner as an
|
|
122
|
+
// interruption of every event aimed at the app (#2546's late tap, from the banner side).
|
|
123
|
+
- (void)startAlertBannerThen:(dispatch_block_t)presentAlert {
|
|
124
|
+
UNUserNotificationCenter *center = UNUserNotificationCenter.currentNotificationCenter;
|
|
125
|
+
center.delegate = self;
|
|
126
|
+
[center requestAuthorizationWithOptions:UNAuthorizationOptionAlert
|
|
127
|
+
completionHandler:^(BOOL granted, NSError *error) {
|
|
128
|
+
(void)error;
|
|
129
|
+
if (!granted) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
133
|
+
presentAlert();
|
|
134
|
+
[self postAlertBanner];
|
|
135
|
+
self.alertBannerRepost = [NSTimer scheduledTimerWithTimeInterval:2.0
|
|
136
|
+
target:self
|
|
137
|
+
selector:@selector(postAlertBanner)
|
|
138
|
+
userInfo:nil
|
|
139
|
+
repeats:YES];
|
|
140
|
+
});
|
|
141
|
+
}];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
- (void)postAlertBanner {
|
|
145
|
+
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
|
|
146
|
+
content.title = @"Agent Device banner";
|
|
147
|
+
content.body = @"Shown over the alert fixture";
|
|
148
|
+
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:NSUUID.UUID.UUIDString
|
|
149
|
+
content:content
|
|
150
|
+
trigger:nil];
|
|
151
|
+
[UNUserNotificationCenter.currentNotificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
- (void)stopAlertBanner {
|
|
155
|
+
if (self.alertBannerRepost == nil) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
[self.alertBannerRepost invalidate];
|
|
159
|
+
self.alertBannerRepost = nil;
|
|
160
|
+
[UNUserNotificationCenter.currentNotificationCenter removeAllDeliveredNotifications];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
|
164
|
+
willPresentNotification:(UNNotification *)notification
|
|
165
|
+
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
|
|
166
|
+
(void)center;
|
|
167
|
+
(void)notification;
|
|
168
|
+
completionHandler(UNNotificationPresentationOptionBanner);
|
|
169
|
+
}
|
|
170
|
+
|
|
104
171
|
|
|
105
172
|
- (void)updateAlertActionStatus {
|
|
106
173
|
self.alertActionStatus.text = [NSString stringWithFormat:@"First actions: %lu; replacement actions: %lu",
|
|
@@ -123,7 +190,12 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
123
190
|
? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
|
|
124
191
|
[alert addAction:[UIAlertAction actionWithTitle:buttonTitle style:style handler:^(UIAlertAction *action) {
|
|
125
192
|
(void)action;
|
|
193
|
+
if (!replacement) {
|
|
194
|
+
self.alertActivationBusyAnswer.text = self.alertActivationBusyBackstop != nil
|
|
195
|
+
? @"Answered while busy" : @"Answered after the app went idle";
|
|
196
|
+
}
|
|
126
197
|
[self stopAlertActivationBusy];
|
|
198
|
+
[self stopAlertBanner];
|
|
127
199
|
if (replacement) {
|
|
128
200
|
self.replacementAlertActions += 1;
|
|
129
201
|
} else {
|
|
@@ -145,9 +217,16 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
145
217
|
if (!self.alertFixtureStarted &&
|
|
146
218
|
[NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-replacement-regression"]) {
|
|
147
219
|
self.alertFixtureStarted = YES;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
[
|
|
220
|
+
dispatch_block_t presentAlert = ^{
|
|
221
|
+
[self presentAlertFixtureReplacement:NO];
|
|
222
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-activation-busy"]) {
|
|
223
|
+
[self startAlertActivationBusy];
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-banner"]) {
|
|
227
|
+
[self startAlertBannerThen:presentAlert];
|
|
228
|
+
} else {
|
|
229
|
+
presentAlert();
|
|
151
230
|
}
|
|
152
231
|
}
|
|
153
232
|
}
|
|
@@ -185,6 +264,19 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
185
264
|
[self updateAlertActionStatus];
|
|
186
265
|
}
|
|
187
266
|
|
|
267
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-alert-activation-busy"]) {
|
|
268
|
+
UILabel *busyAnswer = [[UILabel alloc] init];
|
|
269
|
+
busyAnswer.text = @"Unanswered";
|
|
270
|
+
busyAnswer.accessibilityIdentifier = @"agent-device-alert-busy-answer";
|
|
271
|
+
busyAnswer.translatesAutoresizingMaskIntoConstraints = NO;
|
|
272
|
+
[self.view addSubview:busyAnswer];
|
|
273
|
+
[NSLayoutConstraint activateConstraints:@[
|
|
274
|
+
[busyAnswer.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
|
|
275
|
+
[busyAnswer.topAnchor constraintEqualToAnchor:label.bottomAnchor constant:24],
|
|
276
|
+
]];
|
|
277
|
+
self.alertActivationBusyAnswer = busyAnswer;
|
|
278
|
+
}
|
|
279
|
+
|
|
188
280
|
if ([NSProcessInfo.processInfo.arguments containsObject:@"--agent-device-text-entry-regression"]) {
|
|
189
281
|
UITextField *textField = [[UITextField alloc] init];
|
|
190
282
|
textField.accessibilityIdentifier = @"agent-device-hardware-keyboard-input";
|
|
@@ -227,7 +319,7 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
227
319
|
|
|
228
320
|
@end
|
|
229
321
|
|
|
230
|
-
|
|
322
|
+
// UIApplicationSceneManifest in Info.plist names this class; a rename must update the manifest.
|
|
231
323
|
@interface AgentDeviceRunnerSceneDelegate : UIResponder <UIWindowSceneDelegate>
|
|
232
324
|
@property(nonatomic, strong) UIWindow *window;
|
|
233
325
|
@end
|
|
@@ -250,46 +342,11 @@ static NSTimeInterval const kAgentDeviceAlertActivationBusyWindow = 20.0;
|
|
|
250
342
|
}
|
|
251
343
|
|
|
252
344
|
@end
|
|
253
|
-
#endif
|
|
254
345
|
|
|
255
346
|
@interface AgentDeviceRunnerAppDelegate : UIResponder <UIApplicationDelegate>
|
|
256
|
-
@property(nonatomic, strong) UIWindow *window;
|
|
257
347
|
@end
|
|
258
348
|
|
|
259
349
|
@implementation AgentDeviceRunnerAppDelegate
|
|
260
|
-
|
|
261
|
-
- (BOOL)application:(UIApplication *)application
|
|
262
|
-
didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
|
|
263
|
-
(void)application;
|
|
264
|
-
(void)launchOptions;
|
|
265
|
-
|
|
266
|
-
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
|
|
267
|
-
return YES;
|
|
268
|
-
#else
|
|
269
|
-
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
|
|
270
|
-
self.window.rootViewController = [[AgentDeviceRunnerViewController alloc] init];
|
|
271
|
-
[self.window makeKeyAndVisible];
|
|
272
|
-
|
|
273
|
-
return YES;
|
|
274
|
-
#endif
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
|
|
278
|
-
- (UISceneConfiguration *)application:(UIApplication *)application
|
|
279
|
-
configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession
|
|
280
|
-
options:(UISceneConnectionOptions *)options {
|
|
281
|
-
(void)application;
|
|
282
|
-
(void)connectingSceneSession;
|
|
283
|
-
(void)options;
|
|
284
|
-
|
|
285
|
-
UISceneConfiguration *configuration =
|
|
286
|
-
[[UISceneConfiguration alloc] initWithName:@"Default Configuration"
|
|
287
|
-
sessionRole:UIWindowSceneSessionRoleApplication];
|
|
288
|
-
configuration.delegateClass = AgentDeviceRunnerSceneDelegate.class;
|
|
289
|
-
return configuration;
|
|
290
|
-
}
|
|
291
|
-
#endif
|
|
292
|
-
|
|
293
350
|
@end
|
|
294
351
|
|
|
295
352
|
int main(int argc, char *argv[]) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>UIApplicationSceneManifest</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>UIApplicationSupportsMultipleScenes</key>
|
|
8
|
+
<false/>
|
|
9
|
+
<key>UISceneConfigurations</key>
|
|
10
|
+
<dict>
|
|
11
|
+
<key>UIWindowSceneSessionRoleApplication</key>
|
|
12
|
+
<array>
|
|
13
|
+
<dict>
|
|
14
|
+
<key>UISceneConfigurationName</key>
|
|
15
|
+
<string>Default Configuration</string>
|
|
16
|
+
<key>UISceneDelegateClassName</key>
|
|
17
|
+
<string>AgentDeviceRunnerSceneDelegate</string>
|
|
18
|
+
</dict>
|
|
19
|
+
</array>
|
|
20
|
+
</dict>
|
|
21
|
+
</dict>
|
|
22
|
+
</dict>
|
|
23
|
+
</plist>
|
|
@@ -21,9 +21,22 @@
|
|
|
21
21
|
20EA2EDD2F2CFC7C001CF0EF /* AgentDeviceRunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AgentDeviceRunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
22
22
|
/* End PBXFileReference section */
|
|
23
23
|
|
|
24
|
+
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
|
25
|
+
20EA2EF02F2CFC7C001CF0EF /* Exceptions for "AgentDeviceRunner" folder in "AgentDeviceRunner" target */ = {
|
|
26
|
+
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
|
27
|
+
membershipExceptions = (
|
|
28
|
+
Info.plist,
|
|
29
|
+
);
|
|
30
|
+
target = 20EA2EC52F2CFC7B001CF0EF /* AgentDeviceRunner */;
|
|
31
|
+
};
|
|
32
|
+
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
|
33
|
+
|
|
24
34
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
|
25
35
|
20EA2EC82F2CFC7B001CF0EF /* AgentDeviceRunner */ = {
|
|
26
36
|
isa = PBXFileSystemSynchronizedRootGroup;
|
|
37
|
+
exceptions = (
|
|
38
|
+
20EA2EF02F2CFC7C001CF0EF /* Exceptions for "AgentDeviceRunner" folder in "AgentDeviceRunner" target */,
|
|
39
|
+
);
|
|
27
40
|
path = AgentDeviceRunner;
|
|
28
41
|
sourceTree = "<group>";
|
|
29
42
|
};
|
|
@@ -352,6 +365,8 @@
|
|
|
352
365
|
DEVELOPMENT_TEAM = 2S799L9W4M;
|
|
353
366
|
ENABLE_PREVIEWS = YES;
|
|
354
367
|
GENERATE_INFOPLIST_FILE = YES;
|
|
368
|
+
INFOPLIST_FILE = AgentDeviceRunner/Info.plist;
|
|
369
|
+
"INFOPLIST_FILE[sdk=macosx*]" = "";
|
|
355
370
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO;
|
|
356
371
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
|
357
372
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
|
@@ -386,6 +401,8 @@
|
|
|
386
401
|
DEVELOPMENT_TEAM = 2S799L9W4M;
|
|
387
402
|
ENABLE_PREVIEWS = YES;
|
|
388
403
|
GENERATE_INFOPLIST_FILE = YES;
|
|
404
|
+
INFOPLIST_FILE = AgentDeviceRunner/Info.plist;
|
|
405
|
+
"INFOPLIST_FILE[sdk=macosx*]" = "";
|
|
389
406
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO;
|
|
390
407
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
|
391
408
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerAppScreenCapture.swift
CHANGED
|
@@ -54,6 +54,21 @@ enum RunnerAppScreenCaptureFailure: String, Error {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
extension RunnerTests {
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
func selectObservedScreenCapture(
|
|
61
|
+
resolving: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
62
|
+
fallingBack: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>
|
|
63
|
+
) -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure> {
|
|
64
|
+
let outcome = resolving()
|
|
65
|
+
if case .failure(.unresolvedWindow) = outcome {
|
|
66
|
+
return fallingBack()
|
|
67
|
+
}
|
|
68
|
+
return outcome
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
#if canImport(UIKit) && os(iOS)
|
|
58
73
|
extension RunnerTests {
|
|
59
74
|
|
|
@@ -103,19 +118,6 @@ extension RunnerTests {
|
|
|
103
118
|
)
|
|
104
119
|
}
|
|
105
120
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
func selectObservedScreenCapture(
|
|
109
|
-
resolving: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>,
|
|
110
|
-
fallingBack: () -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure>
|
|
111
|
-
) -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure> {
|
|
112
|
-
let outcome = resolving()
|
|
113
|
-
if case .failure(.unresolvedWindow) = outcome {
|
|
114
|
-
return fallingBack()
|
|
115
|
-
}
|
|
116
|
-
return outcome
|
|
117
|
-
}
|
|
118
|
-
|
|
119
121
|
private static func resolveCapturedAppScreen(
|
|
120
122
|
app: XCUIApplication
|
|
121
123
|
) -> Result<CapturedAppScreen, RunnerAppScreenCaptureFailure> {
|
|
@@ -140,6 +142,12 @@ extension RunnerTests {
|
|
|
140
142
|
guard let cgImage = runnerCGImage(from: upright) else {
|
|
141
143
|
return .failure(.unrenderableImage)
|
|
142
144
|
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
guard cgImage.width > 0, cgImage.height > 0 else {
|
|
149
|
+
return .failure(.unrenderableImage)
|
|
150
|
+
}
|
|
143
151
|
return .success(
|
|
144
152
|
CapturedAppScreen(
|
|
145
153
|
image: upright,
|