From 680b844f3c077ec4e762a3210195ee5573ea44e1 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 21 Feb 2019 17:05:18 -0700 Subject: [PATCH] Allow all windows to do landscape, fixes: 1. Remove undesirable animation from portrait->landscape when minimizizing in landscape and relaunching in landscape. 2. This also seems to fix the intermittently misplaced toolbar when launching in landscape. I believe this is a consequence of fix #1 --- Signal/Signal-Info.plist | 4 - Signal/src/AppDelegate.m | 171 ++---------------- .../ViewControllers/CallViewController.swift | 6 +- .../ViewControllers/OWSNavigationController.m | 2 +- .../ScreenLockViewController.m | 4 +- SignalMessaging/utils/OWSWindowManager.m | 8 +- 6 files changed, 24 insertions(+), 171 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index 5ce47d308..ff7bae766 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -145,10 +145,6 @@ UIStatusBarStyle UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIViewControllerBasedStatusBarAppearance diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index fc580a824..5b7b757e2 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -64,35 +64,6 @@ static NSTimeInterval launchStartedAt; @property (nonatomic) BOOL areVersionMigrationsComplete; @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 #pragma mark - @@ -189,28 +160,26 @@ static NSTimeInterval launchStartedAt; #pragma mark - -- (void)applicationDidEnterBackground:(UIApplication *)application { - OWSLogWarn(@"applicationDidEnterBackground."); - - [self updateShouldEnableLandscape]; +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + OWSLogInfo(@"applicationDidEnterBackground."); [DDLog flushLog]; } -- (void)applicationWillEnterForeground:(UIApplication *)application { - OWSLogWarn(@"applicationWillEnterForeground."); - - [self updateShouldEnableLandscape]; +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + OWSLogInfo(@"applicationWillEnterForeground."); } - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - OWSLogWarn(@"applicationDidReceiveMemoryWarning."); + OWSLogInfo(@"applicationDidReceiveMemoryWarning."); } - (void)applicationWillTerminate:(UIApplication *)application { - OWSLogWarn(@"applicationWillTerminate."); + OWSLogInfo(@"applicationWillTerminate."); [DDLog flushLog]; } @@ -329,14 +298,6 @@ static NSTimeInterval launchStartedAt; selector:@selector(registrationLockDidChange:) name:NSNotificationName_2FAStateDidChange 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."); @@ -675,8 +636,6 @@ static NSTimeInterval launchStartedAt; // be called _before_ we become active. [self clearAllNotificationsAndRestoreBadgeCount]; - [self updateShouldEnableLandscape]; - OWSLogInfo(@"applicationDidBecomeActive completed."); } @@ -779,7 +738,8 @@ static NSTimeInterval launchStartedAt; OWSLogInfo(@"handleActivation completed."); } -- (void)applicationWillResignActive:(UIApplication *)application { +- (void)applicationWillResignActive:(UIApplication *)application +{ OWSAssertIsOnMainThread(); if (self.didAppLaunchFail) { @@ -789,7 +749,6 @@ static NSTimeInterval launchStartedAt; OWSLogWarn(@"applicationWillResignActive."); - [self updateShouldEnableLandscape]; [self clearAllNotificationsAndRestoreBadgeCount]; [DDLog flushLog]; @@ -1008,111 +967,15 @@ static NSTimeInterval launchStartedAt; - (UIInterfaceOrientationMask)application:(UIApplication *)application 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) { + OWSLogInfo(@"has call"); // The call-banner window is only suitable for portrait display 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; } -// 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.35f; - 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 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { @@ -1381,8 +1244,6 @@ static NSTimeInterval launchStartedAt; [self.primaryStorage touchDbAsync]; - [self updateShouldEnableLandscape]; - // Every time the user upgrades to a new version: // // * Update account attributes. @@ -1445,16 +1306,6 @@ static NSTimeInterval launchStartedAt; [self enableBackgroundRefreshIfNecessary]; } -- (void)isScreenBlockActiveDidChange:(NSNotification *)notification -{ - [self updateShouldEnableLandscape]; -} - -- (void)reportedApplicationStateDidChange:(NSNotification *)notification -{ - [self updateShouldEnableLandscape]; -} - - (void)ensureRootViewController { OWSAssertIsOnMainThread(); diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index cb2872c0b..cb6b5360b 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // import Foundation @@ -226,6 +226,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, object: nil) } + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return .portrait + } + // MARK: - Create Views func createViews() { diff --git a/SignalMessaging/ViewControllers/OWSNavigationController.m b/SignalMessaging/ViewControllers/OWSNavigationController.m index a9bd8230e..901cb1517 100644 --- a/SignalMessaging/ViewControllers/OWSNavigationController.m +++ b/SignalMessaging/ViewControllers/OWSNavigationController.m @@ -202,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN if (self.topViewController) { return self.topViewController.supportedInterfaceOrientations; } else { - return UIInterfaceOrientationMaskPortrait; + return UIInterfaceOrientationMaskAllButUpsideDown; } } diff --git a/SignalMessaging/ViewControllers/ScreenLockViewController.m b/SignalMessaging/ViewControllers/ScreenLockViewController.m index d2f5543e7..74afe0844 100644 --- a/SignalMessaging/ViewControllers/ScreenLockViewController.m +++ b/SignalMessaging/ViewControllers/ScreenLockViewController.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "ScreenLockViewController.h" @@ -151,7 +151,7 @@ NSString *NSStringForScreenLockUIState(ScreenLockUIState value) - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - return UIInterfaceOrientationMaskPortrait; + return UIInterfaceOrientationMaskAllButUpsideDown; } @end diff --git a/SignalMessaging/utils/OWSWindowManager.m b/SignalMessaging/utils/OWSWindowManager.m index 057a0d624..deea32f06 100644 --- a/SignalMessaging/utils/OWSWindowManager.m +++ b/SignalMessaging/utils/OWSWindowManager.m @@ -101,7 +101,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - return UIInterfaceOrientationMaskPortrait; + return UIInterfaceOrientationMaskAllButUpsideDown; } @end @@ -120,7 +120,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) - (UIInterfaceOrientationMask)supportedInterfaceOrientations { - return UIInterfaceOrientationMaskPortrait; + return UIInterfaceOrientationMaskAllButUpsideDown; } @end @@ -374,7 +374,9 @@ const UIWindowLevel UIWindowLevel_MessageActions(void) [self.callNavigationController popToRootViewControllerAnimated:NO]; [self.callNavigationController pushViewController:callViewController animated:NO]; self.shouldShowCallView = YES; - + // CallViewController only supports portrait, but if we're _already_ landscape it won't + // automatically switch. + [UIDevice.currentDevice ows_setOrientation:UIInterfaceOrientationPortrait]; [self ensureWindowState]; }