|
|
@ -4,22 +4,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
#import "OWSScreenLockUI.h"
|
|
|
|
#import "OWSScreenLockUI.h"
|
|
|
|
#import "Signal-Swift.h"
|
|
|
|
#import "Signal-Swift.h"
|
|
|
|
|
|
|
|
#import <SignalMessaging/SignalMessaging-Swift.h>
|
|
|
|
|
|
|
|
#import <SignalMessaging/UIView+OWS.h>
|
|
|
|
|
|
|
|
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
|
|
|
|
|
|
|
|
@interface OWSScreenLockUI ()
|
|
|
|
@interface OWSScreenLockUI ()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property (nonatomic) UIWindow *screenBlockingWindow;
|
|
|
|
|
|
|
|
@property (nonatomic) UIViewController *screenBlockingViewController;
|
|
|
|
|
|
|
|
|
|
|
|
// Unlike UIApplication.applicationState, this state is
|
|
|
|
// Unlike UIApplication.applicationState, this state is
|
|
|
|
// updated conservatively, e.g. the flag is cleared during
|
|
|
|
// updated conservatively, e.g. the flag is cleared during
|
|
|
|
// "will enter background."
|
|
|
|
// "will enter background."
|
|
|
|
@property (nonatomic) BOOL appIsInactive;
|
|
|
|
@property (nonatomic) BOOL appIsInactive;
|
|
|
|
@property (nonatomic) BOOL appIsInBackground;
|
|
|
|
@property (nonatomic) BOOL appIsInBackground;
|
|
|
|
@property (nonatomic, nullable) NSDate *appEnteredBackgroundDate;
|
|
|
|
|
|
|
|
@property (nonatomic) UIWindow *screenBlockingWindow;
|
|
|
|
|
|
|
|
@property (nonatomic) BOOL hasUnlockedScreenLock;
|
|
|
|
|
|
|
|
@property (nonatomic) BOOL isShowingScreenLockUI;
|
|
|
|
@property (nonatomic) BOOL isShowingScreenLockUI;
|
|
|
|
|
|
|
|
@property (nonatomic) BOOL didLastUnlockAttemptFail;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We want to remain in "screen lock" mode while "local auth"
|
|
|
|
|
|
|
|
// UI is dismissing.
|
|
|
|
|
|
|
|
@property (nonatomic) BOOL shouldClearAuthUIWhenActive;
|
|
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, nullable) NSTimer *screenLockUITimer;
|
|
|
|
@property (nonatomic, nullable) NSTimer *screenLockUITimer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property (nonatomic, nullable) NSDate *appEnteredBackgroundDate;
|
|
|
|
|
|
|
|
@property (nonatomic, nullable) NSDate *appEnteredForegroundDate;
|
|
|
|
@property (nonatomic, nullable) NSDate *lastUnlockAttemptDate;
|
|
|
|
@property (nonatomic, nullable) NSDate *lastUnlockAttemptDate;
|
|
|
|
@property (nonatomic, nullable) NSDate *lastUnlockSuccessDate;
|
|
|
|
@property (nonatomic, nullable) NSDate *lastUnlockSuccessDate;
|
|
|
|
|
|
|
|
|
|
|
@ -112,11 +123,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (appIsInBackground) {
|
|
|
|
if (appIsInBackground) {
|
|
|
|
if (!_appIsInBackground) {
|
|
|
|
if (!_appIsInBackground) {
|
|
|
|
// Whenever app enters background, clear this state.
|
|
|
|
|
|
|
|
self.hasUnlockedScreenLock = NO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Record the time when app entered background.
|
|
|
|
// Record the time when app entered background.
|
|
|
|
self.appEnteredBackgroundDate = [NSDate new];
|
|
|
|
self.appEnteredBackgroundDate = [NSDate new];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.didLastUnlockAttemptFail = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -148,42 +158,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
if (self.screenBlockingWindow.hidden != !shouldShowBlockWindow) {
|
|
|
|
if (self.screenBlockingWindow.hidden != !shouldShowBlockWindow) {
|
|
|
|
DDLogInfo(@"%@, %@.", self.logTag, shouldShowBlockWindow ? @"showing block window" : @"hiding block window");
|
|
|
|
DDLogInfo(@"%@, %@.", self.logTag, shouldShowBlockWindow ? @"showing block window" : @"hiding block window");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.screenBlockingWindow.hidden = !shouldShowBlockWindow;
|
|
|
|
[self updateScreenBlockingWindow:shouldShowBlockWindow shouldHaveScreenLock:shouldHaveScreenLock];
|
|
|
|
|
|
|
|
|
|
|
|
[self.screenLockUITimer invalidate];
|
|
|
|
[self.screenLockUITimer invalidate];
|
|
|
|
self.screenLockUITimer = nil;
|
|
|
|
self.screenLockUITimer = nil;
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldHaveScreenLock) {
|
|
|
|
if (shouldHaveScreenLock && !self.didLastUnlockAttemptFail) {
|
|
|
|
// In pincode-only mode (e.g. device pincode is set
|
|
|
|
[self tryToPresentScreenLockUI];
|
|
|
|
// but Touch ID/Face ID are not configured), the pincode
|
|
|
|
|
|
|
|
// unlock UI is fullscreen and the app becomes inactive.
|
|
|
|
|
|
|
|
// Hitting the home button will cancel the authentication
|
|
|
|
|
|
|
|
// UI but not send the app to the background. Therefore,
|
|
|
|
|
|
|
|
// to send the "locked" app to the background, you need
|
|
|
|
|
|
|
|
// to tap the home button twice.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Therefore, if our last unlock attempt failed or was
|
|
|
|
|
|
|
|
// cancelled, wait a couple of second before re-presenting
|
|
|
|
|
|
|
|
// the "unlock screen lock UI" so that users have a chance
|
|
|
|
|
|
|
|
// to hit home button again.
|
|
|
|
|
|
|
|
BOOL shouldDelayScreenLockUI = YES;
|
|
|
|
|
|
|
|
if (!self.lastUnlockAttemptDate) {
|
|
|
|
|
|
|
|
shouldDelayScreenLockUI = NO;
|
|
|
|
|
|
|
|
} else if (self.lastUnlockAttemptDate && self.lastUnlockSuccessDate &&
|
|
|
|
|
|
|
|
[self.lastUnlockSuccessDate isAfterDate:self.lastUnlockAttemptDate]) {
|
|
|
|
|
|
|
|
shouldDelayScreenLockUI = NO;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldDelayScreenLockUI) {
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@, Delaying Screen Lock UI.", self.logTag);
|
|
|
|
|
|
|
|
self.screenLockUITimer = [NSTimer weakScheduledTimerWithTimeInterval:1.25f
|
|
|
|
|
|
|
|
target:self
|
|
|
|
|
|
|
|
selector:@selector(tryToPresentScreenLockUI)
|
|
|
|
|
|
|
|
userInfo:nil
|
|
|
|
|
|
|
|
repeats:NO];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
[self tryToPresentScreenLockUI];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -198,6 +179,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
if (!self.shouldHaveScreenLock) {
|
|
|
|
if (!self.shouldHaveScreenLock) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.didLastUnlockAttemptFail) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (self.isShowingScreenLockUI) {
|
|
|
|
if (self.isShowingScreenLockUI) {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -210,27 +194,24 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
[OWSScreenLock.sharedManager tryToUnlockScreenLockWithSuccess:^{
|
|
|
|
[OWSScreenLock.sharedManager tryToUnlockScreenLockWithSuccess:^{
|
|
|
|
DDLogInfo(@"%@ unlock screen lock succeeded.", self.logTag);
|
|
|
|
DDLogInfo(@"%@ unlock screen lock succeeded.", self.logTag);
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
self.hasUnlockedScreenLock = YES;
|
|
|
|
|
|
|
|
self.lastUnlockSuccessDate = [NSDate new];
|
|
|
|
self.lastUnlockSuccessDate = [NSDate new];
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
failure:^(NSError *error) {
|
|
|
|
failure:^(NSError *error) {
|
|
|
|
DDLogInfo(@"%@ unlock screen lock failed.", self.logTag);
|
|
|
|
DDLogInfo(@"%@ unlock screen lock failed.", self.logTag);
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[self showScreenLockFailureAlertWithMessage:error.localizedDescription];
|
|
|
|
[self clearAuthUIWhenActive];
|
|
|
|
}
|
|
|
|
|
|
|
|
unexpectedFailure:^(NSError *error) {
|
|
|
|
|
|
|
|
DDLogInfo(@"%@ unlock screen lock unexpectedly failed.", self.logTag);
|
|
|
|
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
self.didLastUnlockAttemptFail = YES;
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
|
|
|
|
});
|
|
|
|
[self showScreenLockFailureAlertWithMessage:error.localizedDescription];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cancel:^{
|
|
|
|
cancel:^{
|
|
|
|
DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag);
|
|
|
|
DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag);
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
|
|
|
|
|
|
|
|
[self clearAuthUIWhenActive];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.didLastUnlockAttemptFail = YES;
|
|
|
|
|
|
|
|
|
|
|
|
// Re-show the unlock UI.
|
|
|
|
// Re-show the unlock UI.
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
[self ensureScreenProtection];
|
|
|
@ -243,26 +224,57 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// * App is inactive and...
|
|
|
|
// * App is inactive and...
|
|
|
|
// * 'Screen Protection' is enabled.
|
|
|
|
// * 'Screen Protection' is enabled.
|
|
|
|
BOOL shouldHaveScreenProtection = (self.appIsInactive && Environment.preferences.screenSecurityIsEnabled);
|
|
|
|
if (!self.appIsInactive) {
|
|
|
|
return shouldHaveScreenProtection;
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
} else if (!Environment.preferences.screenSecurityIsEnabled) {
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (BOOL)hasUnlockedScreenLock
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!self.lastUnlockSuccessDate) {
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
} else if (!self.appEnteredBackgroundDate) {
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return [self.lastUnlockSuccessDate isAfterDate:self.appEnteredBackgroundDate];
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (BOOL)shouldHaveScreenLock
|
|
|
|
- (BOOL)shouldHaveScreenLock
|
|
|
|
{
|
|
|
|
{
|
|
|
|
BOOL shouldHaveScreenLock = NO;
|
|
|
|
|
|
|
|
if (![TSAccountManager isRegistered]) {
|
|
|
|
if (![TSAccountManager isRegistered]) {
|
|
|
|
// Don't show 'Screen Lock' if user is not registered.
|
|
|
|
// Don't show 'Screen Lock' if user is not registered.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 1.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
} else if (!OWSScreenLock.sharedManager.isScreenLockEnabled) {
|
|
|
|
} else if (!OWSScreenLock.sharedManager.isScreenLockEnabled) {
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' isn't enabled.
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' isn't enabled.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 2.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
} else if (self.hasUnlockedScreenLock) {
|
|
|
|
} else if (self.hasUnlockedScreenLock) {
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' has been unlocked.
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' has been unlocked.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 3.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
} else if (self.appIsInBackground) {
|
|
|
|
} else if (self.appIsInBackground) {
|
|
|
|
// Don't show 'Screen Lock' if app is in background.
|
|
|
|
// Don't show 'Screen Lock' if app is in background.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 4.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
|
|
|
|
} else if (self.isShowingScreenLockUI) {
|
|
|
|
|
|
|
|
// Maintain blocking window in 'screen lock' mode while we're
|
|
|
|
|
|
|
|
// showing the 'Unlock Screen Lock' UI.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock YES 0.", self.logTag);
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
} else if (self.appIsInactive) {
|
|
|
|
} else if (self.appIsInactive) {
|
|
|
|
// Don't show 'Screen Lock' if app is inactive.
|
|
|
|
// Don't show 'Screen Lock' if app is inactive.
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 5.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
} else if (!self.appEnteredBackgroundDate) {
|
|
|
|
} else if (!self.appEnteredBackgroundDate) {
|
|
|
|
// Show 'Screen Lock' if app has just launched.
|
|
|
|
// Show 'Screen Lock' if app has just launched.
|
|
|
|
shouldHaveScreenLock = YES;
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock YES 1.", self.logTag);
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
OWSAssert(self.appEnteredBackgroundDate);
|
|
|
|
OWSAssert(self.appEnteredBackgroundDate);
|
|
|
|
|
|
|
|
|
|
|
@ -272,13 +284,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
OWSAssert(screenLockTimeout >= 0);
|
|
|
|
OWSAssert(screenLockTimeout >= 0);
|
|
|
|
if (screenLockInterval < screenLockTimeout) {
|
|
|
|
if (screenLockInterval < screenLockTimeout) {
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' timeout hasn't elapsed.
|
|
|
|
// Don't show 'Screen Lock' if 'Screen Lock' timeout hasn't elapsed.
|
|
|
|
shouldHaveScreenLock = NO;
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock NO 6.", self.logTag);
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Otherwise, show 'Screen Lock'.
|
|
|
|
// Otherwise, show 'Screen Lock'.
|
|
|
|
shouldHaveScreenLock = YES;
|
|
|
|
DDLogVerbose(@"%@ shouldHaveScreenLock YES 2.", self.logTag);
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return shouldHaveScreenLock;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)showScreenLockFailureAlertWithMessage:(NSString *)message
|
|
|
|
- (void)showScreenLockFailureAlertWithMessage:(NSString *)message
|
|
|
@ -307,13 +320,102 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds];
|
|
|
|
UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds];
|
|
|
|
window.hidden = YES;
|
|
|
|
window.hidden = YES;
|
|
|
|
window.opaque = YES;
|
|
|
|
window.opaque = YES;
|
|
|
|
window.userInteractionEnabled = NO;
|
|
|
|
|
|
|
|
window.windowLevel = CGFLOAT_MAX;
|
|
|
|
window.windowLevel = CGFLOAT_MAX;
|
|
|
|
window.backgroundColor = UIColor.ows_materialBlueColor;
|
|
|
|
window.backgroundColor = UIColor.ows_materialBlueColor;
|
|
|
|
window.rootViewController =
|
|
|
|
|
|
|
|
[[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController];
|
|
|
|
UIViewController *viewController = [UIViewController new];
|
|
|
|
|
|
|
|
viewController.view.backgroundColor = UIColor.ows_materialBlueColor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
window.rootViewController = viewController;
|
|
|
|
|
|
|
|
|
|
|
|
self.screenBlockingWindow = window;
|
|
|
|
self.screenBlockingWindow = window;
|
|
|
|
|
|
|
|
self.screenBlockingViewController = viewController;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[self updateScreenBlockingWindow:YES shouldHaveScreenLock:NO];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void)updateScreenBlockingWindow:(BOOL)shouldShowBlockWindow shouldHaveScreenLock:(BOOL)shouldHaveScreenLock
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.screenBlockingWindow.hidden = !shouldShowBlockWindow;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UIView *rootView = self.screenBlockingViewController.view;
|
|
|
|
|
|
|
|
for (UIView *subview in rootView.subviews) {
|
|
|
|
|
|
|
|
[subview removeFromSuperview];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UIView *edgesView = [UIView containerView];
|
|
|
|
|
|
|
|
[rootView addSubview:edgesView];
|
|
|
|
|
|
|
|
[edgesView autoHCenterInSuperview];
|
|
|
|
|
|
|
|
[edgesView autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
|
|
|
|
|
|
|
[edgesView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UIView *containerView = [UIView containerView];
|
|
|
|
|
|
|
|
[edgesView addSubview:containerView];
|
|
|
|
|
|
|
|
[containerView autoVCenterInSuperview];
|
|
|
|
|
|
|
|
[containerView autoPinWidthToSuperviewWithMargin:20.f];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UIImage *image = [UIImage imageNamed:@"logoSignal"];
|
|
|
|
|
|
|
|
UIImageView *imageView = [UIImageView new];
|
|
|
|
|
|
|
|
imageView.image = image;
|
|
|
|
|
|
|
|
[containerView addSubview:imageView];
|
|
|
|
|
|
|
|
[imageView autoPinTopToSuperview];
|
|
|
|
|
|
|
|
[imageView autoHCenterInSuperview];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const CGSize screenSize = UIScreen.mainScreen.bounds.size;
|
|
|
|
|
|
|
|
const CGFloat shortScreenDimension = MIN(screenSize.width, screenSize.height);
|
|
|
|
|
|
|
|
const CGFloat imageSize = round(shortScreenDimension / 3.f);
|
|
|
|
|
|
|
|
[imageView autoSetDimension:ALDimensionWidth toSize:imageSize];
|
|
|
|
|
|
|
|
[imageView autoSetDimension:ALDimensionHeight toSize:imageSize];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOOL shouldShowUnlockButton = (!self.appIsInactive && !self.appIsInBackground && self.didLastUnlockAttemptFail);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DDLogVerbose(@"%@ updateScreenBlockingWindow. shouldShowBlockWindow: %d, shouldHaveScreenLock: %d, "
|
|
|
|
|
|
|
|
@"shouldShowUnlockButton: %d.",
|
|
|
|
|
|
|
|
self.logTag,
|
|
|
|
|
|
|
|
shouldShowBlockWindow,
|
|
|
|
|
|
|
|
shouldHaveScreenLock,
|
|
|
|
|
|
|
|
shouldShowUnlockButton);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldHaveScreenLock) {
|
|
|
|
|
|
|
|
const CGFloat kButtonHeight = 40.f;
|
|
|
|
|
|
|
|
OWSFlatButton *button =
|
|
|
|
|
|
|
|
[OWSFlatButton buttonWithTitle:NSLocalizedString(@"SCREEN_LOCK_UNLOCK_SIGNAL",
|
|
|
|
|
|
|
|
@"Label for button on lock screen that lets users unlock Signal.")
|
|
|
|
|
|
|
|
font:[OWSFlatButton fontForHeight:kButtonHeight]
|
|
|
|
|
|
|
|
titleColor:[UIColor ows_materialBlueColor]
|
|
|
|
|
|
|
|
backgroundColor:[UIColor whiteColor]
|
|
|
|
|
|
|
|
target:self
|
|
|
|
|
|
|
|
selector:@selector(showUnlockUI)];
|
|
|
|
|
|
|
|
[containerView addSubview:button];
|
|
|
|
|
|
|
|
[button autoSetDimension:ALDimensionHeight toSize:kButtonHeight];
|
|
|
|
|
|
|
|
const CGFloat kVSpacing = 80.f;
|
|
|
|
|
|
|
|
[button autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:imageView withOffset:kVSpacing];
|
|
|
|
|
|
|
|
// For symmetry, use equal padding below so that "unlock" button is visually centered
|
|
|
|
|
|
|
|
// (under the local auth UI alert) and the Signal logo is moved upwards, not blocked by
|
|
|
|
|
|
|
|
// the local auth UI alert.
|
|
|
|
|
|
|
|
const CGFloat kBottomPadding = imageSize + kVSpacing;
|
|
|
|
|
|
|
|
[button autoPinBottomToSuperviewWithMargin:kBottomPadding];
|
|
|
|
|
|
|
|
[button autoPinLeadingAndTrailingToSuperview];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
button.hidden = !shouldShowUnlockButton;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
[imageView autoPinBottomToSuperview];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[rootView layoutIfNeeded];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void)showUnlockUI
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DDLogInfo(@"showUnlockUI");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.didLastUnlockAttemptFail = NO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Events
|
|
|
|
#pragma mark - Events
|
|
|
@ -332,9 +434,23 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
[self ensureScreenProtection];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void)clearAuthUIWhenActive
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (self.appIsInactive) {
|
|
|
|
|
|
|
|
self.shouldClearAuthUIWhenActive = YES;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
|
|
|
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
|
|
|
{
|
|
|
|
{
|
|
|
|
self.appIsInactive = NO;
|
|
|
|
self.appIsInactive = NO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (self.shouldClearAuthUIWhenActive) {
|
|
|
|
|
|
|
|
self.shouldClearAuthUIWhenActive = NO;
|
|
|
|
|
|
|
|
self.isShowingScreenLockUI = NO;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
|
|
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
|
|
@ -353,6 +469,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
|
self.lastUnlockSuccessDate = nil;
|
|
|
|
self.lastUnlockSuccessDate = nil;
|
|
|
|
|
|
|
|
|
|
|
|
self.appIsInBackground = NO;
|
|
|
|
self.appIsInBackground = NO;
|
|
|
|
|
|
|
|
self.appEnteredForegroundDate = [NSDate new];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidEnterBackground:(NSNotification *)notification
|
|
|
|
- (void)applicationDidEnterBackground:(NSNotification *)notification
|
|
|
|