@ -64,35 +64,6 @@ static NSTimeInterval launchStartedAt;
@ property ( nonatomic ) BOOL areVersionMigrationsComplete ;
@ property ( nonatomic ) BOOL areVersionMigrationsComplete ;
@ property ( nonatomic ) BOOL didAppLaunchFail ;
@ property ( nonatomic ) BOOL didAppLaunchFail ;
/ / Signal iOS uses multiple "key " windows , e . g . the screen lock window .
/ / We usually switch "key " windows while becoming active . At the same
/ / time , we often change the state of our orientation mask .
/ /
/ / For reasons unknown , this confuses iOS and leads to very strange
/ / behavior , e . g . :
/ /
/ / * Multiple activation of the app returning from the background , e . g .
/ / transitions from "background , inactive " - > "foreground , inactive "
/ / - > "foreground , active " - > "foreground , inactive " - >
/ / "foreground , active ".
/ / * Multiple ( sometimes incomplete ) orientation changes while becoming
/ / active .
/ / * The side effects of orientation changes ( e . g . safe area insets )
/ / being left in a bad state .
/ /
/ / The solution :
/ /
/ / * Lock app in portrait unless "foreground , active ".
/ / * Don ' t "unlock " until the app has been "foreground , active "
/ / for a short duration ( to allow activation process to safely complete ) .
/ / * After unlocking , try to rotate to the current device orientation .
/ /
/ / The user experience is reasonable : if the user activates the app
/ / while in landscape , the user sees a rotation animation .
@ property ( nonatomic ) BOOL isLandscapeEnabled ;
@ property ( nonatomic ) BOOL shouldEnableLandscape ;
@ property ( nonatomic , nullable ) NSTimer * landscapeTimer ;
@ end
@ end
#pragma mark -
#pragma mark -
@ -189,28 +160,26 @@ static NSTimeInterval launchStartedAt;
#pragma mark -
#pragma mark -
- ( void ) applicationDidEnterBackground : ( UIApplication * ) application {
- ( void ) applicationDidEnterBackground : ( UIApplication * ) application
OWSLogWarn ( @ "applicationDidEnterBackground . ") ;
{
OWSLogInfo ( @ "applicationDidEnterBackground . ") ;
[ self updateShouldEnableLandscape ] ;
[ DDLog flushLog ] ;
[ DDLog flushLog ] ;
}
}
- ( void ) applicationWillEnterForeground : ( UIApplication * ) application {
- ( void ) applicationWillEnterForeground : ( UIApplication * ) application
OWSLogWarn ( @ "applicationWillEnterForeground . ") ;
{
OWSLogInfo ( @ "applicationWillEnterForeground . ") ;
[ self updateShouldEnableLandscape ] ;
}
}
- ( void ) applicationDidReceiveMemoryWarning : ( UIApplication * ) application
- ( void ) applicationDidReceiveMemoryWarning : ( UIApplication * ) application
{
{
OWSLog Warn ( @ "applicationDidReceiveMemoryWarning . ") ;
OWSLog Info ( @ "applicationDidReceiveMemoryWarning . ") ;
}
}
- ( void ) applicationWillTerminate : ( UIApplication * ) application
- ( void ) applicationWillTerminate : ( UIApplication * ) application
{
{
OWSLog Warn ( @ "applicationWillTerminate . ") ;
OWSLog Info ( @ "applicationWillTerminate . ") ;
[ DDLog flushLog ] ;
[ DDLog flushLog ] ;
}
}
@ -329,14 +298,6 @@ static NSTimeInterval launchStartedAt;
selector : @ selector ( registrationLockDidChange : )
selector : @ selector ( registrationLockDidChange : )
name : NSNotificationName_2FAStateDidChange
name : NSNotificationName_2FAStateDidChange
object : nil ] ;
object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( isScreenBlockActiveDidChange : )
name : IsScreenBlockActiveDidChangeNotification
object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( reportedApplicationStateDidChange : )
name : ReportedApplicationStateDidChangeNotification
object : nil ] ;
OWSLogInfo ( @ "application : didFinishLaunchingWithOptions completed . ") ;
OWSLogInfo ( @ "application : didFinishLaunchingWithOptions completed . ") ;
@ -675,8 +636,6 @@ static NSTimeInterval launchStartedAt;
/ / be called _before_ we become active .
/ / be called _before_ we become active .
[ self clearAllNotificationsAndRestoreBadgeCount ] ;
[ self clearAllNotificationsAndRestoreBadgeCount ] ;
[ self updateShouldEnableLandscape ] ;
OWSLogInfo ( @ "applicationDidBecomeActive completed . ") ;
OWSLogInfo ( @ "applicationDidBecomeActive completed . ") ;
}
}
@ -779,7 +738,8 @@ static NSTimeInterval launchStartedAt;
OWSLogInfo ( @ "handleActivation completed . ") ;
OWSLogInfo ( @ "handleActivation completed . ") ;
}
}
- ( void ) applicationWillResignActive : ( UIApplication * ) application {
- ( void ) applicationWillResignActive : ( UIApplication * ) application
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertIsOnMainThread ( ) ;
if ( self . didAppLaunchFail ) {
if ( self . didAppLaunchFail ) {
@ -789,7 +749,6 @@ static NSTimeInterval launchStartedAt;
OWSLogWarn ( @ "applicationWillResignActive . ") ;
OWSLogWarn ( @ "applicationWillResignActive . ") ;
[ self updateShouldEnableLandscape ] ;
[ self clearAllNotificationsAndRestoreBadgeCount ] ;
[ self clearAllNotificationsAndRestoreBadgeCount ] ;
[ DDLog flushLog ] ;
[ DDLog flushLog ] ;
@ -1008,111 +967,15 @@ static NSTimeInterval launchStartedAt;
- ( UIInterfaceOrientationMask ) application : ( UIApplication * ) application
- ( UIInterfaceOrientationMask ) application : ( UIApplication * ) application
supportedInterfaceOrientationsForWindow : ( nullable UIWindow * ) window
supportedInterfaceOrientationsForWindow : ( nullable UIWindow * ) window
{
{
/ / See comments on isLandscapeEnabled property .
if ( !self . isLandscapeEnabled ) {
return UIInterfaceOrientationMaskPortrait ;
}
/ / We use isAppForegroundAndActive which depends on "reportedApplicationState "
/ / and therefore is more conservative about being active .
if ( !CurrentAppContext ( ) . isAppForegroundAndActive ) {
return UIInterfaceOrientationMaskPortrait ;
}
/ / This clause shouldn ' t be necessary , but it ' s nice to
/ / be explicit about our invariants .
if ( !self . hasInitialRootViewController ) {
return UIInterfaceOrientationMaskPortrait ;
}
if ( self . windowManager . hasCall ) {
if ( self . windowManager . hasCall ) {
OWSLogInfo ( @ "has call ") ;
/ / The call - banner window is only suitable for portrait display
/ / The call - banner window is only suitable for portrait display
return UIInterfaceOrientationMaskPortrait ;
return UIInterfaceOrientationMaskPortrait ;
}
}
if ( !window ) {
/ / If `window ` is nil , be permissive . Otherwise orientation
/ / gets messed up during presentation of windows .
return UIInterfaceOrientationMaskAllButUpsideDown ;
}
if ( ![ self . windowManager isAppWindow : window ] ) {
/ / iOS uses various windows for animations , transitions , etc .
/ / e . g . _UIInteractiveHighlightEffectWindow ,
/ / UITextEffectsWindow .
/ /
/ / We should be permissive with these windows .
return UIInterfaceOrientationMaskAllButUpsideDown ;
}
if ( window == self . windowManager . menuActionsWindow ) {
return UIInterfaceOrientationMaskAllButUpsideDown ;
}
if ( self . windowManager . rootWindow != window ) {
return UIInterfaceOrientationMaskPortrait ;
}
return UIInterfaceOrientationMaskAllButUpsideDown ;
return UIInterfaceOrientationMaskAllButUpsideDown ;
}
}
/ / See comments on isLandscapeEnabled property .
- ( void ) updateShouldEnableLandscape
{
OWSAssertIsOnMainThread ( ) ;
/ / We use isAppForegroundAndActive which depends on "reportedApplicationState "
/ / and therefore is more conservative about being active .
self . shouldEnableLandscape = ( CurrentAppContext ( ) . isAppForegroundAndActive && [ AppReadiness isAppReady ]
&& ![ OWSWindowManager sharedManager ] . isScreenBlockActive ) ;
}
/ / See comments on isLandscapeEnabled property .
- ( void ) setShouldEnableLandscape : ( BOOL ) shouldEnableLandscape
{
if ( _shouldEnableLandscape == shouldEnableLandscape ) {
return ;
}
_shouldEnableLandscape = shouldEnableLandscape ;
void ( ^disableLandscape ) ( void ) = ^{
BOOL wasEnabled = self . isLandscapeEnabled ;
self . isLandscapeEnabled = NO ;
[ self . landscapeTimer invalidate ] ;
self . landscapeTimer = nil ;
if ( wasEnabled ) {
[ UIViewController attemptRotationToDeviceOrientation ] ;
}
} ;
if ( shouldEnableLandscape ) {
disableLandscape ( ) ;
/ / Enable Async
NSTimeInterval delay = 0.35 f ;
self . landscapeTimer = [ NSTimer weakScheduledTimerWithTimeInterval : delay
target : self
selector : @ selector ( enableLandscape )
userInfo : nil
repeats : NO ] ;
} else {
/ / Disable .
disableLandscape ( ) ;
}
}
/ / See comments on isLandscapeEnabled property .
- ( void ) enableLandscape
{
OWSAssertIsOnMainThread ( ) ;
self . isLandscapeEnabled = YES ;
[ self . landscapeTimer invalidate ] ;
self . landscapeTimer = nil ;
[ UIViewController attemptRotationToDeviceOrientation ] ;
}
#pragma mark Push Notifications Delegate Methods
#pragma mark Push Notifications Delegate Methods
- ( void ) application : ( UIApplication * ) application didReceiveRemoteNotification : ( NSDictionary * ) userInfo {
- ( void ) application : ( UIApplication * ) application didReceiveRemoteNotification : ( NSDictionary * ) userInfo {
@ -1381,8 +1244,6 @@ static NSTimeInterval launchStartedAt;
[ self . primaryStorage touchDbAsync ] ;
[ self . primaryStorage touchDbAsync ] ;
[ self updateShouldEnableLandscape ] ;
/ / Every time the user upgrades to a new version :
/ / Every time the user upgrades to a new version :
/ /
/ /
/ / * Update account attributes .
/ / * Update account attributes .
@ -1445,16 +1306,6 @@ static NSTimeInterval launchStartedAt;
[ self enableBackgroundRefreshIfNecessary ] ;
[ self enableBackgroundRefreshIfNecessary ] ;
}
}
- ( void ) isScreenBlockActiveDidChange : ( NSNotification * ) notification
{
[ self updateShouldEnableLandscape ] ;
}
- ( void ) reportedApplicationStateDidChange : ( NSNotification * ) notification
{
[ self updateShouldEnableLandscape ] ;
}
- ( void ) ensureRootViewController
- ( void ) ensureRootViewController
{
{
OWSAssertIsOnMainThread ( ) ;
OWSAssertIsOnMainThread ( ) ;