@devicelab/maestro-runner-darwin-arm64 1.1.29 → 1.1.30
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 +15 -4
- package/bin/maestro-runner +0 -0
- package/drivers/android/devicelab-android-driver-test.apk +0 -0
- package/drivers/android/devicelab-android-driver.apk +0 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/ATTRIBUTION.md +16 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests+Lifecycle.swift +33 -0
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests+Snapshot.swift +195 -88
- package/drivers/ios/DevicelabIOSRunner/DevicelabIOSRunnerUITests/RunnerTests.swift +3 -0
- package/drivers/ios/WebDriverAgent/CHANGELOG.md +202 -0
- package/drivers/ios/WebDriverAgent/README.md +18 -9
- package/drivers/ios/WebDriverAgent/Scripts/ci/build-real.sh +6 -10
- package/drivers/ios/WebDriverAgent/Scripts/fetch-prebuilt-wda.mjs +3 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgent.xcodeproj/project.pbxproj +119 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCAXClient_iOS+FBSnapshotReqParams.m +8 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.h +3 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBHelpers.m +30 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.h +53 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIApplication+FBTouchAction.m +124 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h +6 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +100 -23
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHinge.h +41 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBHinge.m +215 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIDevice+FBRotation.m +8 -3
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +20 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m +110 -50
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBTyping.h +7 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBTyping.m +20 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Categories/XCUIElement+FBUtilities.m +14 -11
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBCustomCommands.m +86 -10
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBElementCommands.m +57 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Commands/FBSessionCommands.m +3 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Info.plist +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBHTTPServer.m +39 -16
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBScreenRecordingRequest.m +7 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBSession.h +22 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBSession.m +78 -12
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBTCPSocket.h +5 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBTCPSocket.m +10 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Routing/FBWebServer.m +4 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.h +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBActiveAppDetectionPoint.m +20 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBConfiguration.h +8 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBConfiguration.m +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBHIDOperations.h +41 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBHIDOperations.m +244 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBImageProcessor.m +3 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMathUtils.h +11 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMathUtils.m +38 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBMjpegServer.m +5 -3
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreen.h +17 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreen.m +76 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreenshot.h +2 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBScreenshot.m +6 -2
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettings.h +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettings.m +2 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBSettingsHandler.m +48 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBW3CActionsSynthesizer.m +121 -13
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/FBXPath.m +181 -128
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/LRUCache/LRUCache.m +8 -5
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/Utilities/LRUCache/LRUCacheNode.h +1 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentLib/WebDriverAgentLib.h +1 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/COORDINATE_PROBE.md +3 -1
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/FBCoordinateProbeViewController.m +18 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/SceneDelegate.m +33 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationApp/Classes/ViewController.m +26 -7
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBConfigurationTests.m +52 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBDisplayGestureTests.m +541 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBElementSwipingTests.m +95 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBImageProcessorTests.m +34 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBScreenTests.m +392 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBSessionIntegrationTests.m +97 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBTypingTest.m +33 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/FBW3CTouchActionsIntegrationTests.m +126 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIApplicationHelperTests.m +111 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +97 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIDeviceRotationTests.m +53 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +113 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests_tvOS/FBTVFocusIntegrationTests.m +21 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/IntegrationTests_watchOS/WDAAppLifecycleIntegrationTests.swift +12 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBCustomCommandsTests.m +61 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBElementUtilitiesTests.m +40 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBHTTPServerSessionTests.m +22 -4
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBHTTPServerTests.m +199 -5
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBLRUCacheTests.m +34 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBMathUtilsTests.m +45 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBSessionTests.m +201 -0
- package/drivers/ios/WebDriverAgent/WebDriverAgentTests/UnitTests/FBXPathTests.m +101 -0
- package/drivers/ios/WebDriverAgent/docs/hinge-angle.md +54 -0
- package/drivers/ios/WebDriverAgent/docs/multiple-displays.md +168 -0
- package/drivers/ios/WebDriverAgent/lib/webdriveragent.ts +1 -2
- package/drivers/ios/WebDriverAgent/lib/xcodebuild.ts +58 -10
- package/drivers/ios/WebDriverAgent/package.json +8 -15
- package/drivers/ios/WebDriverAgent/test/functional/helpers/display-settings.ts +49 -0
- package/drivers/ios/WebDriverAgent/test/functional/helpers/simulator.ts +7 -7
- package/drivers/ios/WebDriverAgent/test/functional/webdriveragent-e2e.spec.ts +4 -0
- package/drivers/ios/WebDriverAgent/test/unit/xcodebuild.spec.ts +230 -0
- package/drivers/ios/WebDriverAgent/tsconfig.json +2 -1
- package/drivers/ios/devicelab-ios-agent/README.md +12 -0
- package/drivers/ios/devicelab-ios-agent/device/DevicelabIOSAgent.app/DevicelabIOSAgent +0 -0
- package/drivers/ios/devicelab-ios-agent/device/DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests +0 -0
- package/drivers/ios/devicelab-ios-agent/device/manifest.json +3 -3
- package/drivers/ios/devicelab-ios-agent/simulator/DevicelabIOSAgent.app/DevicelabIOSAgent +0 -0
- package/drivers/ios/devicelab-ios-agent/simulator/DevicelabIOSAgentUITests-Runner.app/PlugIns/DevicelabIOSAgentUITests.xctest/DevicelabIOSAgentUITests +0 -0
- package/drivers/ios/devicelab-ios-agent/simulator/manifest.json +3 -3
- package/package.json +1 -1
- package/drivers/ios/WebDriverAgent/.editorconfig +0 -11
- package/drivers/ios/WebDriverAgent/.github/ISSUE_TEMPLATE.md +0 -4
- package/drivers/ios/WebDriverAgent/.github/actions/xcode-setup/action.yml +0 -32
- package/drivers/ios/WebDriverAgent/.github/dependabot.yml +0 -22
- package/drivers/ios/WebDriverAgent/.github/workflows/functional-test.yml +0 -103
- package/drivers/ios/WebDriverAgent/.github/workflows/pr-title.yml +0 -10
- package/drivers/ios/WebDriverAgent/.github/workflows/publish.js.yml +0 -112
- package/drivers/ios/WebDriverAgent/.github/workflows/unit-test.yml +0 -32
- package/drivers/ios/WebDriverAgent/.github/workflows/wda-package.yml +0 -114
- package/drivers/ios/WebDriverAgent/.github/workflows/wda-tests.yml +0 -246
- package/drivers/ios/WebDriverAgent/oxfmt.config.mjs +0 -6
- package/drivers/ios/WebDriverAgent/oxlint.config.mjs +0 -6
- package/drivers/ios/WebDriverAgent/release.config.mjs +0 -14
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#import <XCTest/XCTest.h>
|
|
10
|
+
#import <UIKit/UIKit.h>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
HID paths for Home, lock/unlock, and rotation on hinged iOS devices.
|
|
14
|
+
|
|
15
|
+
Remove each workaround once its XCTest-only path passes the corresponding regression
|
|
16
|
+
test on supported runtimes and both panels: testHomeButtonBackgroundsApplication,
|
|
17
|
+
testRepeatedLockUnlockAcrossHingePoses, and testRotationOnSelectedDuoDisplay.
|
|
18
|
+
Physical-device Home, lock/unlock, and rotation behavior require verification.
|
|
19
|
+
|
|
20
|
+
Once all paths are obsolete, remove the FBHIDOperations branches and imports from
|
|
21
|
+
XCUIDevice+FBHelpers.m and XCUIDevice+FBRotation.m, then delete this module and its
|
|
22
|
+
Xcode project entries. Hinge control in XCUIDevice+FBHinge is independent.
|
|
23
|
+
|
|
24
|
+
Tracking: https://github.com/appium/appium/issues/22857
|
|
25
|
+
Rotation: https://github.com/appium/appium-ios/pull/81
|
|
26
|
+
*/
|
|
27
|
+
@interface FBHIDOperations : NSObject
|
|
28
|
+
|
|
29
|
+
// All operations apply to hinged iOS devices, including physical devices.
|
|
30
|
+
+ (BOOL)appliesToDevice:(XCUIDevice *)device;
|
|
31
|
+
|
|
32
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
33
|
+
// Call only after the corresponding applicability check succeeds.
|
|
34
|
+
+ (BOOL)pressHomeWithError:(NSError **)error;
|
|
35
|
+
+ (BOOL)pressLockWithError:(NSError **)error;
|
|
36
|
+
// interfaceOrientation is the UIKit equivalent of the requested device orientation.
|
|
37
|
+
+ (BOOL)rotateToOrientation:(UIDeviceOrientation)orientation
|
|
38
|
+
interfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
@end
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2015-present, Facebook, Inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the BSD-style license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#import "FBHIDOperations.h"
|
|
10
|
+
|
|
11
|
+
#import <dlfcn.h>
|
|
12
|
+
#import <mach/mach_time.h>
|
|
13
|
+
|
|
14
|
+
#import "FBConfiguration.h"
|
|
15
|
+
#import "FBErrorBuilder.h"
|
|
16
|
+
#import "FBLogger.h"
|
|
17
|
+
#import "FBRunLoopSpinner.h"
|
|
18
|
+
#import "FBScreen.h"
|
|
19
|
+
#import "FBSession.h"
|
|
20
|
+
#import "XCUIScreen.h"
|
|
21
|
+
#import "XCUIDevice+FBHinge.h"
|
|
22
|
+
#import "XCUIApplication.h"
|
|
23
|
+
#import "XCUIApplication+FBHelpers.h"
|
|
24
|
+
#import "XCUIElement+FBUtilities.h"
|
|
25
|
+
|
|
26
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
27
|
+
|
|
28
|
+
static const uint32_t FBHIDConsumerUsagePage = 0x0C;
|
|
29
|
+
static const uint32_t FBHIDHomeUsage = 0x40;
|
|
30
|
+
static const uint32_t FBHIDPowerUsage = 0x30;
|
|
31
|
+
static const uint32_t FBHIDOrientationUsagePage = 0xff61;
|
|
32
|
+
static const uint32_t FBHIDOrientationUsage = 0x5b;
|
|
33
|
+
static const CFOptionFlags FBHIDBinarySerialization = 1;
|
|
34
|
+
static const NSTimeInterval FBHIDButtonPressDuration = 0.03;
|
|
35
|
+
static const NSTimeInterval FBHIDRotationTimeout = 5.0;
|
|
36
|
+
|
|
37
|
+
typedef struct {
|
|
38
|
+
CFTypeRef (*createKeyboardEvent)(CFAllocatorRef, uint64_t, uint32_t, uint32_t, Boolean, uint32_t);
|
|
39
|
+
CFTypeRef (*createVendorEvent)(CFAllocatorRef, uint64_t, uint32_t, uint32_t,
|
|
40
|
+
uint32_t, uint8_t *, CFIndex, uint32_t);
|
|
41
|
+
CFTypeRef (*createClient)(CFAllocatorRef);
|
|
42
|
+
void (*dispatchEvent)(CFTypeRef, CFTypeRef);
|
|
43
|
+
void (*setTimestamp)(CFTypeRef, uint64_t);
|
|
44
|
+
CFDataRef (*serialize)(CFTypeRef, CFOptionFlags);
|
|
45
|
+
} FBHIDAPI;
|
|
46
|
+
|
|
47
|
+
static const FBHIDAPI *FBGetHIDAPI(void)
|
|
48
|
+
{
|
|
49
|
+
static FBHIDAPI api;
|
|
50
|
+
static dispatch_once_t onceToken;
|
|
51
|
+
dispatch_once(&onceToken, ^{
|
|
52
|
+
// Keep the framework loaded for the lifetime of the cached function pointers.
|
|
53
|
+
void *handle = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_LAZY);
|
|
54
|
+
if (NULL == handle) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
api.createKeyboardEvent = (CFTypeRef (*)(CFAllocatorRef, uint64_t, uint32_t, uint32_t, Boolean, uint32_t))
|
|
58
|
+
dlsym(handle, "IOHIDEventCreateKeyboardEvent");
|
|
59
|
+
api.createVendorEvent = (CFTypeRef (*)(CFAllocatorRef, uint64_t, uint32_t, uint32_t,
|
|
60
|
+
uint32_t, uint8_t *, CFIndex, uint32_t))
|
|
61
|
+
dlsym(handle, "IOHIDEventCreateVendorDefinedEvent");
|
|
62
|
+
api.createClient = (CFTypeRef (*)(CFAllocatorRef))dlsym(handle, "IOHIDEventSystemClientCreate");
|
|
63
|
+
api.dispatchEvent = (void (*)(CFTypeRef, CFTypeRef))dlsym(handle, "IOHIDEventSystemClientDispatchEvent");
|
|
64
|
+
api.setTimestamp = (void (*)(CFTypeRef, uint64_t))dlsym(handle, "IOHIDEventSetTimeStamp");
|
|
65
|
+
api.serialize = (CFDataRef (*)(CFTypeRef, CFOptionFlags))dlsym(handle, "IOCFSerialize");
|
|
66
|
+
});
|
|
67
|
+
// Each operation checks only the symbols it needs.
|
|
68
|
+
return &api;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static void FBLogUnverifiedPhysicalHIDOperation(NSString *operation)
|
|
72
|
+
{
|
|
73
|
+
#if !TARGET_OS_SIMULATOR
|
|
74
|
+
[FBLogger logFmt:@"HID %@ on physical hinged devices: not verified yet.", operation];
|
|
75
|
+
#endif
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static BOOL FBWaitForStableInterfaceOrientation(XCUIApplication *application,
|
|
79
|
+
UIInterfaceOrientation orientation)
|
|
80
|
+
{
|
|
81
|
+
[application fb_waitUntilStableWithTimeout:FBConfiguration.sharedInstance.animationCoolOffTimeout];
|
|
82
|
+
return application.interfaceOrientation == orientation;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Workaround tracked in https://github.com/appium/appium/issues/22857.
|
|
86
|
+
// Reproduced on the iOS 27.1 Duo simulator with Xcode 27.1: XCTest's Home
|
|
87
|
+
// request returns without backgrounding the app. This direct HID path is also
|
|
88
|
+
// enabled on physical hinged devices, but Home behavior there is unverified.
|
|
89
|
+
// The affected Xcode/runtime version range has not been established. Remove
|
|
90
|
+
// the Home workaround when XCTest-only presses pass testHomeButtonBackgroundsApplication
|
|
91
|
+
// on supported Duo environments, including physical devices and both panels.
|
|
92
|
+
static BOOL FBPressHIDButton(uint32_t usage, NSError **error)
|
|
93
|
+
{
|
|
94
|
+
const FBHIDAPI *api = FBGetHIDAPI();
|
|
95
|
+
if (NULL == api->createKeyboardEvent || NULL == api->createClient
|
|
96
|
+
|| NULL == api->dispatchEvent || NULL == api->setTimestamp) {
|
|
97
|
+
return [[FBErrorBuilder.builder withDescription:@"The button HID APIs are unavailable"] buildError:error];
|
|
98
|
+
}
|
|
99
|
+
CFTypeRef client = api->createClient(kCFAllocatorDefault);
|
|
100
|
+
CFTypeRef down = api->createKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(),
|
|
101
|
+
FBHIDConsumerUsagePage, usage, YES, 0);
|
|
102
|
+
CFTypeRef up = api->createKeyboardEvent(kCFAllocatorDefault, mach_absolute_time(),
|
|
103
|
+
FBHIDConsumerUsagePage, usage, NO, 0);
|
|
104
|
+
BOOL ready = NULL != client && NULL != down && NULL != up;
|
|
105
|
+
if (ready) {
|
|
106
|
+
// Dispatch a short paired press. Holding Power for 0.5s invokes Siri on Duo.
|
|
107
|
+
api->dispatchEvent(client, down);
|
|
108
|
+
[NSThread sleepForTimeInterval:FBHIDButtonPressDuration];
|
|
109
|
+
api->setTimestamp(up, mach_absolute_time());
|
|
110
|
+
api->dispatchEvent(client, up);
|
|
111
|
+
}
|
|
112
|
+
if (NULL != down) {
|
|
113
|
+
CFRelease(down);
|
|
114
|
+
}
|
|
115
|
+
if (NULL != up) {
|
|
116
|
+
CFRelease(up);
|
|
117
|
+
}
|
|
118
|
+
if (NULL != client) {
|
|
119
|
+
CFRelease(client);
|
|
120
|
+
}
|
|
121
|
+
return ready || [[FBErrorBuilder.builder
|
|
122
|
+
withDescription:@"Cannot create the button HID event or client"] buildError:error];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Work around XCTest updating Duo device orientation without rotating the app.
|
|
126
|
+
// Reproduction details and checks required before removing this workaround:
|
|
127
|
+
// https://github.com/appium/appium-ios/pull/81
|
|
128
|
+
static BOOL FBDispatchHIDOrientation(UIDeviceOrientation orientation)
|
|
129
|
+
{
|
|
130
|
+
XCUIScreen *screen = [FBScreen currentScreenWithError:nil];
|
|
131
|
+
if (nil == screen) {
|
|
132
|
+
return NO;
|
|
133
|
+
}
|
|
134
|
+
// The inner panel's native orientation is a quarter turn from the cover.
|
|
135
|
+
// Values match DeviceKit's orientation-picker-control (Xcode 27.1).
|
|
136
|
+
NSString *value;
|
|
137
|
+
switch (orientation) {
|
|
138
|
+
case UIDeviceOrientationPortrait:
|
|
139
|
+
value = screen.isMainScreen ? @"portrait" : @"landscape-left";
|
|
140
|
+
break;
|
|
141
|
+
case UIDeviceOrientationLandscapeLeft:
|
|
142
|
+
value = screen.isMainScreen ? @"landscape-left" : @"pud";
|
|
143
|
+
break;
|
|
144
|
+
case UIDeviceOrientationLandscapeRight:
|
|
145
|
+
value = screen.isMainScreen ? @"landscape-right" : @"portrait";
|
|
146
|
+
break;
|
|
147
|
+
case UIDeviceOrientationPortraitUpsideDown:
|
|
148
|
+
value = screen.isMainScreen ? @"pud" : @"landscape-right";
|
|
149
|
+
break;
|
|
150
|
+
case UIDeviceOrientationUnknown:
|
|
151
|
+
case UIDeviceOrientationFaceUp:
|
|
152
|
+
case UIDeviceOrientationFaceDown:
|
|
153
|
+
default:
|
|
154
|
+
return NO;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const FBHIDAPI *api = FBGetHIDAPI();
|
|
158
|
+
if (NULL == api->serialize || NULL == api->createVendorEvent
|
|
159
|
+
|| NULL == api->createClient || NULL == api->dispatchEvent) {
|
|
160
|
+
return NO;
|
|
161
|
+
}
|
|
162
|
+
NSDictionary *payload = @{
|
|
163
|
+
@"provider": @"com.apple.Virtualization.VirtualMachines",
|
|
164
|
+
@"source": @"orientation-picker-control",
|
|
165
|
+
@"type": @"enum",
|
|
166
|
+
@"value": value,
|
|
167
|
+
};
|
|
168
|
+
// The receiver expects IOCF binary serialization, not a binary plist.
|
|
169
|
+
CFDataRef data = api->serialize((__bridge CFTypeRef)payload, FBHIDBinarySerialization);
|
|
170
|
+
if (NULL == data) {
|
|
171
|
+
return NO;
|
|
172
|
+
}
|
|
173
|
+
CFTypeRef event = api->createVendorEvent(kCFAllocatorDefault, mach_absolute_time(),
|
|
174
|
+
FBHIDOrientationUsagePage, FBHIDOrientationUsage, 0,
|
|
175
|
+
(uint8_t *)CFDataGetBytePtr(data), CFDataGetLength(data), 0);
|
|
176
|
+
CFRelease(data);
|
|
177
|
+
CFTypeRef client = api->createClient(kCFAllocatorDefault);
|
|
178
|
+
BOOL canDispatch = NULL != event && NULL != client;
|
|
179
|
+
if (canDispatch) {
|
|
180
|
+
api->dispatchEvent(client, event);
|
|
181
|
+
}
|
|
182
|
+
if (NULL != event) {
|
|
183
|
+
CFRelease(event);
|
|
184
|
+
}
|
|
185
|
+
if (NULL != client) {
|
|
186
|
+
CFRelease(client);
|
|
187
|
+
}
|
|
188
|
+
return canDispatch;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#endif
|
|
192
|
+
|
|
193
|
+
@implementation FBHIDOperations
|
|
194
|
+
|
|
195
|
+
+ (BOOL)appliesToDevice:(XCUIDevice *)device
|
|
196
|
+
{
|
|
197
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
198
|
+
return device.fb_supportsHingeAngleReading;
|
|
199
|
+
#else
|
|
200
|
+
return NO;
|
|
201
|
+
#endif
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
205
|
+
+ (BOOL)pressHomeWithError:(NSError **)error
|
|
206
|
+
{
|
|
207
|
+
FBLogUnverifiedPhysicalHIDOperation(@"Home");
|
|
208
|
+
return FBPressHIDButton(FBHIDHomeUsage, error);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
+ (BOOL)pressLockWithError:(NSError **)error
|
|
212
|
+
{
|
|
213
|
+
FBLogUnverifiedPhysicalHIDOperation(@"lock");
|
|
214
|
+
// XCTest locking times out on Duo / iOS 27.1 (Xcode 27.1). Remove this
|
|
215
|
+
// workaround once XCTest alone passes testRepeatedLockUnlockAcrossHingePoses.
|
|
216
|
+
return FBPressHIDButton(FBHIDPowerUsage, error);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
+ (BOOL)rotateToOrientation:(UIDeviceOrientation)orientation
|
|
220
|
+
interfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
|
221
|
+
{
|
|
222
|
+
FBLogUnverifiedPhysicalHIDOperation(@"rotation");
|
|
223
|
+
XCUIApplication *application = XCUIApplication.fb_activeApplication;
|
|
224
|
+
// Point-based detection can select the cover SpringBoard while the app
|
|
225
|
+
// is on the inner panel. Prefer the session's active application.
|
|
226
|
+
application = FBSession.activeSession.activeApplication ?: application;
|
|
227
|
+
// Keep XCTest's reported device orientation in sync on the simulator too.
|
|
228
|
+
[XCUIDevice sharedDevice].orientation = orientation;
|
|
229
|
+
// On Duo simulators XCTest can update its value without rotating the app.
|
|
230
|
+
// Use the same direct HID path on simulators and physical hinged devices.
|
|
231
|
+
if (!FBDispatchHIDOrientation(orientation)) {
|
|
232
|
+
return NO;
|
|
233
|
+
}
|
|
234
|
+
// Event dispatch is asynchronous. Check the app, not just XCTest's value.
|
|
235
|
+
if (![[[FBRunLoopSpinner new] timeout:FBHIDRotationTimeout] spinUntilTrue:^BOOL{
|
|
236
|
+
return application.interfaceOrientation == interfaceOrientation;
|
|
237
|
+
}]) {
|
|
238
|
+
return NO;
|
|
239
|
+
}
|
|
240
|
+
return FBWaitForStableInterfaceOrientation(application, interfaceOrientation);
|
|
241
|
+
}
|
|
242
|
+
#endif
|
|
243
|
+
|
|
244
|
+
@end
|
|
@@ -144,7 +144,9 @@ const CGFloat FBMaxCompressionQuality = 1.0f;
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
UIGraphicsImageRendererFormat *format = [[UIGraphicsImageRendererFormat alloc] init];
|
|
147
|
-
|
|
147
|
+
// scaledSize already applies the requested factor in points. Preserve the
|
|
148
|
+
// image's pixels-per-point scale instead of applying that factor twice.
|
|
149
|
+
format.scale = image.scale;
|
|
148
150
|
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:scaledSize
|
|
149
151
|
format:format];
|
|
150
152
|
UIImageOrientation desiredOrientation = orientation == nil
|
|
@@ -35,8 +35,19 @@ BOOL FBSizeFuzzyEqualToSize(CGSize size1, CGSize size2, CGFloat threshold);
|
|
|
35
35
|
BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold);
|
|
36
36
|
|
|
37
37
|
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
38
|
+
/*! Converts a portrait-screen rect into the application's orientation, preserving its clipping. */
|
|
39
|
+
CGRect FBRectFromPortraitCoordinates(CGRect frame, CGSize screenSize, UIInterfaceOrientation orientation);
|
|
40
|
+
|
|
38
41
|
/*! Inverts size if necessary to match current screen orientation */
|
|
39
42
|
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation);
|
|
43
|
+
|
|
44
|
+
/*!
|
|
45
|
+
Offsets XCTest screenPoint coordinates for an explicitly selected display.
|
|
46
|
+
XCTest rotates these coordinates using the main screen's dimensions even when
|
|
47
|
+
the synthesized event record targets another display. Sizes are in points.
|
|
48
|
+
*/
|
|
49
|
+
CGVector FBDisplayCoordinateOffset(CGSize mainSize, CGSize displaySize,
|
|
50
|
+
UIInterfaceOrientation orientation);
|
|
40
51
|
#endif
|
|
41
52
|
|
|
42
53
|
#if !TARGET_OS_TV
|
|
@@ -50,6 +50,27 @@ BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold)
|
|
|
50
50
|
|
|
51
51
|
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
52
52
|
|
|
53
|
+
CGRect FBRectFromPortraitCoordinates(CGRect frame, CGSize screenSize, UIInterfaceOrientation orientation)
|
|
54
|
+
{
|
|
55
|
+
if (CGRectIsEmpty(frame)) {
|
|
56
|
+
return frame;
|
|
57
|
+
}
|
|
58
|
+
CGFloat width = MIN(screenSize.width, screenSize.height);
|
|
59
|
+
CGFloat height = MAX(screenSize.width, screenSize.height);
|
|
60
|
+
switch (orientation) {
|
|
61
|
+
case UIInterfaceOrientationLandscapeLeft:
|
|
62
|
+
return CGRectMake(height - CGRectGetMaxY(frame), CGRectGetMinX(frame), frame.size.height, frame.size.width);
|
|
63
|
+
case UIInterfaceOrientationLandscapeRight:
|
|
64
|
+
return CGRectMake(CGRectGetMinY(frame), width - CGRectGetMaxX(frame), frame.size.height, frame.size.width);
|
|
65
|
+
case UIInterfaceOrientationPortraitUpsideDown:
|
|
66
|
+
return CGRectMake(width - CGRectGetMaxX(frame), height - CGRectGetMaxY(frame), frame.size.width, frame.size.height);
|
|
67
|
+
case UIInterfaceOrientationUnknown:
|
|
68
|
+
case UIInterfaceOrientationPortrait:
|
|
69
|
+
default:
|
|
70
|
+
return frame;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation)
|
|
54
75
|
{
|
|
55
76
|
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
|
|
@@ -107,3 +128,20 @@ BOOL FBScrollGestureOffsets(CGRect scrollingFrame,
|
|
|
107
128
|
(endPoint.y - anchorFrame.origin.y) / anchorFrame.size.height);
|
|
108
129
|
return YES;
|
|
109
130
|
}
|
|
131
|
+
|
|
132
|
+
#if !TARGET_OS_TV && !TARGET_OS_WATCH
|
|
133
|
+
CGVector FBDisplayCoordinateOffset(CGSize mainSize, CGSize displaySize,
|
|
134
|
+
UIInterfaceOrientation orientation)
|
|
135
|
+
{
|
|
136
|
+
CGVector offset = CGVectorMake(0, 0);
|
|
137
|
+
if (orientation == UIInterfaceOrientationLandscapeRight
|
|
138
|
+
|| orientation == UIInterfaceOrientationPortraitUpsideDown) {
|
|
139
|
+
offset.dx = displaySize.width - mainSize.width;
|
|
140
|
+
}
|
|
141
|
+
if (orientation == UIInterfaceOrientationLandscapeLeft
|
|
142
|
+
|| orientation == UIInterfaceOrientationPortraitUpsideDown) {
|
|
143
|
+
offset.dy = displaySize.height - mainSize.height;
|
|
144
|
+
}
|
|
145
|
+
return offset;
|
|
146
|
+
}
|
|
147
|
+
#endif
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
#import "FBConfiguration.h"
|
|
17
17
|
#import "FBLogger.h"
|
|
18
18
|
#import "FBScreenshot.h"
|
|
19
|
+
#import "FBScreen.h"
|
|
19
20
|
#import "FBImageProcessor.h"
|
|
20
21
|
#import "FBImageUtils.h"
|
|
21
22
|
#import "XCUIScreen.h"
|
|
@@ -42,7 +43,6 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
42
43
|
@property (nonatomic, readonly) dispatch_queue_t backgroundQueue;
|
|
43
44
|
@property (nonatomic, readonly) NSMutableArray<nw_connection_t> *listeningClients;
|
|
44
45
|
@property (nonatomic, readonly) FBImageProcessor *imageProcessor;
|
|
45
|
-
@property (nonatomic, readonly) long long mainScreenID;
|
|
46
46
|
@property (nonatomic, assign) NSUInteger consecutiveScreenshotFailures;
|
|
47
47
|
@property (atomic, assign) BOOL isStreaming;
|
|
48
48
|
@property (nonatomic, assign) NSUInteger sentFramesCount;
|
|
@@ -67,7 +67,6 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
67
67
|
_pendingFrameCounts = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOptions)(NSMapTableObjectPointerPersonality | NSMapTableStrongMemory)
|
|
68
68
|
valueOptions:(NSPointerFunctionsOptions)NSMapTableStrongMemory];
|
|
69
69
|
_imageProcessor = [[FBImageProcessor alloc] init];
|
|
70
|
-
_mainScreenID = [XCUIScreen.mainScreen displayID];
|
|
71
70
|
dispatch_queue_attr_t queueAttributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
|
|
72
71
|
_backgroundQueue = dispatch_queue_create(QUEUE_NAME, queueAttributes);
|
|
73
72
|
__weak typeof(self) weakSelf = self;
|
|
@@ -116,7 +115,8 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
116
115
|
NSError *error;
|
|
117
116
|
CGFloat compressionQuality = MAX(FBMinCompressionQuality,
|
|
118
117
|
MIN(FBMaxCompressionQuality, (double)FBConfiguration.sharedInstance.mjpegServerScreenshotQuality / 100.0));
|
|
119
|
-
|
|
118
|
+
XCUIScreen *screen = [FBScreen currentScreenWithError:&error];
|
|
119
|
+
NSData *screenshotData = nil == screen ? nil : [FBScreenshot takeInOriginalResolutionWithScreenID:screen.displayID
|
|
120
120
|
compressionQuality:compressionQuality
|
|
121
121
|
uti:UTTypeJPEG
|
|
122
122
|
timeout:FRAME_TIMEOUT
|
|
@@ -221,6 +221,8 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
|
|
|
221
221
|
[self.listeningClients removeObject:client];
|
|
222
222
|
[self.pendingFrameCounts removeObjectForKey:client];
|
|
223
223
|
}
|
|
224
|
+
// Nothing is owed to a client that stopped listening, so its socket can go right away.
|
|
225
|
+
nw_connection_cancel(client);
|
|
224
226
|
[FBLogger log:@"Disconnected a client from screenshots broadcast"];
|
|
225
227
|
}
|
|
226
228
|
|
|
@@ -17,6 +17,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
17
17
|
*/
|
|
18
18
|
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)screensWithError:(NSError **)error;
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
The display with the given identifier
|
|
22
|
+
|
|
23
|
+
@param displayID The display identifier, as returned by screensWithError:
|
|
24
|
+
@param error Set if the display is not available
|
|
25
|
+
@return The matching display or nil
|
|
26
|
+
*/
|
|
27
|
+
+ (nullable XCUIScreen *)screenWithDisplayID:(long long)displayID error:(NSError **)error;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
The display selected by the currentDisplayId setting, or the main display if the setting is not set
|
|
31
|
+
|
|
32
|
+
@param error Set if the selected display is no longer available
|
|
33
|
+
@return The selected display or nil
|
|
34
|
+
*/
|
|
35
|
+
+ (nullable XCUIScreen *)currentScreenWithError:(NSError **)error;
|
|
36
|
+
|
|
20
37
|
/**
|
|
21
38
|
The identifier of the main device's display
|
|
22
39
|
*/
|
|
@@ -7,16 +7,32 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
#import "FBScreen.h"
|
|
10
|
+
#import "FBConfiguration.h"
|
|
11
|
+
#import "FBErrorBuilder.h"
|
|
10
12
|
#import "XCUIElement+FBIsVisible.h"
|
|
11
13
|
#import "FBXCodeCompatibility.h"
|
|
12
14
|
#import "XCUIDevice.h"
|
|
13
15
|
#import "XCUIScreen.h"
|
|
16
|
+
#import <objc/message.h>
|
|
17
|
+
|
|
18
|
+
static NSArray<XCUIScreen *> *FBScreensForDevice(id device, NSError **error)
|
|
19
|
+
{
|
|
20
|
+
SEL selector = NSSelectorFromString(@"screensOrError:");
|
|
21
|
+
if ([device respondsToSelector:selector]) {
|
|
22
|
+
return ((NSArray<XCUIScreen *> *(*)(id, SEL, NSError **))objc_msgSend)(device, selector, error);
|
|
23
|
+
}
|
|
24
|
+
// Older XCTest versions expose screens on XCUIScreen instead of XCUIDevice.
|
|
25
|
+
if ([XCUIScreen respondsToSelector:NSSelectorFromString(@"screens")]) {
|
|
26
|
+
return XCUIScreen.screens;
|
|
27
|
+
}
|
|
28
|
+
return @[XCUIScreen.mainScreen];
|
|
29
|
+
}
|
|
14
30
|
|
|
15
31
|
@implementation FBScreen
|
|
16
32
|
|
|
17
33
|
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)screensWithError:(NSError **)error
|
|
18
34
|
{
|
|
19
|
-
NSArray<XCUIScreen *> *screens =
|
|
35
|
+
NSArray<XCUIScreen *> *screens = FBScreensForDevice(XCUIDevice.sharedDevice, error);
|
|
20
36
|
if (nil == screens) {
|
|
21
37
|
return nil;
|
|
22
38
|
}
|
|
@@ -40,6 +56,65 @@
|
|
|
40
56
|
return result.copy;
|
|
41
57
|
}
|
|
42
58
|
|
|
59
|
+
// Kept separate from sharedDevice so legacy lookup behavior can be tested.
|
|
60
|
+
+ (nullable XCUIScreen *)screenWithDisplayID:(long long)displayID
|
|
61
|
+
device:(XCUIDevice *)device
|
|
62
|
+
error:(NSError **)error
|
|
63
|
+
{
|
|
64
|
+
SEL lookupSelector = NSSelectorFromString(@"screenWithDisplayID:orError:");
|
|
65
|
+
BOOL hasNativeLookup = [device respondsToSelector:lookupSelector];
|
|
66
|
+
BOOL needsEnumeratedLookup = !hasNativeLookup;
|
|
67
|
+
NSError *lookupError = nil;
|
|
68
|
+
if (hasNativeLookup) {
|
|
69
|
+
XCUIScreen *screen = ((XCUIScreen *(*)(id, SEL, long long, NSError **))objc_msgSend)(
|
|
70
|
+
device, lookupSelector, displayID, &lookupError);
|
|
71
|
+
if ([screen respondsToSelector:NSSelectorFromString(@"bounds")] && !CGRectIsEmpty(screen.bounds)) {
|
|
72
|
+
return screen;
|
|
73
|
+
}
|
|
74
|
+
// XCTest may return a zero-sized placeholder for an inactive wireless
|
|
75
|
+
// display which screensOrError: omits. Confirm its availability by listing.
|
|
76
|
+
needsEnumeratedLookup = nil != screen;
|
|
77
|
+
}
|
|
78
|
+
// Enumerate only for legacy/placeholder lookups or to enrich a lookup error.
|
|
79
|
+
NSError *enumerationError = nil;
|
|
80
|
+
NSArray<XCUIScreen *> *screens = FBScreensForDevice(device, &enumerationError);
|
|
81
|
+
if (nil == screens) {
|
|
82
|
+
if (NULL != error) {
|
|
83
|
+
*error = lookupError ?: enumerationError;
|
|
84
|
+
}
|
|
85
|
+
return nil;
|
|
86
|
+
}
|
|
87
|
+
NSMutableArray<NSNumber *> *availableIDs = [NSMutableArray arrayWithCapacity:screens.count];
|
|
88
|
+
for (XCUIScreen *screen in screens) {
|
|
89
|
+
if (needsEnumeratedLookup && screen.displayID == displayID) {
|
|
90
|
+
return screen;
|
|
91
|
+
}
|
|
92
|
+
[availableIDs addObject:@(screen.displayID)];
|
|
93
|
+
}
|
|
94
|
+
FBErrorBuilder *builder = [FBErrorBuilder.builder withDescriptionFormat:
|
|
95
|
+
@"No display with id %lld is available. Available display ids: [%@]",
|
|
96
|
+
displayID, [availableIDs componentsJoinedByString:@", "]];
|
|
97
|
+
if (nil != lookupError) {
|
|
98
|
+
[builder withInnerError:lookupError];
|
|
99
|
+
}
|
|
100
|
+
[builder buildError:error];
|
|
101
|
+
return nil;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
+ (nullable XCUIScreen *)screenWithDisplayID:(long long)displayID error:(NSError **)error
|
|
105
|
+
{
|
|
106
|
+
return [self screenWithDisplayID:displayID device:XCUIDevice.sharedDevice error:error];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
+ (nullable XCUIScreen *)currentScreenWithError:(NSError **)error
|
|
110
|
+
{
|
|
111
|
+
NSNumber *displayID = FBConfiguration.sharedInstance.currentDisplayId;
|
|
112
|
+
if (nil == displayID) {
|
|
113
|
+
return XCUIScreen.mainScreen;
|
|
114
|
+
}
|
|
115
|
+
return [self screenWithDisplayID:displayID.longLongValue error:error];
|
|
116
|
+
}
|
|
117
|
+
|
|
43
118
|
+ (long long)displayID
|
|
44
119
|
{
|
|
45
120
|
return XCUIScreen.mainScreen.displayID;
|
|
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
14
14
|
@interface FBScreenshot : NSObject
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
Retrieves non-scaled screenshot of the
|
|
17
|
+
Retrieves non-scaled screenshot of the display selected by the currentDisplayId setting
|
|
18
18
|
|
|
19
19
|
@param quality The number in range 0-3, where 0 is PNG (lossless), 3 is HEIC (lossless), 1- low quality JPEG and 2 - high quality JPEG
|
|
20
20
|
@param error If there is an error, upon return contains an NSError object that describes the problem.
|
|
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
24
24
|
error:(NSError **)error;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
Retrieves non-scaled screenshot of the
|
|
27
|
+
Retrieves non-scaled screenshot of the display selected by the currentDisplayId setting
|
|
28
28
|
|
|
29
29
|
@param screenID The screen identifier to take the screenshot from
|
|
30
30
|
@param compressionQuality Normalized screenshot quality value in range 0..1, where 1 is the best quality
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#import "FBImageProcessor.h"
|
|
16
16
|
#import "FBLogger.h"
|
|
17
17
|
#import "FBMacros.h"
|
|
18
|
+
#import "FBScreen.h"
|
|
18
19
|
#import "FBXCodeCompatibility.h"
|
|
19
20
|
#import "FBXCTestDaemonsProxy.h"
|
|
20
21
|
#import "XCTMessagingChannel_RunnerToDaemon-Protocol.h"
|
|
@@ -60,8 +61,11 @@ NSString *formatTimeInterval(NSTimeInterval interval) {
|
|
|
60
61
|
+ (NSData *)takeInOriginalResolutionWithQuality:(NSUInteger)quality
|
|
61
62
|
error:(NSError **)error
|
|
62
63
|
{
|
|
63
|
-
XCUIScreen *
|
|
64
|
-
|
|
64
|
+
XCUIScreen *screen = [FBScreen currentScreenWithError:error];
|
|
65
|
+
if (nil == screen) {
|
|
66
|
+
return nil;
|
|
67
|
+
}
|
|
68
|
+
return [self.class takeWithScreenID:screen.displayID
|
|
65
69
|
scale:SCREENSHOT_SCALE
|
|
66
70
|
compressionQuality:[self.class compressionQualityWithQuality:quality]
|
|
67
71
|
sourceUTI:[self.class imageUtiWithQuality:quality]
|
|
@@ -36,6 +36,7 @@ extern NSString* const FB_SETTING_SCREENSHOT_ORIENTATION;
|
|
|
36
36
|
extern NSString* const FB_SETTING_WAIT_FOR_IDLE_TIMEOUT;
|
|
37
37
|
extern NSString* const FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT;
|
|
38
38
|
extern NSString* const FB_SETTING_MAX_TYPING_FREQUENCY;
|
|
39
|
+
extern NSString* const FB_SETTING_KEYBOARD_WAIT_TIMEOUT;
|
|
39
40
|
extern NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS;
|
|
40
41
|
extern NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT;
|
|
41
42
|
extern NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE;
|
|
@@ -46,5 +47,6 @@ extern NSString *const FB_SETTING_INCLUDE_NATIVE_ACCESSIBILITY_ELEMENT_IN_PAGE_S
|
|
|
46
47
|
extern NSString *const FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE;
|
|
47
48
|
extern NSString *const FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE;
|
|
48
49
|
extern NSString *const FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS;
|
|
50
|
+
extern NSString *const FB_SETTING_CURRENT_DISPLAY_ID;
|
|
49
51
|
|
|
50
52
|
NS_ASSUME_NONNULL_END
|
|
@@ -32,6 +32,7 @@ NSString* const FB_SETTING_SCREENSHOT_ORIENTATION = @"screenshotOrientation";
|
|
|
32
32
|
NSString* const FB_SETTING_WAIT_FOR_IDLE_TIMEOUT = @"waitForIdleTimeout";
|
|
33
33
|
NSString* const FB_SETTING_ANIMATION_COOL_OFF_TIMEOUT = @"animationCoolOffTimeout";
|
|
34
34
|
NSString* const FB_SETTING_MAX_TYPING_FREQUENCY = @"maxTypingFrequency";
|
|
35
|
+
NSString* const FB_SETTING_KEYBOARD_WAIT_TIMEOUT = @"keyboardWaitTimeout";
|
|
35
36
|
NSString* const FB_SETTING_RESPECT_SYSTEM_ALERTS = @"respectSystemAlerts";
|
|
36
37
|
NSString* const FB_SETTING_USE_CLEAR_TEXT_SHORTCUT = @"useClearTextShortcut";
|
|
37
38
|
NSString* const FB_SETTING_LIMIT_XPATH_CONTEXT_SCOPE = @"limitXPathContextScope";
|
|
@@ -42,3 +43,4 @@ NSString* const FB_SETTING_INCLUDE_NATIVE_ACCESSIBILITY_ELEMENT_IN_PAGE_SOURCE =
|
|
|
42
43
|
NSString* const FB_SETTING_INCLUDE_MIN_MAX_VALUE_IN_PAGE_SOURCE = @"includeMinMaxValueInPageSource";
|
|
43
44
|
NSString* const FB_SETTING_INCLUDE_CUSTOM_ACTIONS_IN_PAGE_SOURCE = @"includeCustomActionsInPageSource";
|
|
44
45
|
NSString* const FB_SETTING_ENFORCE_CUSTOM_SNAPSHOTS = @"enforceCustomSnapshots";
|
|
46
|
+
NSString* const FB_SETTING_CURRENT_DISPLAY_ID = @"currentDisplayId";
|