|  |  | @ -9,6 +9,29 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | NS_ASSUME_NONNULL_BEGIN |  |  |  | NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | typedef NS_ENUM(NSUInteger, ScreenLockUIState) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ScreenLockUIStateNone, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // Shown while app is inactive or background, if enabled. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ScreenLockUIStateScreenProtection, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // Shown while app is active, if enabled. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ScreenLockUIStateScreenLock, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | NSString *NSStringForScreenLockUIState(ScreenLockUIState value); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | NSString *NSStringForScreenLockUIState(ScreenLockUIState value) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     switch (value) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case ScreenLockUIStateNone: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return @"ScreenLockUIStateNone"; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case ScreenLockUIStateScreenProtection: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return @"ScreenLockUIStateScreenProtection"; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case ScreenLockUIStateScreenLock: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return @"ScreenLockUIStateScreenLock"; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const UIWindowLevel UIWindowLevel_Background = -1.f; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @interface OWSScreenLockUI () |  |  |  | @interface OWSScreenLockUI () | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) UIWindow *screenBlockingWindow; |  |  |  | @property (nonatomic) UIWindow *screenBlockingWindow; | 
			
		
	
	
		
		
			
				
					|  |  | @ -18,35 +41,43 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) NSArray<NSLayoutConstraint *> *screenBlockingConstraints; |  |  |  | @property (nonatomic) NSArray<NSLayoutConstraint *> *screenBlockingConstraints; | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) NSString *screenBlockingSignature; |  |  |  | @property (nonatomic) NSString *screenBlockingSignature; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Unlike UIApplication.applicationState, this state is |  |  |  | // Unlike UIApplication.applicationState, this state reflects the | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // updated conservatively, e.g. the flag is cleared during |  |  |  | // notifications, i.e. "did become active", "will resign active", | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // "will enter background." |  |  |  | // "will enter foreground", "did enter background". | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL appIsInactive; |  |  |  | // | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // We want to update our state to reflect these transitions and have | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // the "update" logic be consistent with "last reported" state. i.e. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // when you're responding to "will resign active", we need to behave | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // as though we're already inactive. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // Secondly, we need to show the screen protection _before_ we become | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // inactive in order for it to be reflected in the app switcher. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | @property (nonatomic) BOOL appIsInactiveOrBackground; | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL appIsInBackground; |  |  |  | @property (nonatomic) BOOL appIsInBackground; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL isShowingScreenLockUI; |  |  |  | @property (nonatomic) BOOL isShowingScreenLockUI; | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL didLastUnlockAttemptFail; |  |  |  | @property (nonatomic) BOOL didLastUnlockAttemptFail; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // We want to remain in "screen lock" mode while "local auth" |  |  |  | // We want to remain in "screen lock" mode while "local auth" | 
			
		
	
		
		
			
				
					
					|  |  |  | // UI is dismissing. |  |  |  | // UI is dismissing. So we lazily clear isShowingScreenLockUI | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // using this property. | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL shouldClearAuthUIWhenActive; |  |  |  | @property (nonatomic) BOOL shouldClearAuthUIWhenActive; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Indicates whether or not the user is currently locked out of |  |  |  | // Indicates whether or not the user is currently locked out of | 
			
		
	
		
		
			
				
					
					|  |  |  | // the app.  Only applies if OWSScreenLock.isScreenLockEnabled. |  |  |  | // the app.  Should only be set if OWSScreenLock.isScreenLockEnabled. | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | // |  |  |  | // | 
			
		
	
		
		
			
				
					
					|  |  |  | // * The user is locked out out by default on app launch. |  |  |  | // * The user is locked out by default on app launch. | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | // * The user is also locked out if they spend more than |  |  |  | // * The user is also locked out if they spend more than | 
			
		
	
		
		
			
				
					
					|  |  |  | //   "timeout" seconds outside the app.  When the user leaves |  |  |  | //   "timeout" seconds outside the app.  When the user leaves | 
			
		
	
		
		
			
				
					
					|  |  |  | //   the app, a "countdown" begins. |  |  |  | //   the app, a "countdown" begins. | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic) BOOL isScreenLockUnlocked; |  |  |  | @property (nonatomic) BOOL isScreenLockLocked; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // The "countdown" until screen lock takes effect. | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic, nullable) NSDate *screenLockCountdownDate; |  |  |  | @property (nonatomic, nullable) NSDate *screenLockCountdownDate; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // We normally start the "countdown" when the app enters the background, |  |  |  | @property (nonatomic) UIWindow *rootWindow; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | // But we also want to start the "countdown" if the app is inactive for |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | // more than N seconds. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | @property (nonatomic, nullable) NSTimer *inactiveTimer; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | @property (nonatomic, nullable) UIResponder *rootWindowResponder; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @end |  |  |  | @end | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -72,6 +103,10 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |         return self; |  |  |  |         return self; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     _appIsInactiveOrBackground = [UIApplication sharedApplication].applicationState != UIApplicationStateActive; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self observeNotifications]; |  |  |  |     [self observeNotifications]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSSingletonAssert(); |  |  |  |     OWSSingletonAssert(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -102,17 +137,13 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |                                              selector:@selector(applicationDidEnterBackground:) |  |  |  |                                              selector:@selector(applicationDidEnterBackground:) | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                  name:OWSApplicationDidEnterBackgroundNotification |  |  |  |                                                  name:OWSApplicationDidEnterBackgroundNotification | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                object:nil]; |  |  |  |                                                object:nil]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     [[NSNotificationCenter defaultCenter] addObserver:self |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                              selector:@selector(registrationStateDidChange) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                  name:RegistrationStateDidChangeNotification |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                object:nil]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     [[NSNotificationCenter defaultCenter] addObserver:self |  |  |  |     [[NSNotificationCenter defaultCenter] addObserver:self | 
			
		
	
		
		
			
				
					
					|  |  |  |                                              selector:@selector(screenLockDidChange:) |  |  |  |                                              selector:@selector(screenLockDidChange:) | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                  name:OWSScreenLock.ScreenLockDidChange |  |  |  |                                                  name:OWSScreenLock.ScreenLockDidChange | 
			
		
	
		
		
			
				
					
					|  |  |  |                                                object:nil]; |  |  |  |                                                object:nil]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     [[NSNotificationCenter defaultCenter] addObserver:self |  |  |  |     [[NSNotificationCenter defaultCenter] addObserver:self | 
			
		
	
		
		
			
				
					
					|  |  |  |                                              selector:@selector(screenLockWasEnabled:) |  |  |  |                                              selector:@selector(clockDidChange:) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                  name:OWSScreenLock.ScreenLockWasEnabled |  |  |  |                                                  name:NSSystemClockDidChangeNotification | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                                                object:nil]; |  |  |  |                                                object:nil]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -121,27 +152,50 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssert(rootWindow); |  |  |  |     OWSAssert(rootWindow); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     self.rootWindow = rootWindow; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self prepareScreenProtectionWithRootWindow:rootWindow]; |  |  |  |     [self prepareScreenProtectionWithRootWindow:rootWindow]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // Initialize the screen lock state. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // It's not safe to access OWSScreenLock.isScreenLockEnabled | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // until the app is ready. | 
			
		
	
		
		
			
				
					
					|  |  |  |     [AppReadiness runNowOrWhenAppIsReady:^{ |  |  |  |     [AppReadiness runNowOrWhenAppIsReady:^{ | 
			
		
	
		
		
			
				
					
					|  |  |  |         [self ensureScreenProtection]; |  |  |  |         self.isScreenLockLocked = OWSScreenLock.sharedManager.isScreenLockEnabled; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self ensureUI]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     }]; |  |  |  |     }]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #pragma mark - Methods |  |  |  | #pragma mark - Methods | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)tryToActivateScreenLockUponBecomingActive |  |  |  | - (void)tryToActivateScreenLockBasedOnCountdown | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssert(!self.appIsInactive); |  |  |  |     OWSAssert(!self.appIsInBackground); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!self.isScreenLockUnlocked) { |  |  |  |     if (!AppReadiness.isAppReady) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         // Screen lock is already activated. |  |  |  |         // It's not safe to access OWSScreenLock.isScreenLockEnabled | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // until the app is ready. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // We don't need to try to lock the screen lock; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // It will be initialized by `setupWithRootWindow`. | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 0", self.logTag); |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 0", self.logTag); | 
			
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (!OWSScreenLock.sharedManager.isScreenLockEnabled) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Screen lock is not enabled. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 1", self.logTag); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (self.isScreenLockLocked) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Screen lock is already activated. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 2", self.logTag); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!self.screenLockCountdownDate) { |  |  |  |     if (!self.screenLockCountdownDate) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // We became inactive, but never started a countdown. |  |  |  |         // We became inactive, but never started a countdown. | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 1", self.logTag); |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 3", self.logTag); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     NSTimeInterval countdownInterval = fabs([self.screenLockCountdownDate timeIntervalSinceNow]); |  |  |  |     NSTimeInterval countdownInterval = fabs([self.screenLockCountdownDate timeIntervalSinceNow]); | 
			
		
	
	
		
		
			
				
					|  |  | @ -149,99 +203,108 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |     NSTimeInterval screenLockTimeout = OWSScreenLock.sharedManager.screenLockTimeout; |  |  |  |     NSTimeInterval screenLockTimeout = OWSScreenLock.sharedManager.screenLockTimeout; | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssert(screenLockTimeout >= 0); |  |  |  |     OWSAssert(screenLockTimeout >= 0); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (countdownInterval >= screenLockTimeout) { |  |  |  |     if (countdownInterval >= screenLockTimeout) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.isScreenLockUnlocked = NO; |  |  |  |         self.isScreenLockLocked = YES; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive YES 1 (%0.3f >= %0.3f)", |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive YES 4 (%0.3f >= %0.3f)", | 
			
		
	
		
		
			
				
					
					|  |  |  |             self.logTag, |  |  |  |             self.logTag, | 
			
		
	
		
		
			
				
					
					|  |  |  |             countdownInterval, |  |  |  |             countdownInterval, | 
			
		
	
		
		
			
				
					
					|  |  |  |             screenLockTimeout); |  |  |  |             screenLockTimeout); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 2 (%0.3f < %0.3f)", |  |  |  |         DDLogVerbose(@"%@ tryToActivateScreenLockUponBecomingActive NO 5 (%0.3f < %0.3f)", | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             self.logTag, |  |  |  |             self.logTag, | 
			
		
	
		
		
			
				
					
					|  |  |  |             countdownInterval, |  |  |  |             countdownInterval, | 
			
		
	
		
		
			
				
					
					|  |  |  |             screenLockTimeout); |  |  |  |             screenLockTimeout); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)setAppIsInactive:(BOOL)appIsInactive |  |  |  | // Setter for property indicating that the app is either | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // inactive or in the background, e.g. not "foreground and active." | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | - (void)setAppIsInactiveOrBackground:(BOOL)appIsInactiveOrBackground | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     _appIsInactive = appIsInactive; |  |  |  |     OWSAssertIsOnMainThread(); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!appIsInactive) { |  |  |  |     _appIsInactiveOrBackground = appIsInactiveOrBackground; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         [self tryToActivateScreenLockUponBecomingActive]; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.screenLockCountdownDate = nil; |  |  |  |     if (appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (!self.isShowingScreenLockUI) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             [self startScreenLockCountdownIfNecessary]; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self tryToActivateScreenLockBasedOnCountdown]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self startInactiveTimerIfNecessary]; |  |  |  |         DDLogInfo(@"%@ setAppIsInactiveOrBackground clear screenLockCountdownDate.", self.logTag); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.screenLockCountdownDate = nil; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |     [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // Setter for property indicating that the app is in the background. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // If true, by definition the app is not active. | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)setAppIsInBackground:(BOOL)appIsInBackground |  |  |  | - (void)setAppIsInBackground:(BOOL)appIsInBackground | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (appIsInBackground && !_appIsInBackground) { |  |  |  |     OWSAssertIsOnMainThread(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         [self startScreenLockCountdownIfNecessary]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     _appIsInBackground = appIsInBackground; |  |  |  |     _appIsInBackground = appIsInBackground; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |     if (self.appIsInBackground) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self startScreenLockCountdownIfNecessary]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self tryToActivateScreenLockBasedOnCountdown]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     [self ensureUI]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)startScreenLockCountdownIfNecessary |  |  |  | - (void)startScreenLockCountdownIfNecessary | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     DDLogVerbose(@"%@ startScreenLockCountdownIfNecessary: %d", self.logTag, self.screenLockCountdownDate != nil); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!self.screenLockCountdownDate) { |  |  |  |     if (!self.screenLockCountdownDate) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ startScreenLockCountdownIfNecessary.", self.logTag); |  |  |  |         DDLogInfo(@"%@ startScreenLockCountdown.", self.logTag); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         self.screenLockCountdownDate = [NSDate new]; |  |  |  |         self.screenLockCountdownDate = [NSDate new]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.didLastUnlockAttemptFail = NO; |  |  |  |     self.didLastUnlockAttemptFail = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self clearInactiveTimer]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)ensureScreenProtection |  |  |  | // Ensure that: | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * The blocking window has the correct state. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | // * That we show the "iOS auth UI to unlock" if necessary. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | - (void)ensureUI | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!AppReadiness.isAppReady) { |  |  |  |     if (!AppReadiness.isAppReady) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         [AppReadiness runNowOrWhenAppIsReady:^{ |  |  |  |         [AppReadiness runNowOrWhenAppIsReady:^{ | 
			
		
	
		
		
			
				
					
					|  |  |  |             [self ensureScreenProtection]; |  |  |  |             [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         }]; |  |  |  |         }]; | 
			
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     BOOL shouldHaveScreenLock = self.shouldHaveScreenLock; |  |  |  |     ScreenLockUIState desiredUIState = self.desiredUIState; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     BOOL shouldHaveScreenProtection = self.shouldHaveScreenProtection; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     BOOL shouldShowBlockWindow = shouldHaveScreenProtection || shouldHaveScreenLock; |  |  |  |     DDLogVerbose(@"%@, ensureUI: %@", self.logTag, NSStringForScreenLockUIState(desiredUIState)); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogVerbose(@"%@, shouldHaveScreenProtection: %d, shouldHaveScreenLock: %d, shouldShowBlockWindow: %d", |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.logTag, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldHaveScreenProtection, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldHaveScreenLock, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldShowBlockWindow); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (self.screenBlockingWindow.hidden != !shouldShowBlockWindow) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogInfo(@"%@, %@.", self.logTag, shouldShowBlockWindow ? @"showing block window" : @"hiding block window"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self updateScreenBlockingWindow:shouldShowBlockWindow shouldHaveScreenLock:shouldHaveScreenLock animated:YES]; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (shouldHaveScreenLock && !self.didLastUnlockAttemptFail) { |  |  |  |     [self updateScreenBlockingWindow:desiredUIState animated:YES]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         [self tryToPresentScreenLockUI]; |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // Show the "iOS auth UI to unlock" if necessary. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (desiredUIState == ScreenLockUIStateScreenLock && !self.didLastUnlockAttemptFail) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self tryToPresentAuthUIToUnlockScreenLock]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)tryToPresentScreenLockUI |  |  |  | - (void)tryToPresentAuthUIToUnlockScreenLock | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // If we no longer want to present the screen lock UI, abort. |  |  |  |     if (self.isShowingScreenLockUI) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     if (!self.shouldHaveScreenLock) { |  |  |  |         // We're already showing the auth UI; abort. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (self.didLastUnlockAttemptFail) { |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (self.isShowingScreenLockUI) { |  |  |  |     if (self.appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Never show the auth UI unless active. | 
			
		
	
		
		
			
				
					
					|  |  |  |         return; |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -254,9 +317,9 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.isShowingScreenLockUI = NO; |  |  |  |         self.isShowingScreenLockUI = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.isScreenLockUnlocked = YES; |  |  |  |         self.isScreenLockLocked = NO; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         [self ensureScreenProtection]; |  |  |  |         [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |         failure:^(NSError *error) { |  |  |  |         failure:^(NSError *error) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             DDLogInfo(@"%@ unlock screen lock failed.", self.logTag); |  |  |  |             DDLogInfo(@"%@ unlock screen lock failed.", self.logTag); | 
			
		
	
	
		
		
			
				
					|  |  | @ -285,54 +348,37 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |             self.didLastUnlockAttemptFail = YES; |  |  |  |             self.didLastUnlockAttemptFail = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Re-show the unlock UI. |  |  |  |             // Re-show the unlock UI. | 
			
		
	
		
		
			
				
					
					|  |  |  |             [self ensureScreenProtection]; |  |  |  |             [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         }]; |  |  |  |         }]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |     [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (BOOL)shouldHaveScreenProtection |  |  |  | // Determines what the state of the app should be. | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | - (ScreenLockUIState)desiredUIState | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Show 'Screen Protection' if: |  |  |  |     if (self.isScreenLockLocked) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     // |  |  |  |         if (self.appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     // * App is inactive and... |  |  |  |             DDLogVerbose(@"%@ desiredUIState: screen protection 1.", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     // * 'Screen Protection' is enabled. |  |  |  |             return ScreenLockUIStateScreenProtection; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     if (!self.appIsInactive) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         return NO; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (!Environment.preferences.screenSecurityIsEnabled) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         return NO; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |         return YES; |  |  |  |             DDLogVerbose(@"%@ desiredUIState: screen lock 2.", self.logTag); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return ScreenLockUIStateScreenLock; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (BOOL)shouldHaveScreenLock |  |  |  |     if (!self.appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |         // App is inactive or background. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     if (![TSAccountManager isRegistered]) { |  |  |  |         DDLogVerbose(@"%@ desiredUIState: none 3.", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         // Don't show 'Screen Lock' if user is not registered. |  |  |  |         return ScreenLockUIStateNone; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ shouldHaveScreenLock NO 1.", self.logTag); |  |  |  |     } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         return NO; |  |  |  | 
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (!OWSScreenLock.sharedManager.isScreenLockEnabled) { |  |  |  |     if (Environment.preferences.screenSecurityIsEnabled) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         // Don't show 'Screen Lock' if 'Screen Lock' isn't enabled. |  |  |  |         DDLogVerbose(@"%@ desiredUIState: screen protection 4.", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ shouldHaveScreenLock NO 2.", self.logTag); |  |  |  |         return ScreenLockUIStateScreenProtection; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         return NO; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (self.appIsInBackground) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // 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) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Don't show 'Screen Lock' if app is inactive. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ shouldHaveScreenLock NO 5.", self.logTag); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         return NO; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |         BOOL shouldHaveScreenLock = !self.isScreenLockUnlocked; |  |  |  |         DDLogVerbose(@"%@ desiredUIState: none 5.", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         DDLogVerbose(@"%@ shouldHaveScreenLock ? %d.", self.logTag, shouldHaveScreenLock); |  |  |  |         return ScreenLockUIStateNone; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         return shouldHaveScreenLock; |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -346,7 +392,7 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |                       buttonTitle:nil |  |  |  |                       buttonTitle:nil | 
			
		
	
		
		
			
				
					
					|  |  |  |                      buttonAction:^(UIAlertAction *action) { |  |  |  |                      buttonAction:^(UIAlertAction *action) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                          // After the alert, re-show the unlock UI. |  |  |  |                          // After the alert, re-show the unlock UI. | 
			
		
	
		
		
			
				
					
					|  |  |  |                          [self ensureScreenProtection]; |  |  |  |                          [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                      }]; |  |  |  |                      }]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -360,15 +406,14 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssert(rootWindow); |  |  |  |     OWSAssert(rootWindow); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds]; |  |  |  |     UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     window.hidden = YES; |  |  |  |     window.hidden = NO; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     window.windowLevel = UIWindowLevel_Background; | 
			
		
	
		
		
			
				
					
					|  |  |  |     window.opaque = YES; |  |  |  |     window.opaque = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |     window.windowLevel = CGFLOAT_MAX; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     window.backgroundColor = UIColor.ows_materialBlueColor; |  |  |  |     window.backgroundColor = UIColor.ows_materialBlueColor; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     UIViewController *viewController = [UIViewController new]; |  |  |  |     UIViewController *viewController = [UIViewController new]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     viewController.view.backgroundColor = UIColor.ows_materialBlueColor; |  |  |  |     viewController.view.backgroundColor = UIColor.ows_materialBlueColor; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     UIView *rootView = viewController.view; |  |  |  |     UIView *rootView = viewController.view; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     UIView *edgesView = [UIView containerView]; |  |  |  |     UIView *edgesView = [UIView containerView]; | 
			
		
	
	
		
		
			
				
					|  |  | @ -413,7 +458,8 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.screenBlockingImageView = imageView; |  |  |  |     self.screenBlockingImageView = imageView; | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.screenBlockingButton = button; |  |  |  |     self.screenBlockingButton = button; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self updateScreenBlockingWindow:YES shouldHaveScreenLock:NO animated:NO]; |  |  |  |     // Default to screen protection until we know otherwise. | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     [self updateScreenBlockingWindow:ScreenLockUIStateNone animated:NO]; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // The "screen blocking" window has three possible states: |  |  |  | // The "screen blocking" window has three possible states: | 
			
		
	
	
		
		
			
				
					|  |  | @ -423,13 +469,48 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | // * "Screen Lock, local auth UI presented". Move the Signal logo so that it is visible. |  |  |  | // * "Screen Lock, local auth UI presented". Move the Signal logo so that it is visible. | 
			
		
	
		
		
			
				
					
					|  |  |  | // * "Screen Lock, local auth UI not presented". Move the Signal logo so that it is visible, |  |  |  | // * "Screen Lock, local auth UI not presented". Move the Signal logo so that it is visible, | 
			
		
	
		
		
			
				
					
					|  |  |  | //    show "unlock" button. |  |  |  | //    show "unlock" button. | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)updateScreenBlockingWindow:(BOOL)shouldShowBlockWindow |  |  |  | - (void)updateScreenBlockingWindow:(ScreenLockUIState)desiredUIState animated:(BOOL)animated | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |               shouldHaveScreenLock:(BOOL)shouldHaveScreenLock |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                           animated:(BOOL)animated |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.screenBlockingWindow.hidden = !shouldShowBlockWindow; |  |  |  |     BOOL shouldShowBlockWindow = desiredUIState != ScreenLockUIStateNone; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (self.rootWindow.hidden != shouldShowBlockWindow) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogInfo(@"%@, %@.", self.logTag, shouldShowBlockWindow ? @"showing block window" : @"hiding block window"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // When we show the block window, try to capture the first responder of | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // the root window before it is hidden. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // When we hide the root window, its first responder will resign. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (shouldShowBlockWindow && !self.rootWindow.hidden) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.rootWindowResponder = [UIResponder currentFirstResponder]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogInfo(@"%@ trying to capture self.rootWindowResponder: %@", self.logTag, self.rootWindowResponder); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // * Show/hide the app's root window as necessary. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // * Never hide the blocking window (that can lead to bad frames). | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     //   Instead, manipulate its window level to move it in front of | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     //   or behind the root window. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if (shouldShowBlockWindow) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Show the blocking window in front of the status bar. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.screenBlockingWindow.windowLevel = UIWindowLevelStatusBar + 1; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.rootWindow.hidden = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.screenBlockingWindow.windowLevel = UIWindowLevel_Background; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self.rootWindow makeKeyAndVisible]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // When we hide the block window, try to restore the first | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // responder of the root window. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // It's important we restore first responder status once the user completes | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // In some cases, (RegistrationLock Reminder) it just puts the keyboard back where | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // the user needs it, saving them a tap. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // But in the case of an inputAccessoryView, like the ConversationViewController, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // failing to restore firstResponder could hide the input toolbar. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         DDLogInfo(@"%@ trying to restore self.rootWindowResponder: %@", self.logTag, self.rootWindowResponder); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         [self.rootWindowResponder becomeFirstResponder]; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.rootWindowResponder = nil; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     UIView *rootView = self.screenBlockingViewController.view; |  |  |  |     UIView *rootView = self.screenBlockingViewController.view; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -437,15 +518,7 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     NSMutableArray<NSLayoutConstraint *> *screenBlockingConstraints = [NSMutableArray new]; |  |  |  |     NSMutableArray<NSLayoutConstraint *> *screenBlockingConstraints = [NSMutableArray new]; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     BOOL shouldShowUnlockButton = (!self.appIsInactive && !self.appIsInBackground && self.didLastUnlockAttemptFail); |  |  |  |     BOOL shouldHaveScreenLock = desiredUIState == ScreenLockUIStateScreenLock; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogVerbose(@"%@ updateScreenBlockingWindow. shouldShowBlockWindow: %d, shouldHaveScreenLock: %d, " |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                  @"shouldShowUnlockButton: %d.", |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.logTag, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldShowBlockWindow, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldHaveScreenLock, |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         shouldShowUnlockButton); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     NSString *signature = [NSString stringWithFormat:@"%d %d", shouldHaveScreenLock, self.isShowingScreenLockUI]; |  |  |  |     NSString *signature = [NSString stringWithFormat:@"%d %d", shouldHaveScreenLock, self.isShowingScreenLockUI]; | 
			
		
	
		
		
			
				
					
					|  |  |  |     if ([NSObject isNullableObject:self.screenBlockingSignature equalTo:signature]) { |  |  |  |     if ([NSObject isNullableObject:self.screenBlockingSignature equalTo:signature]) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Skip redundant work to avoid interfering with ongoing animations. |  |  |  |         // Skip redundant work to avoid interfering with ongoing animations. | 
			
		
	
	
		
		
			
				
					|  |  | @ -481,48 +554,35 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |     OWSAssertIsOnMainThread(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogInfo(@"showUnlockUI"); |  |  |  |     if (self.appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // This button can be pressed while the app is inactive | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // for a brief window while the iOS auth UI is dismissing. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         return; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     DDLogInfo(@"%@ unlockButtonTapped", self.logTag); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.didLastUnlockAttemptFail = NO; |  |  |  |     self.didLastUnlockAttemptFail = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |     [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #pragma mark - Events |  |  |  | #pragma mark - Events | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)screenLockDidChange:(NSNotification *)notification |  |  |  | - (void)screenLockDidChange:(NSNotification *)notification | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |     [self ensureUI]; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)screenLockWasEnabled:(NSNotification *)notification |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     // When we enable screen lock, consider that an unlock. |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.isScreenLockUnlocked = YES; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogVerbose(@"%@ screenLockWasEnabled", self.logTag); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)registrationStateDidChange |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     OWSAssertIsOnMainThread(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     DDLogInfo(@"registrationStateDidChange"); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self ensureScreenProtection]; |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)clearAuthUIWhenActive |  |  |  | - (void)clearAuthUIWhenActive | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // For continuity, continue to present blocking screen in "screen lock" mode while |  |  |  |     // For continuity, continue to present blocking screen in "screen lock" mode while | 
			
		
	
		
		
			
				
					
					|  |  |  |     // dismissing the "local auth UI". |  |  |  |     // dismissing the "local auth UI". | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (self.appIsInactive) { |  |  |  |     if (self.appIsInactiveOrBackground) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         self.shouldClearAuthUIWhenActive = YES; |  |  |  |         self.shouldClearAuthUIWhenActive = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.isShowingScreenLockUI = NO; |  |  |  |         self.isShowingScreenLockUI = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  |         [self ensureScreenProtection]; |  |  |  |         [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -533,12 +593,12 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.isShowingScreenLockUI = NO; |  |  |  |         self.isShowingScreenLockUI = NO; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.appIsInactive = NO; |  |  |  |     self.appIsInactiveOrBackground = NO; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)applicationWillResignActive:(NSNotification *)notification |  |  |  | - (void)applicationWillResignActive:(NSNotification *)notification | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.appIsInactive = YES; |  |  |  |     self.appIsInactiveOrBackground = YES; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)applicationWillEnterForeground:(NSNotification *)notification |  |  |  | - (void)applicationWillEnterForeground:(NSNotification *)notification | 
			
		
	
	
		
		
			
				
					|  |  | @ -551,29 +611,27 @@ NS_ASSUME_NONNULL_BEGIN | 
			
		
	
		
		
			
				
					
					|  |  |  |     self.appIsInBackground = YES; |  |  |  |     self.appIsInBackground = YES; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #pragma mark - Inactive Timer |  |  |  | // Whenever the device date/time is edited by the user, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | // trigger screen lock immediately if enabled. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | - (void)inactiveTimerDidFire |  |  |  | - (void)clockDidChange:(NSNotification *)notification | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |     [self startScreenLockCountdownIfNecessary]; |  |  |  |     DDLogInfo(@"%@ clock did change", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)startInactiveTimerIfNecessary |  |  |  |     if (!AppReadiness.isAppReady) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |         // It's not safe to access OWSScreenLock.isScreenLockEnabled | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     if (self.appIsInactive && !self.isShowingScreenLockUI && !self.inactiveTimer) { |  |  |  |         // until the app is ready. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         [self.inactiveTimer invalidate]; |  |  |  |         // | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         self.inactiveTimer = [NSTimer weakScheduledTimerWithTimeInterval:45.f |  |  |  |         // We don't need to try to lock the screen lock; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                                   target:self |  |  |  |         // It will be initialized by `setupWithRootWindow`. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                                 selector:@selector(inactiveTimerDidFire) |  |  |  |         DDLogVerbose(@"%@ clockDidChange 0", self.logTag); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                                 userInfo:nil |  |  |  |         return; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                                                                  repeats:NO]; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     self.isScreenLockLocked = OWSScreenLock.sharedManager.isScreenLockEnabled; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | - (void)clearInactiveTimer |  |  |  |     // NOTE: this notifications fires _before_ applicationDidBecomeActive, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  |     // which is desirable.  Don't assume that though; call ensureUI | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     [self.inactiveTimer invalidate]; |  |  |  |     // just in case it's necessary. | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     self.inactiveTimer = nil; |  |  |  |     [self ensureUI]; | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | @end |  |  |  | @end | 
			
		
	
	
		
		
			
				
					|  |  | 
 |