diff --git a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h index 48aa80e3b..85701c2dc 100644 --- a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h +++ b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.h @@ -22,13 +22,36 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)fb_fingerTouchShouldMatch:(BOOL)shouldMatch; /** - Forces devices to go to homescreen + Forces the device under test to switch to the home screen @param error If there is an error, upon return contains an NSError object that describes the problem. @return YES if the operation succeeds, otherwise NO. */ - (BOOL)fb_goToHomescreenWithError:(NSError **)error; +/** + Checks if the screen is locked or not. + + @return YES if screen is locked + */ +- (BOOL)fb_isScreenLocked; + +/** + Forces the device under test to switch to the lock screen. An immediate return will happen if the device is already locked and an error is going to be thrown if the screen has not been locked after the timeout. + + @param error If there is an error, upon return contains an NSError object that describes the problem. + @return YES if the operation succeeds, otherwise NO. + */ +- (BOOL)fb_lockScreen:(NSError **)error; + +/** + Forces the device under test to unlock. An immediate return will happen if the device is already unlocked and an error is going to be thrown if the screen has not been unlocked after the timeout. + + @param error If there is an error, upon return contains an NSError object that describes the problem. + @return YES if the operation succeeds, otherwise NO. + */ +- (BOOL)fb_unlockScreen:(NSError **)error; + /** Returns screenshot @param error If there is an error, upon return contains an NSError object that describes the problem. diff --git a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m index 4d1e212ec..8b0412694 100644 --- a/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m +++ b/WebDriverAgentLib/Categories/XCUIDevice+FBHelpers.m @@ -16,16 +16,38 @@ #import "FBSpringboardApplication.h" #import "FBErrorBuilder.h" +#import "FBMacros.h" #import "FBMathUtils.h" #import "FBXCodeCompatibility.h" -#import "FBMacros.h" +#import "XCUIDevice.h" #import "XCAXClient_iOS.h" static const NSTimeInterval FBHomeButtonCoolOffTime = 1.; +static const NSTimeInterval FBScreenLockTimeout = 5.; @implementation XCUIDevice (FBHelpers) +static bool fb_isLocked; + ++ (void)load +{ + [self fb_registerAppforDetectLockState]; +} + ++ (void)fb_registerAppforDetectLockState +{ + int notify_token; + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wstrict-prototypes" + notify_register_dispatch("com.apple.springboard.lockstate", ¬ify_token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token) { + uint64_t state = UINT64_MAX; + notify_get_state(token, &state); + fb_isLocked = state != 0; + }); + #pragma clang diagnostic pop +} + - (BOOL)fb_goToHomescreenWithError:(NSError **)error { [self pressButton:XCUIDeviceButtonHome]; @@ -41,6 +63,46 @@ - (BOOL)fb_goToHomescreenWithError:(NSError **)error return YES; } +- (BOOL)fb_lockScreen:(NSError **)error +{ + if (fb_isLocked) { + return YES; + } + [self pressLockButton]; + return [[[[FBRunLoopSpinner new] + timeout:FBScreenLockTimeout] + timeoutErrorMessage:@"Timed out while waiting until the screen gets locked"] + spinUntilTrue:^BOOL{ + return fb_isLocked; + } error:error]; +} + +- (BOOL)fb_isScreenLocked +{ + return fb_isLocked; +} + +- (BOOL)fb_unlockScreen:(NSError **)error +{ + if (!fb_isLocked) { + return YES; + } + [self pressButton:XCUIDeviceButtonHome]; + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:FBHomeButtonCoolOffTime]]; + if (SYSTEM_VERSION_LESS_THAN(@"10.0")) { + [[FBApplication fb_activeApplication] swipeRight]; + } else { + [self pressButton:XCUIDeviceButtonHome]; + } + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:FBHomeButtonCoolOffTime]]; + return [[[[FBRunLoopSpinner new] + timeout:FBScreenLockTimeout] + timeoutErrorMessage:@"Timed out while waiting until the screen gets unlocked"] + spinUntilTrue:^BOOL{ + return !fb_isLocked; + } error:error]; +} + - (NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error { id xcScreen = NSClassFromString(@"XCUIScreen"); @@ -54,7 +116,7 @@ - (NSData *)fb_screenshotWithError:(NSError*__autoreleasing*)error } return result; } - + id mainScreen = [xcScreen valueForKey:@"mainScreen"]; FBApplication *activeApplication = FBApplication.fb_activeApplication; UIInterfaceOrientation orientation = activeApplication.interfaceOrientation; diff --git a/WebDriverAgentLib/Commands/FBCustomCommands.m b/WebDriverAgentLib/Commands/FBCustomCommands.m index 9cb403b0a..2a764c87e 100644 --- a/WebDriverAgentLib/Commands/FBCustomCommands.m +++ b/WebDriverAgentLib/Commands/FBCustomCommands.m @@ -39,7 +39,10 @@ + (NSArray *)routes [[FBRoute POST:@"/wda/homescreen"].withoutSession respondWithTarget:self action:@selector(handleHomescreenCommand:)], [[FBRoute POST:@"/wda/deactivateApp"] respondWithTarget:self action:@selector(handleDeactivateAppCommand:)], [[FBRoute POST:@"/wda/keyboard/dismiss"] respondWithTarget:self action:@selector(handleDismissKeyboardCommand:)], - [[FBRoute GET:@"/lock"].withoutSession respondWithTarget:self action:@selector(handleLock:)], + [[FBRoute POST:@"/wda/lock"].withoutSession respondWithTarget:self action:@selector(handleLock:)], + [[FBRoute POST:@"/wda/lock"] respondWithTarget:self action:@selector(handleLock:)], + [[FBRoute POST:@"/wda/unlock"].withoutSession respondWithTarget:self action:@selector(handleUnlock:)], + [[FBRoute POST:@"/wda/unlock"] respondWithTarget:self action:@selector(handleUnlock:)], [[FBRoute GET:@"/wda/screen"] respondWithTarget:self action:@selector(handleGetScreen:)] ]; } @@ -96,20 +99,6 @@ + (NSArray *)routes return FBResponseWithOK(); } -+ (id)handleLock:(FBRouteRequest *)request -{ - - dispatch_async(dispatch_get_main_queue(), ^{ - @try{ -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - [[XCUIDevice sharedDevice] performSelector:NSSelectorFromString(@"pressLockButton")]; - }@catch(NSException *exception){ - NSLog(@"Exception cought in the main thread %@",exception); - } - }); - return FBResponseWithOK(); -} - + (id)handleGetScreen:(FBRouteRequest *)request { FBSession *session = request.session; @@ -119,8 +108,27 @@ + (NSArray *)routes @"statusBarSize": @{@"width": @(statusBarSize.width), @"height": @(statusBarSize.height), }, - @"scale": @([FBScreen scale]) + @"scale": @([FBScreen scale]), + @"locked": @([[XCUIDevice sharedDevice] fb_isScreenLocked]) }); } ++ (id)handleLock:(FBRouteRequest *)request +{ + NSError *error; + if (![[XCUIDevice sharedDevice] fb_lockScreen:&error]) { + return FBResponseWithError(error); + } + return FBResponseWithOK(); +} + ++ (id)handleUnlock:(FBRouteRequest *)request +{ + NSError *error; + if (![[XCUIDevice sharedDevice] fb_unlockScreen:&error]) { + return FBResponseWithError(error); + } + return FBResponseWithOK(); +} + @end diff --git a/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m b/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m index 6fcb969f8..00e8bdcf6 100644 --- a/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m +++ b/WebDriverAgentTests/IntegrationTests/XCUIDeviceHelperTests.m @@ -53,4 +53,16 @@ - (void)testGoToHomeScreen XCTAssertTrue([FBApplication fb_activeApplication].icons[@"Safari"].exists); } +- (void)testLockUnlockScreen +{ + XCTAssertFalse([[XCUIDevice sharedDevice] fb_isScreenLocked]); + NSError *error; + XCTAssertTrue([[XCUIDevice sharedDevice] fb_lockScreen:&error]); + XCTAssertTrue([[XCUIDevice sharedDevice] fb_isScreenLocked]); + XCTAssertNil(error); + XCTAssertTrue([[XCUIDevice sharedDevice] fb_unlockScreen:&error]); + XCTAssertFalse([[XCUIDevice sharedDevice] fb_isScreenLocked]); + XCTAssertNil(error); +} + @end