mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Add screen lock feature.
This commit is contained in:
parent
1f82891024
commit
cf0e6fce09
|
@ -205,6 +205,7 @@
|
||||||
34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */; };
|
34D1F0BD1F8D108C0066283D /* AttachmentUploadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */; };
|
||||||
34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */; };
|
34D1F0C01F8EC1760066283D /* MessageRecipientStatusUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */; };
|
||||||
34D2CCD4206294B900CB1A14 /* OWSScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */; };
|
34D2CCD4206294B900CB1A14 /* OWSScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */; };
|
||||||
|
34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */; };
|
||||||
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
|
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
|
||||||
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; };
|
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; };
|
||||||
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; };
|
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; };
|
||||||
|
@ -811,6 +812,8 @@
|
||||||
34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AttachmentUploadView.m; sourceTree = "<group>"; };
|
34D1F0BC1F8D108C0066283D /* AttachmentUploadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AttachmentUploadView.m; sourceTree = "<group>"; };
|
||||||
34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRecipientStatusUtils.swift; sourceTree = "<group>"; };
|
34D1F0BF1F8EC1760066283D /* MessageRecipientStatusUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRecipientStatusUtils.swift; sourceTree = "<group>"; };
|
||||||
34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSScreenLock.swift; sourceTree = "<group>"; };
|
34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSScreenLock.swift; sourceTree = "<group>"; };
|
||||||
|
34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSScreenLockUI.h; sourceTree = "<group>"; };
|
||||||
|
34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSScreenLockUI.m; sourceTree = "<group>"; };
|
||||||
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = "<group>"; };
|
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = "<group>"; };
|
||||||
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = "<group>"; };
|
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = "<group>"; };
|
||||||
34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = "<group>"; };
|
34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = "<group>"; };
|
||||||
|
@ -1972,6 +1975,8 @@
|
||||||
340FC8CB20518C76007AEB0F /* OWSBackupJob.h */,
|
340FC8CB20518C76007AEB0F /* OWSBackupJob.h */,
|
||||||
340FC8CC20518C76007AEB0F /* OWSBackupJob.m */,
|
340FC8CC20518C76007AEB0F /* OWSBackupJob.m */,
|
||||||
34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */,
|
34D2CCD3206294B900CB1A14 /* OWSScreenLock.swift */,
|
||||||
|
34D2CCD82062E7D000CB1A14 /* OWSScreenLockUI.h */,
|
||||||
|
34D2CCD92062E7D000CB1A14 /* OWSScreenLockUI.m */,
|
||||||
4579431C1E7C8CE9008ED0C0 /* Pastelog.h */,
|
4579431C1E7C8CE9008ED0C0 /* Pastelog.h */,
|
||||||
4579431D1E7C8CE9008ED0C0 /* Pastelog.m */,
|
4579431D1E7C8CE9008ED0C0 /* Pastelog.m */,
|
||||||
450DF2041E0D74AC003D14BE /* Platform.swift */,
|
450DF2041E0D74AC003D14BE /* Platform.swift */,
|
||||||
|
@ -3212,6 +3217,7 @@
|
||||||
45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */,
|
45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */,
|
||||||
340FC8A7204DAC8D007AEB0F /* RegistrationViewController.m in Sources */,
|
340FC8A7204DAC8D007AEB0F /* RegistrationViewController.m in Sources */,
|
||||||
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
||||||
|
34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */,
|
||||||
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,
|
||||||
345BC30C2047030700257B7C /* OWS2FASettingsViewController.m in Sources */,
|
345BC30C2047030700257B7C /* OWS2FASettingsViewController.m in Sources */,
|
||||||
340FC8CA20517B84007AEB0F /* OWSBackupImportJob.m in Sources */,
|
340FC8CA20517B84007AEB0F /* OWSBackupImportJob.m in Sources */,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#import "OWS2FASettingsViewController.h"
|
#import "OWS2FASettingsViewController.h"
|
||||||
#import "OWSBackup.h"
|
#import "OWSBackup.h"
|
||||||
#import "OWSNavigationController.h"
|
#import "OWSNavigationController.h"
|
||||||
|
#import "OWSScreenLockUI.h"
|
||||||
#import "Pastelog.h"
|
#import "Pastelog.h"
|
||||||
#import "PushManager.h"
|
#import "PushManager.h"
|
||||||
#import "RegistrationViewController.h"
|
#import "RegistrationViewController.h"
|
||||||
|
@ -66,15 +67,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
@property (nonatomic) BOOL areVersionMigrationsComplete;
|
@property (nonatomic) BOOL areVersionMigrationsComplete;
|
||||||
@property (nonatomic) BOOL didAppLaunchFail;
|
@property (nonatomic) BOOL didAppLaunchFail;
|
||||||
|
|
||||||
// Unlike UIApplication.applicationState, this state is
|
|
||||||
// updated conservatively, e.g. the flag is cleared during
|
|
||||||
// "will enter background."
|
|
||||||
@property (nonatomic) BOOL appIsInactive;
|
|
||||||
@property (nonatomic, nullable) NSDate *appBecameInactiveDate;
|
|
||||||
@property (nonatomic) UIWindow *screenBlockingWindow;
|
|
||||||
@property (nonatomic) BOOL hasUnlockedScreenLock;
|
|
||||||
@property (nonatomic) BOOL isShowingScreenLockUI;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
@ -87,8 +79,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
DDLogWarn(@"%@ applicationDidEnterBackground.", self.logTag);
|
DDLogWarn(@"%@ applicationDidEnterBackground.", self.logTag);
|
||||||
|
|
||||||
[DDLog flushLog];
|
[DDLog flushLog];
|
||||||
|
|
||||||
self.appIsInactive = YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||||
|
@ -200,7 +190,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
[self application:application didReceiveRemoteNotification:remoteNotif];
|
[self application:application didReceiveRemoteNotification:remoteNotif];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self prepareScreenProtection];
|
[OWSScreenLockUI.sharedManager setupWithRootWindow:self.window];
|
||||||
|
|
||||||
// Ensure OWSContactsSyncing is instantiated.
|
// Ensure OWSContactsSyncing is instantiated.
|
||||||
[OWSContactsSyncing sharedManager];
|
[OWSContactsSyncing sharedManager];
|
||||||
|
@ -217,10 +207,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
selector:@selector(registrationLockDidChange:)
|
selector:@selector(registrationLockDidChange:)
|
||||||
name:NSNotificationName_2FAStateDidChange
|
name:NSNotificationName_2FAStateDidChange
|
||||||
object:nil];
|
object:nil];
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
||||||
selector:@selector(screenLockDidChange:)
|
|
||||||
name:OWSScreenLock.ScreenLockDidChange
|
|
||||||
object:nil];
|
|
||||||
|
|
||||||
DDLogInfo(@"%@ application: didFinishLaunchingWithOptions completed.", self.logTag);
|
DDLogInfo(@"%@ application: didFinishLaunchingWithOptions completed.", self.logTag);
|
||||||
|
|
||||||
|
@ -604,8 +590,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
[self handleActivation];
|
[self handleActivation];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
self.appIsInactive = NO;
|
|
||||||
|
|
||||||
DDLogInfo(@"%@ applicationDidBecomeActive completed.", self.logTag);
|
DDLogInfo(@"%@ applicationDidBecomeActive completed.", self.logTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,8 +707,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
|
|
||||||
DDLogWarn(@"%@ applicationWillResignActive.", self.logTag);
|
DDLogWarn(@"%@ applicationWillResignActive.", self.logTag);
|
||||||
|
|
||||||
self.appIsInactive = YES;
|
|
||||||
|
|
||||||
__block OWSBackgroundTask *backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
__block OWSBackgroundTask *backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||||
[AppReadiness runNowOrWhenAppIsReady:^{
|
[AppReadiness runNowOrWhenAppIsReady:^{
|
||||||
if ([TSAccountManager isRegistered]) {
|
if ([TSAccountManager isRegistered]) {
|
||||||
|
@ -1152,8 +1134,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
[self ensureRootViewController];
|
[self ensureRootViewController];
|
||||||
|
|
||||||
[OWSBackup.sharedManager setup];
|
[OWSBackup.sharedManager setup];
|
||||||
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)registrationStateDidChange
|
- (void)registrationStateDidChange
|
||||||
|
@ -1179,8 +1159,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
// For non-legacy users, read receipts are on by default.
|
// For non-legacy users, read receipts are on by default.
|
||||||
[OWSReadReceiptManager.sharedManager setAreReadReceiptsEnabled:YES];
|
[OWSReadReceiptManager.sharedManager setAreReadReceiptsEnabled:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)registrationLockDidChange:(NSNotification *)notification
|
- (void)registrationLockDidChange:(NSNotification *)notification
|
||||||
|
@ -1215,151 +1193,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
}
|
}
|
||||||
|
|
||||||
[AppUpdateNag.sharedInstance showAppUpgradeNagIfNecessary];
|
[AppUpdateNag.sharedInstance showAppUpgradeNagIfNecessary];
|
||||||
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Screen Lock and Protection
|
|
||||||
|
|
||||||
- (void)setAppIsInactive:(BOOL)appIsInactive
|
|
||||||
{
|
|
||||||
if (appIsInactive) {
|
|
||||||
if (!_appIsInactive) {
|
|
||||||
// Whenever app becomes inactive, clear this state.
|
|
||||||
self.hasUnlockedScreenLock = NO;
|
|
||||||
|
|
||||||
// Note the time when app became inactive.
|
|
||||||
self.appBecameInactiveDate = [NSDate new];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_appIsInactive = appIsInactive;
|
|
||||||
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)ensureScreenProtection
|
|
||||||
{
|
|
||||||
OWSAssertIsOnMainThread();
|
|
||||||
|
|
||||||
if (!AppReadiness.isAppReady) {
|
|
||||||
[AppReadiness runNowOrWhenAppIsReady:^{
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't show 'Screen Protection' if:
|
|
||||||
//
|
|
||||||
// * App is active or...
|
|
||||||
// * 'Screen Protection' is not enabled.
|
|
||||||
BOOL shouldHaveScreenProtection = (self.appIsInactive && Environment.preferences.screenSecurityIsEnabled);
|
|
||||||
|
|
||||||
BOOL shouldHaveScreenLock = NO;
|
|
||||||
if (self.appIsInactive) {
|
|
||||||
// Don't show 'Screen Lock' if app is inactive.
|
|
||||||
} else if (![TSAccountManager isRegistered]) {
|
|
||||||
// Don't show 'Screen Lock' if user is not registered.
|
|
||||||
} else if (!OWSScreenLock.sharedManager.isScreenLockEnabled) {
|
|
||||||
// Don't show 'Screen Lock' if 'Screen Lock' isn't enabled.
|
|
||||||
} else if (self.hasUnlockedScreenLock) {
|
|
||||||
// Don't show 'Screen Lock' if 'Screen Lock' has been unlocked.
|
|
||||||
} else if (!self.appBecameInactiveDate) {
|
|
||||||
// Show 'Screen Lock' if app hasn't become inactive yet (just launched).
|
|
||||||
shouldHaveScreenLock = YES;
|
|
||||||
} else {
|
|
||||||
OWSAssert(self.appBecameInactiveDate);
|
|
||||||
|
|
||||||
NSTimeInterval screenLockInterval = fabs([self.appBecameInactiveDate timeIntervalSinceNow]);
|
|
||||||
NSTimeInterval screenLockTimeout = OWSScreenLock.sharedManager.screenLockTimeout;
|
|
||||||
OWSAssert(screenLockInterval >= 0);
|
|
||||||
OWSAssert(screenLockTimeout >= 0);
|
|
||||||
if (self.appBecameInactiveDate && screenLockInterval < screenLockTimeout) {
|
|
||||||
// Don't show 'Screen Lock' if 'Screen Lock' timeout hasn't elapsed.
|
|
||||||
shouldHaveScreenProtection = YES;
|
|
||||||
|
|
||||||
// Check again when screen lock timeout should elapse.
|
|
||||||
NSTimeInterval screenLockRemaining = screenLockTimeout - screenLockInterval + 0.2f;
|
|
||||||
OWSAssert(screenLockRemaining >= 0);
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(screenLockRemaining * NSEC_PER_SEC)),
|
|
||||||
dispatch_get_main_queue(),
|
|
||||||
^{
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Otherwise, show 'Screen Lock'.
|
|
||||||
shouldHaveScreenLock = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL shouldShowBlockWindow = shouldHaveScreenProtection || shouldHaveScreenLock;
|
|
||||||
self.screenBlockingWindow.hidden = !shouldShowBlockWindow;
|
|
||||||
|
|
||||||
if (shouldHaveScreenLock) {
|
|
||||||
if (!self.isShowingScreenLockUI) {
|
|
||||||
self.isShowingScreenLockUI = YES;
|
|
||||||
|
|
||||||
[OWSScreenLock.sharedManager tryToUnlockScreenLockWithSuccess:^{
|
|
||||||
DDLogInfo(@"%@ unlock screen lock succeeded.", self.logTag);
|
|
||||||
self.isShowingScreenLockUI = NO;
|
|
||||||
self.hasUnlockedScreenLock = YES;
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
|
||||||
failure:^(NSError *error) {
|
|
||||||
DDLogInfo(@"%@ unlock screen lock failed.", self.logTag);
|
|
||||||
self.isShowingScreenLockUI = NO;
|
|
||||||
|
|
||||||
[self showScreenLockFailureAlertWithMessage:error.localizedDescription];
|
|
||||||
}
|
|
||||||
cancel:^{
|
|
||||||
DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag);
|
|
||||||
self.isShowingScreenLockUI = NO;
|
|
||||||
|
|
||||||
[self showScreenLockFailureAlertWithMessage:
|
|
||||||
NSLocalizedString(@"SCREEN_LOCK_UNLOCK_CANCELLED",
|
|
||||||
@"Message for alert indicating that screen lock unlock was cancelled.")];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)showScreenLockFailureAlertWithMessage:(NSString *)message
|
|
||||||
{
|
|
||||||
OWSAssertIsOnMainThread();
|
|
||||||
|
|
||||||
[OWSAlerts showAlertWithTitle:NSLocalizedString(@"SCREEN_LOCK_UNLOCK_FAILED",
|
|
||||||
@"Title for alert indicating that screen lock could not be unlocked.")
|
|
||||||
message:message
|
|
||||||
buttonTitle:nil
|
|
||||||
buttonAction:^(UIAlertAction *action) {
|
|
||||||
// After the alert, re-show the unlock UI.
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)screenLockDidChange:(NSNotification *)notification
|
|
||||||
{
|
|
||||||
[self ensureScreenProtection];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'Screen Blocking' window obscures the app screen:
|
|
||||||
//
|
|
||||||
// * In the app switcher.
|
|
||||||
// * During 'Screen Lock' unlock process.
|
|
||||||
- (void)prepareScreenProtection
|
|
||||||
{
|
|
||||||
OWSAssertIsOnMainThread();
|
|
||||||
|
|
||||||
UIWindow *window = [[UIWindow alloc] initWithFrame:self.window.bounds];
|
|
||||||
window.hidden = YES;
|
|
||||||
window.opaque = YES;
|
|
||||||
window.userInteractionEnabled = NO;
|
|
||||||
window.windowLevel = CGFLOAT_MAX;
|
|
||||||
window.backgroundColor = UIColor.ows_materialBlueColor;
|
|
||||||
window.rootViewController =
|
|
||||||
[[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController];
|
|
||||||
|
|
||||||
self.screenBlockingWindow = window;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -91,10 +91,6 @@
|
||||||
self.title = NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE", @"Title for settings activity");
|
self.title = NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE", @"Title for settings activity");
|
||||||
|
|
||||||
[self updateTableContents];
|
[self updateTableContents];
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self showPrivacy];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated
|
- (void)viewWillAppear:(BOOL)animated
|
||||||
|
|
|
@ -167,26 +167,19 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
}]];
|
}]];
|
||||||
[contents addSection:twoFactorAuthSection];
|
[contents addSection:twoFactorAuthSection];
|
||||||
|
|
||||||
// BOOL showScreenLockUI = OWSScreenLock.sharedManager.isScreenLockSupported;
|
OWSTableSection *screenLockSection = [OWSTableSection new];
|
||||||
//#ifdef DEBUG
|
screenLockSection.headerTitle = NSLocalizedString(
|
||||||
// showScreenLockUI = YES;
|
@"SETTINGS_SCREEN_LOCK_SECTION_TITLE", @"Title for the 'screen lock' section of the privacy settings.");
|
||||||
//#endif
|
screenLockSection.footerTitle = NSLocalizedString(
|
||||||
BOOL showScreenLockUI = YES;
|
@"SETTINGS_SCREEN_LOCK_SECTION_FOOTER", @"Footer for the 'screen lock' section of the privacy settings.");
|
||||||
if (showScreenLockUI) {
|
[screenLockSection
|
||||||
OWSTableSection *screenLockSection = [OWSTableSection new];
|
addItem:[OWSTableItem
|
||||||
screenLockSection.headerTitle = NSLocalizedString(
|
switchItemWithText:NSLocalizedString(@"SETTINGS_SCREEN_LOCK_SWITCH_LABEL",
|
||||||
@"SETTINGS_SCREEN_LOCK_SECTION_TITLE", @"Title for the 'screen lock' section of the privacy settings.");
|
@"Label for the 'enable screen lock' switch of the privacy settings.")
|
||||||
screenLockSection.footerTitle = NSLocalizedString(
|
isOn:OWSScreenLock.sharedManager.isScreenLockEnabled
|
||||||
@"SETTINGS_SCREEN_LOCK_SECTION_FOOTER", @"Footer for the 'screen lock' section of the privacy settings.");
|
target:self
|
||||||
[screenLockSection
|
selector:@selector(isScreenLockEnabledDidChange:)]];
|
||||||
addItem:[OWSTableItem
|
[contents addSection:screenLockSection];
|
||||||
switchItemWithText:NSLocalizedString(@"SETTINGS_SCREEN_LOCK_SWITCH_LABEL",
|
|
||||||
@"Label for the 'enable screen lock' switch of the privacy settings.")
|
|
||||||
isOn:OWSScreenLock.sharedManager.isScreenLockEnabled
|
|
||||||
target:self
|
|
||||||
selector:@selector(isScreenLockEnabledDidChange:)]];
|
|
||||||
[contents addSection:screenLockSection];
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contents = contents;
|
self.contents = contents;
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,10 +284,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
|
||||||
}
|
}
|
||||||
|
|
||||||
[self updateBarButtonItems];
|
[self updateBarButtonItems];
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
[self settingsButtonPressed:nil];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
|
|
|
@ -173,7 +173,7 @@ import LocalAuthentication
|
||||||
let completion = { (outcome: OWSScreenLockOutcome) in
|
let completion = { (outcome: OWSScreenLockOutcome) in
|
||||||
switch outcome {
|
switch outcome {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
Logger.error("\(self.TAG) enable screen lock failed with error: \(error)")
|
Logger.error("\(self.TAG) local authentication failed with error: \(error)")
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -189,13 +189,13 @@ import LocalAuthentication
|
||||||
var authError: NSError?
|
var authError: NSError?
|
||||||
let canEvaluatePolicy = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError)
|
let canEvaluatePolicy = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError)
|
||||||
if !canEvaluatePolicy || authError != nil {
|
if !canEvaluatePolicy || authError != nil {
|
||||||
Logger.error("\(TAG) could not determine if screen lock is supported: \(String(describing: authError))")
|
Logger.error("\(TAG) could not determine if local authentication is supported: \(String(describing: authError))")
|
||||||
|
|
||||||
let outcome = self.outcomeForLAError(errorParam: authError,
|
let outcome = self.outcomeForLAError(errorParam: authError,
|
||||||
defaultErrorDescription: defaultErrorDescription)
|
defaultErrorDescription: defaultErrorDescription)
|
||||||
switch outcome {
|
switch outcome {
|
||||||
case .success:
|
case .success:
|
||||||
owsFail("\(self.TAG) unexpected success")
|
owsFail("\(self.TAG) local authentication unexpected success")
|
||||||
completion(.failure(error:defaultErrorDescription))
|
completion(.failure(error:defaultErrorDescription))
|
||||||
case .cancel, .failure:
|
case .cancel, .failure:
|
||||||
completion(outcome)
|
completion(outcome)
|
||||||
|
@ -214,14 +214,14 @@ import LocalAuthentication
|
||||||
|
|
||||||
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: localizedReason) { success, evaluateError in
|
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: localizedReason) { success, evaluateError in
|
||||||
if success {
|
if success {
|
||||||
Logger.info("\(self.TAG) enable screen lock succeeded.")
|
Logger.info("\(self.TAG) local authentication succeeded.")
|
||||||
completion(.success)
|
completion(.success)
|
||||||
} else {
|
} else {
|
||||||
let outcome = self.outcomeForLAError(errorParam: evaluateError,
|
let outcome = self.outcomeForLAError(errorParam: evaluateError,
|
||||||
defaultErrorDescription: defaultErrorDescription)
|
defaultErrorDescription: defaultErrorDescription)
|
||||||
switch outcome {
|
switch outcome {
|
||||||
case .success:
|
case .success:
|
||||||
owsFail("\(self.TAG) unexpected success")
|
owsFail("\(self.TAG) local authentication unexpected success")
|
||||||
completion(.failure(error:defaultErrorDescription))
|
completion(.failure(error:defaultErrorDescription))
|
||||||
case .cancel, .failure:
|
case .cancel, .failure:
|
||||||
completion(outcome)
|
completion(outcome)
|
||||||
|
|
17
Signal/src/util/OWSScreenLockUI.h
Normal file
17
Signal/src/util/OWSScreenLockUI.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface OWSScreenLockUI : NSObject
|
||||||
|
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
+ (instancetype)sharedManager;
|
||||||
|
|
||||||
|
- (void)setupWithRootWindow:(UIWindow *)rootWindow;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
256
Signal/src/util/OWSScreenLockUI.m
Normal file
256
Signal/src/util/OWSScreenLockUI.m
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "OWSScreenLockUI.h"
|
||||||
|
#import "Signal-Swift.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface OWSScreenLockUI ()
|
||||||
|
|
||||||
|
// Unlike UIApplication.applicationState, this state is
|
||||||
|
// updated conservatively, e.g. the flag is cleared during
|
||||||
|
// "will enter background."
|
||||||
|
@property (nonatomic) BOOL appIsInactive;
|
||||||
|
@property (nonatomic, nullable) NSDate *appBecameInactiveDate;
|
||||||
|
@property (nonatomic) UIWindow *screenBlockingWindow;
|
||||||
|
@property (nonatomic) BOOL hasUnlockedScreenLock;
|
||||||
|
@property (nonatomic) BOOL isShowingScreenLockUI;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
|
||||||
|
@implementation OWSScreenLockUI
|
||||||
|
|
||||||
|
+ (instancetype)sharedManager
|
||||||
|
{
|
||||||
|
static OWSScreenLockUI *instance = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
instance = [[self alloc] initDefault];
|
||||||
|
});
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initDefault
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
|
if (!self) {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self observeNotifications];
|
||||||
|
|
||||||
|
OWSSingletonAssert();
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)observeNotifications
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(applicationDidBecomeActive:)
|
||||||
|
name:OWSApplicationDidBecomeActiveNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(applicationWillResignActive:)
|
||||||
|
name:OWSApplicationWillResignActiveNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(registrationStateDidChange)
|
||||||
|
name:RegistrationStateDidChangeNotification
|
||||||
|
object:nil];
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
|
selector:@selector(screenLockDidChange:)
|
||||||
|
name:OWSScreenLock.ScreenLockDidChange
|
||||||
|
object:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setupWithRootWindow:(UIWindow *)rootWindow
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
OWSAssert(rootWindow);
|
||||||
|
|
||||||
|
[self prepareScreenProtectionWithRootWindow:rootWindow];
|
||||||
|
|
||||||
|
[AppReadiness runNowOrWhenAppIsReady:^{
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Methods
|
||||||
|
|
||||||
|
- (void)setAppIsInactive:(BOOL)appIsInactive
|
||||||
|
{
|
||||||
|
if (appIsInactive) {
|
||||||
|
if (!_appIsInactive) {
|
||||||
|
// Whenever app becomes inactive, clear this state.
|
||||||
|
self.hasUnlockedScreenLock = NO;
|
||||||
|
|
||||||
|
// Note the time when app became inactive.
|
||||||
|
self.appBecameInactiveDate = [NSDate new];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_appIsInactive = appIsInactive;
|
||||||
|
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)ensureScreenProtection
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
if (!AppReadiness.isAppReady) {
|
||||||
|
[AppReadiness runNowOrWhenAppIsReady:^{
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't show 'Screen Protection' if:
|
||||||
|
//
|
||||||
|
// * App is active or...
|
||||||
|
// * 'Screen Protection' is not enabled.
|
||||||
|
BOOL shouldHaveScreenProtection = (self.appIsInactive && Environment.preferences.screenSecurityIsEnabled);
|
||||||
|
|
||||||
|
BOOL shouldHaveScreenLock = NO;
|
||||||
|
if (self.appIsInactive) {
|
||||||
|
// Don't show 'Screen Lock' if app is inactive.
|
||||||
|
} else if (![TSAccountManager isRegistered]) {
|
||||||
|
// Don't show 'Screen Lock' if user is not registered.
|
||||||
|
} else if (!OWSScreenLock.sharedManager.isScreenLockEnabled) {
|
||||||
|
// Don't show 'Screen Lock' if 'Screen Lock' isn't enabled.
|
||||||
|
} else if (self.hasUnlockedScreenLock) {
|
||||||
|
// Don't show 'Screen Lock' if 'Screen Lock' has been unlocked.
|
||||||
|
} else if (!self.appBecameInactiveDate) {
|
||||||
|
// Show 'Screen Lock' if app hasn't become inactive yet (just launched).
|
||||||
|
shouldHaveScreenLock = YES;
|
||||||
|
} else {
|
||||||
|
OWSAssert(self.appBecameInactiveDate);
|
||||||
|
|
||||||
|
NSTimeInterval screenLockInterval = fabs([self.appBecameInactiveDate timeIntervalSinceNow]);
|
||||||
|
NSTimeInterval screenLockTimeout = OWSScreenLock.sharedManager.screenLockTimeout;
|
||||||
|
OWSAssert(screenLockInterval >= 0);
|
||||||
|
OWSAssert(screenLockTimeout >= 0);
|
||||||
|
if (self.appBecameInactiveDate && screenLockInterval < screenLockTimeout) {
|
||||||
|
// Don't show 'Screen Lock' if 'Screen Lock' timeout hasn't elapsed.
|
||||||
|
shouldHaveScreenProtection = YES;
|
||||||
|
|
||||||
|
// Check again when screen lock timeout should elapse.
|
||||||
|
NSTimeInterval screenLockRemaining = screenLockTimeout - screenLockInterval + 0.2f;
|
||||||
|
OWSAssert(screenLockRemaining >= 0);
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(screenLockRemaining * NSEC_PER_SEC)),
|
||||||
|
dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Otherwise, show 'Screen Lock'.
|
||||||
|
shouldHaveScreenLock = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL shouldShowBlockWindow = shouldHaveScreenProtection || shouldHaveScreenLock;
|
||||||
|
self.screenBlockingWindow.hidden = !shouldShowBlockWindow;
|
||||||
|
|
||||||
|
if (shouldHaveScreenLock) {
|
||||||
|
if (!self.isShowingScreenLockUI) {
|
||||||
|
self.isShowingScreenLockUI = YES;
|
||||||
|
|
||||||
|
[OWSScreenLock.sharedManager tryToUnlockScreenLockWithSuccess:^{
|
||||||
|
DDLogInfo(@"%@ unlock screen lock succeeded.", self.logTag);
|
||||||
|
self.isShowingScreenLockUI = NO;
|
||||||
|
self.hasUnlockedScreenLock = YES;
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}
|
||||||
|
failure:^(NSError *error) {
|
||||||
|
DDLogInfo(@"%@ unlock screen lock failed.", self.logTag);
|
||||||
|
self.isShowingScreenLockUI = NO;
|
||||||
|
|
||||||
|
[self showScreenLockFailureAlertWithMessage:error.localizedDescription];
|
||||||
|
}
|
||||||
|
cancel:^{
|
||||||
|
DDLogInfo(@"%@ unlock screen lock cancelled.", self.logTag);
|
||||||
|
self.isShowingScreenLockUI = NO;
|
||||||
|
|
||||||
|
[self showScreenLockFailureAlertWithMessage:
|
||||||
|
NSLocalizedString(@"SCREEN_LOCK_UNLOCK_CANCELLED",
|
||||||
|
@"Message for alert indicating that screen lock unlock was cancelled.")];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)showScreenLockFailureAlertWithMessage:(NSString *)message
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
[OWSAlerts showAlertWithTitle:NSLocalizedString(@"SCREEN_LOCK_UNLOCK_FAILED",
|
||||||
|
@"Title for alert indicating that screen lock could not be unlocked.")
|
||||||
|
message:message
|
||||||
|
buttonTitle:nil
|
||||||
|
buttonAction:^(UIAlertAction *action) {
|
||||||
|
// After the alert, re-show the unlock UI.
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'Screen Blocking' window obscures the app screen:
|
||||||
|
//
|
||||||
|
// * In the app switcher.
|
||||||
|
// * During 'Screen Lock' unlock process.
|
||||||
|
- (void)prepareScreenProtectionWithRootWindow:(UIWindow *)rootWindow
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
OWSAssert(rootWindow);
|
||||||
|
|
||||||
|
UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds];
|
||||||
|
window.hidden = YES;
|
||||||
|
window.opaque = YES;
|
||||||
|
window.userInteractionEnabled = NO;
|
||||||
|
window.windowLevel = CGFLOAT_MAX;
|
||||||
|
window.backgroundColor = UIColor.ows_materialBlueColor;
|
||||||
|
window.rootViewController =
|
||||||
|
[[UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil] instantiateInitialViewController];
|
||||||
|
|
||||||
|
self.screenBlockingWindow = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Events
|
||||||
|
|
||||||
|
- (void)screenLockDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)registrationStateDidChange
|
||||||
|
{
|
||||||
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
DDLogInfo(@"registrationStateDidChange");
|
||||||
|
|
||||||
|
[self ensureScreenProtection];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
self.appIsInactive = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
self.appIsInactive = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
|
@ -29,4 +29,5 @@ extern NSString *const kNSNotificationName_BlockedPhoneNumbersDidChange;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
Loading…
Reference in a new issue