Merge pull request #377 from mpretty-cyro/feature/refactor-screen-lock

Cleaned up some of the Screen Lock behaviours
pull/1061/head
Morgan Pretty 2 months ago committed by GitHub
commit 43952c8386
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -312,7 +312,6 @@
C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF240255B6D67007E1867 /* UIView+OWS.swift */; }; C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF240255B6D67007E1867 /* UIView+OWS.swift */; };
C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF241255B6D67007E1867 /* Collection+OWS.swift */; }; C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF241255B6D67007E1867 /* Collection+OWS.swift */; };
C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */; }; C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */; };
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */; };
C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF304255B6DBE007E1867 /* ImageCache.swift */; }; C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF304255B6DBE007E1867 /* ImageCache.swift */; };
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */; }; C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */; };
C38EF372255B6DCC007E1867 /* MediaMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF358255B6DCC007E1867 /* MediaMessageView.swift */; }; C38EF372255B6DCC007E1867 /* MediaMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF358255B6DCC007E1867 /* MediaMessageView.swift */; };
@ -685,8 +684,6 @@
FD4C53AF2CC1D62E003B10F4 /* _021_ReworkRecipientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4C53AE2CC1D61E003B10F4 /* _021_ReworkRecipientState.swift */; }; FD4C53AF2CC1D62E003B10F4 /* _021_ReworkRecipientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4C53AE2CC1D61E003B10F4 /* _021_ReworkRecipientState.swift */; };
FD52090328B4680F006098F6 /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090228B4680F006098F6 /* RadioButton.swift */; }; FD52090328B4680F006098F6 /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090228B4680F006098F6 /* RadioButton.swift */; };
FD52090528B4915F006098F6 /* PrivacySettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090428B4915F006098F6 /* PrivacySettingsViewModel.swift */; }; FD52090528B4915F006098F6 /* PrivacySettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090428B4915F006098F6 /* PrivacySettingsViewModel.swift */; };
FD52090928B59411006098F6 /* ScreenLockUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090828B59411006098F6 /* ScreenLockUI.swift */; };
FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */; };
FD559DF52A7368CB00C7C62A /* DispatchQueue+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */; }; FD559DF52A7368CB00C7C62A /* DispatchQueue+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */; };
FD5931A72A8DA5DA0040147D /* SQLInterpolation+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */; }; FD5931A72A8DA5DA0040147D /* SQLInterpolation+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */; };
FD5931AB2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */; }; FD5931AB2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */; };
@ -708,6 +705,9 @@
FD65318B2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; }; FD65318B2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
FD65318C2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; }; FD65318C2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
FD65318D2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; }; FD65318D2AA025C500DFEEAA /* TestDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6531892AA025C500DFEEAA /* TestDependencies.swift */; };
FD6673FD2D77F54600041530 /* ScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6673FC2D77F54400041530 /* ScreenLockViewController.swift */; };
FD6673FF2D77F9C100041530 /* ScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6673FE2D77F9BE00041530 /* ScreenLock.swift */; };
FD6674002D77F9FD00041530 /* ScreenLockWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090828B59411006098F6 /* ScreenLockWindow.swift */; };
FD6673F62D7021E700041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F52D7021E700041530 /* SessionUtil */; }; FD6673F62D7021E700041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F52D7021E700041530 /* SessionUtil */; };
FD6673F82D7021F200041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F72D7021F200041530 /* SessionUtil */; }; FD6673F82D7021F200041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F72D7021F200041530 /* SessionUtil */; };
FD6673FA2D7021F800041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F92D7021F800041530 /* SessionUtil */; }; FD6673FA2D7021F800041530 /* SessionUtil in Frameworks */ = {isa = PBXBuildFile; productRef = FD6673F92D7021F800041530 /* SessionUtil */; };
@ -1579,7 +1579,6 @@
C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SessionUIKit/Components/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; }; C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PlaceholderIcon.swift; path = SessionUIKit/Components/PlaceholderIcon.swift; sourceTree = SOURCE_ROOT; };
C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SessionUIKit/Components/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; }; C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProfilePictureView.swift; path = SessionUIKit/Components/ProfilePictureView.swift; sourceTree = SOURCE_ROOT; };
C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; }; C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIViewController+Utilities.swift"; path = "SignalUtilitiesKit/Utilities/UIViewController+Utilities.swift"; sourceTree = SOURCE_ROOT; };
C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ScreenLock.swift; path = "SignalUtilitiesKit/Screen Lock/ScreenLock.swift"; sourceTree = SOURCE_ROOT; };
C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SessionMessagingKit/Utilities/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; }; C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SessionMessagingKit/Utilities/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; };
C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SessionUtilitiesKit/General/Weak.swift; sourceTree = SOURCE_ROOT; }; C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SessionUtilitiesKit/General/Weak.swift; sourceTree = SOURCE_ROOT; };
C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SessionMessagingKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; }; C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SessionMessagingKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; };
@ -1899,8 +1898,7 @@
FD52090228B4680F006098F6 /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; }; FD52090228B4680F006098F6 /* RadioButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButton.swift; sourceTree = "<group>"; };
FD52090428B4915F006098F6 /* PrivacySettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsViewModel.swift; sourceTree = "<group>"; }; FD52090428B4915F006098F6 /* PrivacySettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsViewModel.swift; sourceTree = "<group>"; };
FD52090628B49738006098F6 /* ConfirmationModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationModal.swift; sourceTree = "<group>"; }; FD52090628B49738006098F6 /* ConfirmationModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationModal.swift; sourceTree = "<group>"; };
FD52090828B59411006098F6 /* ScreenLockUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockUI.swift; sourceTree = "<group>"; }; FD52090828B59411006098F6 /* ScreenLockWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockWindow.swift; sourceTree = "<group>"; };
FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockViewController.swift; sourceTree = "<group>"; };
FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Utilities.swift"; sourceTree = "<group>"; }; FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Utilities.swift"; sourceTree = "<group>"; };
FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SQLInterpolation+Utilities.swift"; sourceTree = "<group>"; }; FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SQLInterpolation+Utilities.swift"; sourceTree = "<group>"; };
FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScopeAdapter+Utilities.swift"; sourceTree = "<group>"; }; FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScopeAdapter+Utilities.swift"; sourceTree = "<group>"; };
@ -1918,6 +1916,8 @@
FD61FCF82D308CC5005752DE /* GroupMemberSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberSpec.swift; sourceTree = "<group>"; }; FD61FCF82D308CC5005752DE /* GroupMemberSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberSpec.swift; sourceTree = "<group>"; };
FD61FCFA2D34A5DE005752DE /* _007_SplitSnodeReceivedMessageInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _007_SplitSnodeReceivedMessageInfo.swift; sourceTree = "<group>"; }; FD61FCFA2D34A5DE005752DE /* _007_SplitSnodeReceivedMessageInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _007_SplitSnodeReceivedMessageInfo.swift; sourceTree = "<group>"; };
FD6531892AA025C500DFEEAA /* TestDependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDependencies.swift; sourceTree = "<group>"; }; FD6531892AA025C500DFEEAA /* TestDependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestDependencies.swift; sourceTree = "<group>"; };
FD6673FC2D77F54400041530 /* ScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockViewController.swift; sourceTree = "<group>"; };
FD6673FE2D77F9BE00041530 /* ScreenLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLock.swift; sourceTree = "<group>"; };
FD66CB272BF3449B00268FAB /* SessionSnodeKit.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SessionSnodeKit.xctestplan; sourceTree = "<group>"; }; FD66CB272BF3449B00268FAB /* SessionSnodeKit.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SessionSnodeKit.xctestplan; sourceTree = "<group>"; };
FD66CB2B2BF344C600268FAB /* SessionMessageKit.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = SessionMessageKit.xctestplan; sourceTree = "<group>"; }; FD66CB2B2BF344C600268FAB /* SessionMessageKit.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = SessionMessageKit.xctestplan; sourceTree = "<group>"; };
FD6A38F02C2A66B100762359 /* KeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStorage.swift; sourceTree = "<group>"; }; FD6A38F02C2A66B100762359 /* KeychainStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStorage.swift; sourceTree = "<group>"; };
@ -2818,6 +2818,7 @@
C35D0DB425AE5F1200B6BF49 /* UIEdgeInsets.swift */, C35D0DB425AE5F1200B6BF49 /* UIEdgeInsets.swift */,
FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */, FD848B9228420164000E298B /* UnicodeScalar+Utilities.swift */,
C38EF2EF255B6DBB007E1867 /* Weak.swift */, C38EF2EF255B6DBB007E1867 /* Weak.swift */,
FD6673FE2D77F9BE00041530 /* ScreenLock.swift */,
FD5D201D27B0D87C00FEA984 /* SessionId.swift */, FD5D201D27B0D87C00FEA984 /* SessionId.swift */,
7B7CB191271508AD0079FF93 /* CallRingTonePlayer.swift */, 7B7CB191271508AD0079FF93 /* CallRingTonePlayer.swift */,
7B0EFDED274F598600FFAAE7 /* TimestampUtils.swift */, 7B0EFDED274F598600FFAAE7 /* TimestampUtils.swift */,
@ -2856,7 +2857,7 @@
FD71162128D983ED00B47552 /* QRCodeScanningViewController.swift */, FD71162128D983ED00B47552 /* QRCodeScanningViewController.swift */,
9422569E2C23F8FE00C0FDBF /* ScanQRCodeScreen.swift */, 9422569E2C23F8FE00C0FDBF /* ScanQRCodeScreen.swift */,
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */, B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */,
FD52090828B59411006098F6 /* ScreenLockUI.swift */, FD52090828B59411006098F6 /* ScreenLockWindow.swift */,
FD37EA0828AA2D27003AE748 /* SessionTableViewModel.swift */, FD37EA0828AA2D27003AE748 /* SessionTableViewModel.swift */,
FD10AF0B2AF32B9A007709E5 /* SessionListViewModel.swift */, FD10AF0B2AF32B9A007709E5 /* SessionListViewModel.swift */,
FD37EA0628AA2CCA003AE748 /* SessionTableViewController.swift */, FD37EA0628AA2CCA003AE748 /* SessionTableViewController.swift */,
@ -3114,6 +3115,7 @@
FD52090628B49738006098F6 /* ConfirmationModal.swift */, FD52090628B49738006098F6 /* ConfirmationModal.swift */,
C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */, C38EF2A3255B6D93007E1867 /* PlaceholderIcon.swift */,
C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */, C38EF2A4255B6D93007E1867 /* ProfilePictureView.swift */,
FD6673FC2D77F54400041530 /* ScreenLockViewController.swift */,
FD0150572CA27DEE005B08A1 /* ScrollableLabel.swift */, FD0150572CA27DEE005B08A1 /* ScrollableLabel.swift */,
FD71165A28E6DDBC00B47552 /* StyledNavigationController.swift */, FD71165A28E6DDBC00B47552 /* StyledNavigationController.swift */,
FD0B77AF29B69A65009169BA /* TopBannerController.swift */, FD0B77AF29B69A65009169BA /* TopBannerController.swift */,
@ -3128,7 +3130,6 @@
children = ( children = (
C33FD9B7255A54A300E217F9 /* Meta */, C33FD9B7255A54A300E217F9 /* Meta */,
C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */, C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */,
C36096EE25AD21BC008B62B2 /* Screen Lock */,
C3851CD225624B060061EEB0 /* Shared Views */, C3851CD225624B060061EEB0 /* Shared Views */,
C360970125AD22D3008B62B2 /* Shared View Controllers */, C360970125AD22D3008B62B2 /* Shared View Controllers */,
C3CA3B11255CF17200F4C6D4 /* Utilities */, C3CA3B11255CF17200F4C6D4 /* Utilities */,
@ -3312,15 +3313,6 @@
path = "Media Viewing & Editing"; path = "Media Viewing & Editing";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
C36096EE25AD21BC008B62B2 /* Screen Lock */ = {
isa = PBXGroup;
children = (
C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */,
FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */,
);
path = "Screen Lock";
sourceTree = "<group>";
};
C360970125AD22D3008B62B2 /* Shared View Controllers */ = { C360970125AD22D3008B62B2 /* Shared View Controllers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -5812,6 +5804,7 @@
FD37E9F628A5F106003AE748 /* Configuration.swift in Sources */, FD37E9F628A5F106003AE748 /* Configuration.swift in Sources */,
FD2272E62C351378004D8A6C /* SUIKImageFormat.swift in Sources */, FD2272E62C351378004D8A6C /* SUIKImageFormat.swift in Sources */,
7BF8D1FB2A70AF57005F1D6E /* SwiftUI+Theme.swift in Sources */, 7BF8D1FB2A70AF57005F1D6E /* SwiftUI+Theme.swift in Sources */,
FD6673FD2D77F54600041530 /* ScreenLockViewController.swift in Sources */,
FDE754BE2C9BA16C002A2623 /* UIButtonConfiguration+Utilities.swift in Sources */, FDE754BE2C9BA16C002A2623 /* UIButtonConfiguration+Utilities.swift in Sources */,
FDBB25E72988BBBE00F1508E /* UIContextualAction+Theming.swift in Sources */, FDBB25E72988BBBE00F1508E /* UIContextualAction+Theming.swift in Sources */,
C331FFE02558FB0000070591 /* SearchBar.swift in Sources */, C331FFE02558FB0000070591 /* SearchBar.swift in Sources */,
@ -5847,7 +5840,6 @@
C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */,
C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */,
C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */,
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */,
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */,
C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */,
C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */, C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */,
@ -5872,7 +5864,6 @@
C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */, C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */,
C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */, C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */,
C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */,
FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */,
C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */,
C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */, C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */,
C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */,
@ -6028,6 +6019,7 @@
FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */, FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */,
FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */, FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */,
FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */, FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */,
FD6673FF2D77F9C100041530 /* ScreenLock.swift in Sources */,
FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */, FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */,
FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */, FD848B9328420164000E298B /* UnicodeScalar+Utilities.swift in Sources */,
FDE754CE2C9BAF37002A2623 /* ImageFormat.swift in Sources */, FDE754CE2C9BAF37002A2623 /* ImageFormat.swift in Sources */,
@ -6340,7 +6332,6 @@
files = ( files = (
FD97B2422A3FEBF30027DD57 /* UnreadMarkerCell.swift in Sources */, FD97B2422A3FEBF30027DD57 /* UnreadMarkerCell.swift in Sources */,
FD0606C32BCE13ED00C3816E /* MessageRequestFooterView.swift in Sources */, FD0606C32BCE13ED00C3816E /* MessageRequestFooterView.swift in Sources */,
FD52090928B59411006098F6 /* ScreenLockUI.swift in Sources */,
7B2561C429874851005C086C /* SessionCarouselView+Info.swift in Sources */, 7B2561C429874851005C086C /* SessionCarouselView+Info.swift in Sources */,
FDF2220B2818F38D000A4995 /* SessionApp.swift in Sources */, FDF2220B2818F38D000A4995 /* SessionApp.swift in Sources */,
FD7115EB28C5D78E00B47552 /* ThreadSettingsViewModel.swift in Sources */, FD7115EB28C5D78E00B47552 /* ThreadSettingsViewModel.swift in Sources */,
@ -6451,6 +6442,7 @@
FDE754B72C9B96BB002A2623 /* WebRTCSession+MessageHandling.swift in Sources */, FDE754B72C9B96BB002A2623 /* WebRTCSession+MessageHandling.swift in Sources */,
FD37EA1928AC5CCA003AE748 /* NotificationSoundViewModel.swift in Sources */, FD37EA1928AC5CCA003AE748 /* NotificationSoundViewModel.swift in Sources */,
7BAFA75A2AAEA281001DA43E /* LinkPreviewView_SwiftUI.swift in Sources */, 7BAFA75A2AAEA281001DA43E /* LinkPreviewView_SwiftUI.swift in Sources */,
FD6674002D77F9FD00041530 /* ScreenLockWindow.swift in Sources */,
FD71163E28E2C82900B47552 /* SessionCell.swift in Sources */, FD71163E28E2C82900B47552 /* SessionCell.swift in Sources */,
9422569C2C23F8F000C0FDBF /* QRCodeScreen.swift in Sources */, 9422569C2C23F8F000C0FDBF /* QRCodeScreen.swift in Sources */,
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */, 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */,

@ -97,13 +97,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
// Note: Intentionally dispatching sync as we want to wait for these to complete before // Note: Intentionally dispatching sync as we want to wait for these to complete before
// continuing // continuing
DispatchQueue.main.sync { DispatchQueue.main.sync {
ScreenLockUI.shared.setupWithRootWindow(rootWindow: mainWindow, using: dependencies) dependencies[singleton: .screenLock].setupWithRootWindow(rootWindow: mainWindow)
OWSWindowManager.shared().setup( OWSWindowManager.shared().setup(
withRootWindow: mainWindow, withRootWindow: mainWindow,
screenBlockingWindow: ScreenLockUI.shared.screenBlockingWindow, screenBlockingWindow: dependencies[singleton: .screenLock].window,
backgroundWindowLevel: .background backgroundWindowLevel: .background
) )
ScreenLockUI.shared.startObserving()
} }
}, },
migrationProgressChanged: { [weak self] progress, minEstimatedTotalTime in migrationProgressChanged: { [weak self] progress, minEstimatedTotalTime in

@ -1,122 +1,79 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit import UIKit
import LocalAuthentication
import SessionUIKit import SessionUIKit
import SessionMessagingKit import SessionMessagingKit
import SessionUtilitiesKit import SessionUtilitiesKit
import SignalUtilitiesKit
class ScreenLockUI { // MARK: - Singleton
public static let shared: ScreenLockUI = ScreenLockUI()
private var dependencies: Dependencies?
public lazy var screenBlockingWindow: UIWindow = {
let result: UIWindow = UIWindow()
result.isHidden = false
result.windowLevel = .background
result.isOpaque = true
result.themeBackgroundColorForced = .theme(.classicDark, color: .backgroundPrimary)
result.rootViewController = self.screenBlockingViewController
return result
}()
private lazy var screenBlockingViewController: ScreenLockViewController = {
let result: ScreenLockViewController = ScreenLockViewController { [weak self] in
guard self?.appIsInactiveOrBackground == false else {
// This button can be pressed while the app is inactive
// for a brief window while the iOS auth UI is dismissing.
return
}
Log.info("unlockButtonWasTapped") public extension Singleton {
static let screenLock: SingletonConfig<ScreenLockWindow> = Dependencies.create(
identifier: "screenLock",
createInstance: { dependencies in ScreenLockWindow(using: dependencies) }
)
}
self?.didLastUnlockAttemptFail = false /// Obscures the app screen:
self?.ensureUI() ///
} /// * In the app switcher.
/// * During 'Screen Lock' unlock process.
return result public class ScreenLockWindow {
}() private let dependencies: Dependencies
/// Unlike UIApplication.applicationState, this state reflects the notifications, i.e. "did become active", "will resign active", /// Indicates whether or not the user is currently locked out of the app. Should only be set if `db[.isScreenLockEnabled]`.
/// "will enter foreground", "did enter background".
///
/// 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 /// * The user is locked out by default on app launch.
/// app switcher. /// * The user is also locked out if the app is sent to the background
private var appIsInactiveOrBackground: Bool = false { @ThreadSafe private var isScreenLockLocked: Bool = false
didSet {
if self.appIsInactiveOrBackground {
if !self.isShowingScreenLockUI {
self.didLastUnlockAttemptFail = false
self.tryToActivateScreenLockBasedOnCountdown()
}
}
else if !self.didUnlockJustSucceed {
self.tryToActivateScreenLockBasedOnCountdown()
}
self.didUnlockJustSucceed = false
self.ensureUI()
}
}
private var appIsInBackground: Bool = false {
didSet {
self.didUnlockJustSucceed = false
self.tryToActivateScreenLockBasedOnCountdown()
self.ensureUI()
}
}
private var isShowingScreenLockUI: Bool = false private var isShowingScreenLockUI: Bool = false
private var didUnlockJustSucceed: Bool = false private var didUnlockJustSucceed: Bool = false
private var didLastUnlockAttemptFail: Bool = false private var didLastUnlockAttemptFail: Bool = false
/// We want to remain in "screen lock" mode while "local auth" UI is dismissing. So we lazily clear isShowingScreenLockUI /// We want to remain in "screen lock" mode while "local auth" UI is dismissing. So we lazily clear isShowingScreenLockUI
/// using this property. /// using this property.
private var shouldClearAuthUIWhenActive: Bool = false private var shouldClearAuthUIWhenActive: Bool = false
/// Indicates whether or not the user is currently locked out of the app. Should only be set if db[.isScreenLockEnabled].
///
/// * The user is locked out by default on app launch.
/// * The user is also locked out if the app is sent to the background
@ThreadSafe private var isScreenLockLocked: Bool = false
// Determines what the state of the app should be. // MARK: - UI
private var desiredUIState: ScreenLockViewController.State {
if isScreenLockLocked { public lazy var window: UIWindow = {
if appIsInactiveOrBackground { let result: UIWindow = UIWindow()
Log.verbose("desiredUIState: screen protection 1.") result.isHidden = false
return .protection result.windowLevel = .background
} result.isOpaque = true
result.themeBackgroundColorForced = .theme(.classicDark, color: .backgroundPrimary)
Log.verbose("desiredUIState: screen lock 2.") result.rootViewController = self.viewController
return (isShowingScreenLockUI ? .protection : .lock)
}
if !self.appIsInactiveOrBackground {
// App is inactive or background.
Log.verbose("desiredUIState: none 3.");
return .none;
}
if SessionEnvironment.shared?.isRequestingPermission == true { return result
return .none; }()
private lazy var viewController: ScreenLockViewController = ScreenLockViewController { [weak self, dependencies] in
guard dependencies[singleton: .appContext].isAppForegroundAndActive else {
// This button can be pressed while the app is inactive
// for a brief window while the iOS auth UI is dismissing.
return
} }
Log.verbose("desiredUIState: screen protection 4.") Log.info(.screenLock, "unlockButtonWasTapped")
return .protection;
self?.didLastUnlockAttemptFail = false
self?.ensureUI()
} }
// MARK: - Lifecycle // MARK: - Lifecycle
init(using dependencies: Dependencies) {
self.dependencies = dependencies
}
deinit { deinit {
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
} }
// MARK: - Observations
private func observeNotifications() { private func observeNotifications() {
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
self, self,
@ -150,56 +107,72 @@ class ScreenLockUI {
) )
} }
public func setupWithRootWindow(rootWindow: UIWindow, using dependencies: Dependencies) { public func setupWithRootWindow(rootWindow: UIWindow) {
self.dependencies = dependencies self.window.frame = rootWindow.bounds
self.screenBlockingWindow.frame = rootWindow.bounds
}
public func startObserving() {
self.appIsInactiveOrBackground = (UIApplication.shared.applicationState != .active)
self.observeNotifications() self.observeNotifications()
// Hide the screen blocking window until "app is ready" to /// Hide the screen blocking window until "app is ready" to avoid blocking the loading view
// avoid blocking the loading view.
updateScreenBlockingWindow(state: .none, animated: false) updateScreenBlockingWindow(state: .none, animated: false)
// Initialize the screen lock state. /// Initialize the screen lock state.
// ///
// It's not safe to access OWSScreenLock.isScreenLockEnabled /// It's not safe to access `isScreenLockEnabled` in `storage` until the app is ready
// until the app is ready. dependencies[singleton: .appReadiness].runNowOrWhenAppWillBecomeReady { [weak self, dependencies] in
dependencies?[singleton: .appReadiness].runNowOrWhenAppWillBecomeReady { [weak self, dependencies] in self?.isScreenLockLocked = (dependencies[singleton: .storage, key: .isScreenLockEnabled] == true)
DispatchQueue.global(qos: .background).async {
self?.isScreenLockLocked = (dependencies?[singleton: .storage, key: .isScreenLockEnabled] == true) switch Thread.isMainThread {
case true: self?.ensureUI()
DispatchQueue.main.async { case false: DispatchQueue.main.async { self?.ensureUI() }
self?.ensureUI()
}
} }
} }
} }
// MARK: - Functions // MARK: - Functions
private func determineDesiredUIState() -> ScreenLockViewController.State {
if isScreenLockLocked {
if dependencies[singleton: .appContext].isNotInForeground {
Log.verbose(.screenLock, "App not in foreground, desiredUIState is: protection.")
return .protection
}
Log.verbose(.screenLock, "App in foreground and locked, desiredUIState is: \(isShowingScreenLockUI ? "protection" : "lock").")
return (isShowingScreenLockUI ? .protection : .lock)
}
if dependencies[singleton: .appContext].isAppForegroundAndActive {
// App is inactive or background.
Log.verbose(.screenLock, "App in foreground and not locked, desiredUIState is: none.")
return .none;
}
if SessionEnvironment.shared?.isRequestingPermission == true {
Log.verbose(.screenLock, "App requesting permissions and not locked, desiredUIState is: none.")
return .none;
}
Log.verbose(.screenLock, "desiredUIState is: protection.")
return .protection;
}
private func tryToActivateScreenLockBasedOnCountdown() { private func tryToActivateScreenLockBasedOnCountdown() {
guard dependencies?[singleton: .appReadiness].isAppReady == true else { guard dependencies[singleton: .appReadiness].isAppReady else {
// It's not safe to access OWSScreenLock.isScreenLockEnabled /// It's not safe to access `isScreenLockEnabled` in `storage` until the app is ready
// until the app is ready. ///
// /// We don't need to try to lock the screen lock;
// We don't need to try to lock the screen lock; /// It will be initialized by `setupWithRootWindow`
// It will be initialized by `setupWithRootWindow`. Log.verbose(.screenLock, "tryToActivateScreenLockUponBecomingActive NO 0")
Log.verbose("tryToActivateScreenLockUponBecomingActive NO 0")
return return
} }
guard dependencies?[singleton: .storage, key: .isScreenLockEnabled] == true else { guard dependencies[singleton: .storage, key: .isScreenLockEnabled] else {
// Screen lock is not enabled. /// Screen lock is not enabled.
Log.verbose("tryToActivateScreenLockUponBecomingActive NO 1") Log.verbose(.screenLock, "tryToActivateScreenLockUponBecomingActive NO 1")
return; return
} }
guard !isScreenLockLocked else { guard !isScreenLockLocked else {
// Screen lock is already activated. /// Screen lock is already activated.
Log.verbose("tryToActivateScreenLockUponBecomingActive NO 2") Log.verbose(.screenLock, "tryToActivateScreenLockUponBecomingActive NO 2")
return; return
} }
self.isScreenLockLocked = true self.isScreenLockLocked = true
@ -210,49 +183,52 @@ class ScreenLockUI {
/// * The blocking window has the correct state. /// * The blocking window has the correct state.
/// * That we show the "iOS auth UI to unlock" if necessary. /// * That we show the "iOS auth UI to unlock" if necessary.
private func ensureUI() { private func ensureUI() {
guard dependencies?[singleton: .appReadiness].isAppReady == true else { guard dependencies[singleton: .appReadiness].isAppReady else {
dependencies?[singleton: .appReadiness].runNowOrWhenAppWillBecomeReady { [weak self] in dependencies[singleton: .appReadiness].runNowOrWhenAppWillBecomeReady { [weak self] in
self?.ensureUI() self?.ensureUI()
} }
return return
} }
let desiredUIState: ScreenLockViewController.State = self.desiredUIState let desiredUIState: ScreenLockViewController.State = determineDesiredUIState()
Log.verbose("ensureUI: \(desiredUIState)") Log.verbose(.screenLock, "ensureUI: \(desiredUIState)")
// Show the "iOS auth UI to unlock" if necessary. /// Show the "iOS auth UI to unlock" if necessary.
if desiredUIState == .lock && !didLastUnlockAttemptFail { if desiredUIState == .lock && !didLastUnlockAttemptFail {
tryToPresentAuthUIToUnlockScreenLock() tryToPresentAuthUIToUnlockScreenLock()
} }
// Note: We want to regenerate the 'desiredUIState' as if we are about to show the /// Note: We want to regenerate the `desiredUIState` as if we are about to show the "unlock screen" UI then we
// 'unlock screen' UI then we shouldn't show the "unlock" button /// shouldn't show the "unlock" button
updateScreenBlockingWindow(state: self.desiredUIState, animated: true) updateScreenBlockingWindow(state: determineDesiredUIState(), animated: true)
} }
private func tryToPresentAuthUIToUnlockScreenLock() { private func tryToPresentAuthUIToUnlockScreenLock() {
guard !isShowingScreenLockUI else { return } // We're already showing the auth UI; abort /// If we're already showing the auth UI; or the app isn't active then don't do anything
guard !appIsInactiveOrBackground else { return } // Never show the auth UI unless active guard
!isShowingScreenLockUI,
dependencies[singleton: .appContext].isAppForegroundAndActive
else { return }
Log.info("try to unlock screen lock") Log.info(.screenLock, "Try to unlock screen lock")
isShowingScreenLockUI = true isShowingScreenLockUI = true
ScreenLock.shared.tryToUnlockScreenLock( ScreenLock.tryToUnlockScreenLock(
success: { [weak self] in success: { [weak self] in
Log.info("unlock screen lock succeeded.") Log.info(.screenLock, "Unlock screen lock succeeded")
self?.isShowingScreenLockUI = false self?.isShowingScreenLockUI = false
self?.isScreenLockLocked = false self?.isScreenLockLocked = false
self?.didUnlockJustSucceed = true self?.didUnlockJustSucceed = true
self?.ensureUI() self?.ensureUI()
}, },
failure: { [weak self] error in failure: { [weak self] error in
Log.info("unlock screen lock failed.") Log.info(.screenLock, "Unlock screen lock failed")
self?.clearAuthUIWhenActive() self?.clearAuthUIWhenActive()
self?.didLastUnlockAttemptFail = true self?.didLastUnlockAttemptFail = true
self?.showScreenLockFailureAlert(message: "\(error)") self?.showScreenLockFailureAlert(message: "\(error)")
}, },
unexpectedFailure: { [weak self] error in unexpectedFailure: { [weak self] error in
Log.info("unlock screen lock unexpectedly failed.") Log.warn(.screenLock, "Unlock screen lock unexpectedly failed")
// Local Authentication isn't working properly. // Local Authentication isn't working properly.
// This isn't covered by the docs or the forums but in practice // This isn't covered by the docs or the forums but in practice
@ -262,7 +238,7 @@ class ScreenLockUI {
} }
}, },
cancel: { [weak self] in cancel: { [weak self] in
Log.info("unlock screen lock cancelled.") Log.info(.screenLock, "Unlock screen lock cancelled")
self?.clearAuthUIWhenActive() self?.clearAuthUIWhenActive()
self?.didLastUnlockAttemptFail = true self?.didLastUnlockAttemptFail = true
@ -277,7 +253,7 @@ class ScreenLockUI {
private func showScreenLockFailureAlert(message: String) { private func showScreenLockFailureAlert(message: String) {
let modal: ConfirmationModal = ConfirmationModal( let modal: ConfirmationModal = ConfirmationModal(
targetView: screenBlockingWindow.rootViewController?.view, targetView: viewController.view,
info: ConfirmationModal.Info( info: ConfirmationModal.Info(
title: "authenticateFailed".localized(), title: "authenticateFailed".localized(),
body: .text(message), body: .text(message),
@ -286,36 +262,7 @@ class ScreenLockUI {
afterClosed: { [weak self] in self?.ensureUI() } // After the alert, update the UI afterClosed: { [weak self] in self?.ensureUI() } // After the alert, update the UI
) )
) )
screenBlockingWindow.rootViewController?.present(modal, animated: true) viewController.present(modal, animated: true)
}
/// 'Screen Blocking' window obscures the app screen:
///
/// * In the app switcher.
/// * During 'Screen Lock' unlock process.
private func createScreenBlockingWindow(rootWindow: UIWindow) {
let window: UIWindow = UIWindow(frame: rootWindow.bounds)
window.isHidden = false
window.windowLevel = .background
window.isOpaque = true
window.themeBackgroundColorForced = .theme(.classicDark, color: .backgroundPrimary)
let viewController: ScreenLockViewController = ScreenLockViewController { [weak self] in
guard self?.appIsInactiveOrBackground == false else {
// This button can be pressed while the app is inactive
// for a brief window while the iOS auth UI is dismissing.
return
}
Log.info("unlockButtonWasTapped")
self?.didLastUnlockAttemptFail = false
self?.ensureUI()
}
window.rootViewController = viewController
self.screenBlockingWindow = window
self.screenBlockingViewController = viewController
} }
/// The "screen blocking" window has three possible states: /// The "screen blocking" window has three possible states:
@ -327,7 +274,7 @@ class ScreenLockUI {
let shouldShowBlockWindow: Bool = (state != .none) let shouldShowBlockWindow: Bool = (state != .none)
OWSWindowManager.shared().isScreenBlockActive = shouldShowBlockWindow OWSWindowManager.shared().isScreenBlockActive = shouldShowBlockWindow
self.screenBlockingViewController.updateUI(state: state, animated: animated) self.viewController.updateUI(state: state, animated: animated)
} }
// MARK: - Events // MARK: - Events
@ -335,7 +282,7 @@ class ScreenLockUI {
private func clearAuthUIWhenActive() { private func 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.appIsInactiveOrBackground { if !dependencies[singleton: .appContext].isAppForegroundAndActive {
self.shouldClearAuthUIWhenActive = true self.shouldClearAuthUIWhenActive = true
} }
else { else {
@ -345,42 +292,61 @@ class ScreenLockUI {
} }
@objc private func applicationDidBecomeActive() { @objc private func applicationDidBecomeActive() {
if self.shouldClearAuthUIWhenActive { if shouldClearAuthUIWhenActive {
self.shouldClearAuthUIWhenActive = false shouldClearAuthUIWhenActive = false
self.isShowingScreenLockUI = false isShowingScreenLockUI = false
}
if !didUnlockJustSucceed {
tryToActivateScreenLockBasedOnCountdown()
} }
self.appIsInactiveOrBackground = false didUnlockJustSucceed = false
ensureUI()
} }
/// When the OS shows the TouchID/FaceID/Pin UI the application will resign active (and we don't want to re-authenticate if we are
/// already locked)
///
/// Secondly, we need to show the screen protection _before_ we become inactive in order for it to be reflected in the app switcher
@objc private func applicationWillResignActive() { @objc private func applicationWillResignActive() {
self.appIsInactiveOrBackground = true if !isShowingScreenLockUI {
didLastUnlockAttemptFail = false
tryToActivateScreenLockBasedOnCountdown()
}
didUnlockJustSucceed = false
ensureUI()
} }
@objc private func applicationWillEnterForeground() { @objc private func applicationWillEnterForeground() {
self.appIsInBackground = false didUnlockJustSucceed = false
tryToActivateScreenLockBasedOnCountdown()
ensureUI()
} }
@objc private func applicationDidEnterBackground() { @objc private func applicationDidEnterBackground() {
self.appIsInBackground = true didUnlockJustSucceed = false
tryToActivateScreenLockBasedOnCountdown()
ensureUI()
} }
/// Whenever the device date/time is edited by the user, trigger screen lock immediately if enabled. /// Whenever the device date/time is edited by the user, trigger screen lock immediately if enabled.
@objc private func clockDidChange() { @objc private func clockDidChange() {
Log.info("clock did change") Log.info(.screenLock, "clock did change")
guard dependencies?[singleton: .appReadiness].isAppReady == true else { guard dependencies[singleton: .appReadiness].isAppReady == true else {
// It's not safe to access OWSScreenLock.isScreenLockEnabled // It's not safe to access OWSScreenLock.isScreenLockEnabled
// until the app is ready. // until the app is ready.
// //
// We don't need to try to lock the screen lock; // We don't need to try to lock the screen lock;
// It will be initialized by `setupWithRootWindow`. // It will be initialized by `setupWithRootWindow`.
Log.verbose("clockDidChange 0") Log.verbose(.screenLock, "clockDidChange 0")
return; return;
} }
DispatchQueue.global(qos: .background).async { [dependencies] in DispatchQueue.global(qos: .background).async { [dependencies] in
self.isScreenLockLocked = (dependencies?[singleton: .storage, key: .isScreenLockEnabled] == true) self.isScreenLockLocked = (dependencies[singleton: .storage, key: .isScreenLockEnabled] == true)
DispatchQueue.main.async { DispatchQueue.main.async {
// NOTE: this notifications fires _before_ applicationDidBecomeActive, // NOTE: this notifications fires _before_ applicationDidBecomeActive,

@ -107,7 +107,7 @@ final class SAEScreenLockViewController: ScreenLockViewController {
isShowingAuthUI = true isShowingAuthUI = true
ScreenLock.shared.tryToUnlockScreenLock( ScreenLock.tryToUnlockScreenLock(
success: { [weak self] in success: { [weak self] in
Log.assertOnMainThread() Log.assertOnMainThread()
Log.info("unlock screen lock succeeded.") Log.info("unlock screen lock succeeded.")

@ -1,7 +1,6 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. // Copyright © 2025 Rangeproof Pty Ltd. All rights reserved.
import UIKit import UIKit
import SessionUIKit
open class ScreenLockViewController: UIViewController { open class ScreenLockViewController: UIViewController {
public enum State { public enum State {
@ -36,7 +35,7 @@ open class ScreenLockViewController: UIViewController {
public lazy var unlockButton: SessionButton = { public lazy var unlockButton: SessionButton = {
let result: SessionButton = SessionButton(style: .bordered, size: .medium) let result: SessionButton = SessionButton(style: .bordered, size: .medium)
result.translatesAutoresizingMaskIntoConstraints = false result.translatesAutoresizingMaskIntoConstraints = false
result.setTitle("lockAppUnlock".localized(), for: .normal) result.setTitle("lockAppUnlock".localizedSNUIKit(), for: .normal)
result.addTarget(self, action: #selector(showUnlockUI), for: .touchUpInside) result.addTarget(self, action: #selector(showUnlockUI), for: .touchUpInside)
result.isHidden = true result.isHidden = true

@ -1,10 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. // Copyright © 2025 Rangeproof Pty Ltd. All rights reserved.
import Foundation import UIKit
import GRDB
import LocalAuthentication import LocalAuthentication
import SessionMessagingKit
import SessionUtilitiesKit
// MARK: - Log.Category // MARK: - Log.Category
@ -14,7 +11,17 @@ public extension Log.Category {
// MARK: - ScreenLock // MARK: - ScreenLock
public class ScreenLock { public enum ScreenLock {
public static let screenLockTimeoutDefault = (15 * 60)
public static let screenLockTimeouts = [
1 * 60,
5 * 60,
15 * 60,
30 * 60,
1 * 60 * 60,
0
]
public enum ScreenLockError: Error { public enum ScreenLockError: Error {
case general(description: String) case general(description: String)
} }
@ -26,18 +33,6 @@ public class ScreenLock {
case unexpectedFailure(error: String) case unexpectedFailure(error: String)
} }
public let screenLockTimeoutDefault = (15 * 60)
public let screenLockTimeouts = [
1 * 60,
5 * 60,
15 * 60,
30 * 60,
1 * 60 * 60,
0
]
public static let shared: ScreenLock = ScreenLock()
// MARK: - Methods // MARK: - Methods
/// This method should only be called: /// This method should only be called:
@ -48,7 +43,7 @@ public class ScreenLock {
/// ///
/// * Asynchronously. /// * Asynchronously.
/// * On the main thread. /// * On the main thread.
public func tryToUnlockScreenLock( public static func tryToUnlockScreenLock(
success: @escaping (() -> Void), success: @escaping (() -> Void),
failure: @escaping ((Error) -> Void), failure: @escaping ((Error) -> Void),
unexpectedFailure: @escaping ((Error) -> Void), unexpectedFailure: @escaping ((Error) -> Void),
@ -57,8 +52,7 @@ public class ScreenLock {
Log.assertOnMainThread() Log.assertOnMainThread()
tryToVerifyLocalAuthentication( tryToVerifyLocalAuthentication(
// Description of how and why Signal iOS uses Touch ID/Face ID/Phone Passcode to // Description of how and the app uses Touch ID/Face ID/Phone Passcode to unlock 'screen lock'.
// unlock 'screen lock'.
localizedReason: "authenticateToOpen" localizedReason: "authenticateToOpen"
.put(key: "app_name", value: Constants.app_name) .put(key: "app_name", value: Constants.app_name)
.localized() .localized()
@ -93,7 +87,7 @@ public class ScreenLock {
/// ///
/// * Asynchronously. /// * Asynchronously.
/// * On the main thread. /// * On the main thread.
private func tryToVerifyLocalAuthentication( private static func tryToVerifyLocalAuthentication(
localizedReason: String, localizedReason: String,
completion completionParam: @escaping ((Outcome) -> Void) completion completionParam: @escaping ((Outcome) -> Void)
) { ) {
@ -155,7 +149,7 @@ public class ScreenLock {
// MARK: - Outcome // MARK: - Outcome
private func outcomeForLAError(errorParam: Error?, defaultErrorDescription: String) -> Outcome { private static func outcomeForLAError(errorParam: Error?, defaultErrorDescription: String) -> Outcome {
if let error = errorParam { if let error = errorParam {
guard let laError = error as? LAError else { guard let laError = error as? LAError else {
return .failure(error: defaultErrorDescription) return .failure(error: defaultErrorDescription)
@ -222,7 +216,7 @@ public class ScreenLock {
// MARK: - Context // MARK: - Context
private func screenLockContext() -> LAContext { private static func screenLockContext() -> LAContext {
let context = LAContext() let context = LAContext()
// Never recycle biometric auth. // Never recycle biometric auth.
Loading…
Cancel
Save