diff --git a/Signal/src/util/MainAppContext.m b/Signal/src/util/MainAppContext.m index 1199d698a..5d7f708e1 100644 --- a/Signal/src/util/MainAppContext.m +++ b/Signal/src/util/MainAppContext.m @@ -128,6 +128,11 @@ NS_ASSUME_NONNULL_BEGIN [[UIApplication sharedApplication] setStatusBarHidden:isHidden animated:isAnimated]; } +- (CGFloat)statusBarHeight +{ + return [UIApplication sharedApplication].statusBarFrame.size.height; +} + - (BOOL)isInBackground { return [UIApplication sharedApplication].applicationState == UIApplicationStateBackground; diff --git a/SignalMessaging/ViewControllers/OWSNavigationController.m b/SignalMessaging/ViewControllers/OWSNavigationController.m index 189fef258..cd85fc451 100644 --- a/SignalMessaging/ViewControllers/OWSNavigationController.m +++ b/SignalMessaging/ViewControllers/OWSNavigationController.m @@ -49,11 +49,17 @@ NS_ASSUME_NONNULL_BEGIN if (@available(iOS 11.0, *)) { if (OWSWindowManager.sharedManager.hasCall) { - self.additionalSafeAreaInsets = UIEdgeInsetsMake(64, 0, 0, 0); + if (UIDevice.currentDevice.isIPhoneX) { + // iPhoneX computes status bar height differently. + self.additionalSafeAreaInsets = UIEdgeInsetsMake(navbar.navbarWithoutStatusHeight + 20, 0, 0, 0); + } else { + self.additionalSafeAreaInsets + = UIEdgeInsetsMake(navbar.navbarWithoutStatusHeight + CurrentAppContext().statusBarHeight, 0, 0, 0); + } } else { self.additionalSafeAreaInsets = UIEdgeInsetsZero; } - // in iOS11 we have to ensure the position *in* layoutSubviews. + // in iOS11 we have to ensure the navbar frame *in* layoutSubviews. [navbar layoutSubviews]; } else { // Pre iOS11 we size the navbar, and position it vertically once. diff --git a/SignalMessaging/Views/OWSNavigationBar.swift b/SignalMessaging/Views/OWSNavigationBar.swift index 6b458adb8..04be1803a 100644 --- a/SignalMessaging/Views/OWSNavigationBar.swift +++ b/SignalMessaging/Views/OWSNavigationBar.swift @@ -16,22 +16,30 @@ class OWSNavigationBar: UINavigationBar { weak var navBarLayoutDelegate: NavBarLayoutDelegate? let navbarWithoutStatusHeight: CGFloat = 44 - let callBannerHeight: CGFloat = OWSWindowManagerCallScreenHeight() + + var callBannerHeight: CGFloat { + return OWSWindowManagerCallScreenHeight() + } var statusBarHeight: CGFloat { - return 20 + return CurrentAppContext().statusBarHeight } var fullWidth: CGFloat { return UIScreen.main.bounds.size.width } + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override init(frame: CGRect) { super.init(frame: frame) self.isTranslucent = false NotificationCenter.default.addObserver(self, selector: #selector(callDidChange), name: .OWSWindowManagerCallDidChange, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(didChangeStatusBarFrame), name: .UIApplicationDidChangeStatusBarFrame, object: nil) } @objc @@ -40,8 +48,10 @@ class OWSNavigationBar: UINavigationBar { self.navBarLayoutDelegate?.navBarCallLayoutDidChange(navbar: self) } - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") + @objc + public func didChangeStatusBarFrame() { + Logger.debug("\(self.logTag) in \(#function)") + self.navBarLayoutDelegate?.navBarCallLayoutDidChange(navbar: self) } override func sizeThatFits(_ size: CGSize) -> CGSize { diff --git a/SignalMessaging/utils/OWSWindowManager.m b/SignalMessaging/utils/OWSWindowManager.m index b5f75518c..a1ede3eae 100644 --- a/SignalMessaging/utils/OWSWindowManager.m +++ b/SignalMessaging/utils/OWSWindowManager.m @@ -16,9 +16,12 @@ NSString *const OWSWindowManagerCallDidChangeNotification = @"OWSWindowManagerCa const CGFloat OWSWindowManagerCallScreenHeight(void) { if ([UIDevice currentDevice].isIPhoneX) { + // On an iPhoneX, the system return-to-call banner has been replaced by a much subtler green + // circle behind the system clock. Instead, we mimic the old system call banner as on older devices, + // but it has to be taller to fit beneath the notch. return 64; } else { - return 40; + return CurrentAppContext().statusBarHeight + 20; } } @@ -29,11 +32,10 @@ const UIWindowLevel UIWindowLevel_Background = -1.f; // It obscures status bar content like the system clock // But being behind the status bar introduces two worse problems that'd we'd need to address // 1. Tap target is too small, only the 20px below the status bar are tappable -// 2. hot-spot connected banner obscure our return-to-call banner, so the user can't see that they're in a call. const UIWindowLevel UIWindowLevel_ReturnToCall(void); const UIWindowLevel UIWindowLevel_ReturnToCall(void) { - return UIWindowLevelStatusBar + 1.f; + return UIWindowLevelStatusBar - 1; } // In front of the root window, behind the screen blocking window. @@ -122,15 +124,34 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void) OWSAssert(screenBlockingWindow); OWSAssert(!self.screenBlockingWindow); + // MJK FIXME + rootWindow.backgroundColor = UIColor.yellowColor; + self.rootWindow = rootWindow; self.screenBlockingWindow = screenBlockingWindow; self.returnToCallWindow = [self createReturnToCallWindow:rootWindow]; self.callViewWindow = [self createCallViewWindow:rootWindow]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangeStatusBarFrame:) + name:UIApplicationDidChangeStatusBarFrameNotification + object:nil]; + [self ensureWindowState]; } +- (void)didChangeStatusBarFrame:(NSNotification *)notification +{ + CGRect newFrame = self.returnToCallWindow.frame; + newFrame.size.height = OWSWindowManagerCallScreenHeight(); + + DDLogDebug(@"%@ StatusBar changed frames - updating returnToCallWindowFrame: %@", + self.logTag, + NSStringFromCGRect(newFrame)); + self.returnToCallWindow.frame = newFrame; +} + - (UIWindow *)createReturnToCallWindow:(UIWindow *)rootWindow { OWSAssertIsOnMainThread(); diff --git a/SignalServiceKit/src/Util/AppContext.h b/SignalServiceKit/src/Util/AppContext.h index 78c77df50..1feea801e 100755 --- a/SignalServiceKit/src/Util/AppContext.h +++ b/SignalServiceKit/src/Util/AppContext.h @@ -59,6 +59,8 @@ NSString *NSStringForUIApplicationState(UIApplicationState value); - (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle; - (void)setStatusBarHidden:(BOOL)isHidden animated:(BOOL)isAnimated; +@property (nonatomic, readonly) CGFloat statusBarHeight; + // Returns the VC that should be used to present alerts, modals, etc. - (nullable UIViewController *)frontmostViewController; diff --git a/SignalShareExtension/utils/ShareAppExtensionContext.m b/SignalShareExtension/utils/ShareAppExtensionContext.m index 0b926a223..6bf57d5b0 100644 --- a/SignalShareExtension/utils/ShareAppExtensionContext.m +++ b/SignalShareExtension/utils/ShareAppExtensionContext.m @@ -135,6 +135,12 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"Ignoring request to show/hide status bar style since we're in an app extension"); } +- (CGFloat)statusBarHeight +{ + OWSFail(@"%@ in %s unexpected for share extension", self.logTag, __PRETTY_FUNCTION__); + return 20; +} + - (BOOL)isInBackground { return self.isSAEInBackground;