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
This commit is contained in:
Michael Kirk 2019-02-21 17:05:18 -07:00
parent 4e3af534df
commit 680b844f3c
6 changed files with 24 additions and 171 deletions

View File

@ -145,10 +145,6 @@
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>

View File

@ -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();

View File

@ -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() {

View File

@ -202,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN
if (self.topViewController) {
return self.topViewController.supportedInterfaceOrientations;
} else {
return UIInterfaceOrientationMaskPortrait;
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}

View File

@ -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

View File

@ -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];
}