diff --git a/Signal/src/util/MainAppContext.m b/Signal/src/util/MainAppContext.m index 5d7f708e1..4937ee4e0 100644 --- a/Signal/src/util/MainAppContext.m +++ b/Signal/src/util/MainAppContext.m @@ -11,6 +11,14 @@ NS_ASSUME_NONNULL_BEGIN +@interface MainAppContext () + +@property (atomic) UIApplicationState reportedApplicationState; + +@end + +#pragma mark - + @implementation MainAppContext @synthesize mainWindow = _mainWindow; @@ -23,6 +31,8 @@ NS_ASSUME_NONNULL_BEGIN return self; } + self.reportedApplicationState = UIApplicationStateInactive; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification @@ -58,6 +68,8 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertIsOnMainThread(); + self.reportedApplicationState = UIApplicationStateInactive; + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationWillEnterForegroundNotification object:nil]; @@ -67,6 +79,8 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertIsOnMainThread(); + self.reportedApplicationState = UIApplicationStateBackground; + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [DDLog flushLog]; @@ -77,6 +91,8 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertIsOnMainThread(); + self.reportedApplicationState = UIApplicationStateInactive; + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [DDLog flushLog]; @@ -87,6 +103,8 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertIsOnMainThread(); + self.reportedApplicationState = UIApplicationStateActive; + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationDidBecomeActiveNotification object:nil]; @@ -135,12 +153,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)isInBackground { - return [UIApplication sharedApplication].applicationState == UIApplicationStateBackground; -} - -- (UIApplicationState)mainApplicationState -{ - return [UIApplication sharedApplication].applicationState; + return self.reportedApplicationState == UIApplicationStateBackground; } - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler: diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index d4dd65b1b..2145d78b9 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -720,9 +720,9 @@ NSString *const kNSUserDefaults_DatabaseExtensionVersionMap = @"kNSUserDefaults_ stringWithFormat:@"CipherKeySpec inaccessible. New install or no unlock since device restart? Error: %@", error]; if (CurrentAppContext().isMainApp) { - UIApplicationState applicationState = CurrentAppContext().mainApplicationState; - errorDescription = - [errorDescription stringByAppendingFormat:@", ApplicationState: %d", (int)applicationState]; + UIApplicationState applicationState = CurrentAppContext().reportedApplicationState; + errorDescription = [errorDescription + stringByAppendingFormat:@", ApplicationState: %@", NSStringForUIApplicationState(applicationState)]; } DDLogError(@"%@ %@", self.logTag, errorDescription); [DDLog flushLog]; diff --git a/SignalServiceKit/src/Util/AppContext.h b/SignalServiceKit/src/Util/AppContext.h index 1feea801e..8c10362c7 100755 --- a/SignalServiceKit/src/Util/AppContext.h +++ b/SignalServiceKit/src/Util/AppContext.h @@ -33,13 +33,26 @@ NSString *NSStringForUIApplicationState(UIApplicationState value); @property (atomic, nullable) UIWindow *mainWindow; -// Should only be called if isMainApp is YES. +// Unlike UIApplication.applicationState, this is thread-safe. +// It contains the "last known" application state. +// +// Because it is updated in response to "will/did-style" events, it is +// conservative and skews toward less-active and not-foreground: // -// Wherever possible, use isMainAppAndActive or isInBackground instead. -// This should only be used by debugging/logging code. -- (UIApplicationState)mainApplicationState; +// * It doesn't report "is active" until the app is active +// and reports "inactive" as soon as it _will become_ inactive. +// * It doesn't report "is foreground (but inactive)" until the app is +// foreground & inactive and reports "background" as soon as it _will +// enter_ background. +// +// This conservatism is useful, since we want to err on the side of +// caution when, for example, we do work that should only be done +// when the app is foreground and active. +@property (atomic, readonly) UIApplicationState reportedApplicationState; -// Similar to UIApplicationStateBackground, but works in SAE. +// A convenience accessor for reportedApplicationState. +// +// This method is thread-safe. - (BOOL)isInBackground; // Should start a background task if isMainApp is YES. diff --git a/SignalShareExtension/utils/ShareAppExtensionContext.m b/SignalShareExtension/utils/ShareAppExtensionContext.m index 6bf57d5b0..140fd914a 100644 --- a/SignalShareExtension/utils/ShareAppExtensionContext.m +++ b/SignalShareExtension/utils/ShareAppExtensionContext.m @@ -11,7 +11,8 @@ NS_ASSUME_NONNULL_BEGIN @interface ShareAppExtensionContext () @property (nonatomic) UIViewController *rootViewController; -@property (atomic) BOOL isSAEInBackground; + +@property (atomic) UIApplicationState reportedApplicationState; @end @@ -33,6 +34,8 @@ NS_ASSUME_NONNULL_BEGIN _rootViewController = rootViewController; + self.reportedApplicationState = UIApplicationStateInactive; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(extensionHostDidBecomeActive:) name:NSExtensionHostDidBecomeActiveNotification @@ -66,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - self.isSAEInBackground = NO; + self.reportedApplicationState = UIApplicationStateActive; [NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationDidBecomeActiveNotification object:nil]; } @@ -75,6 +78,8 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssertIsOnMainThread(); + self.reportedApplicationState = UIApplicationStateInactive; + DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [DDLog flushLog]; @@ -88,7 +93,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); [DDLog flushLog]; - self.isSAEInBackground = YES; + self.reportedApplicationState = UIApplicationStateBackground; [NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationDidEnterBackgroundNotification object:nil]; } @@ -99,7 +104,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - self.isSAEInBackground = NO; + self.reportedApplicationState = UIApplicationStateInactive; [NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationWillEnterForegroundNotification object:nil]; } @@ -143,13 +148,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)isInBackground { - return self.isSAEInBackground; -} - -- (UIApplicationState)mainApplicationState -{ - OWSFail(@"%@ called %s.", self.logTag, __PRETTY_FUNCTION__); - return UIApplicationStateBackground; + return self.reportedApplicationState == UIApplicationStateBackground; } - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler: