|
|
|
@ -166,21 +166,13 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidEnterBackground:(UIApplication *)application
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"applicationDidEnterBackground");
|
|
|
|
|
|
|
|
|
|
[DDLog flushLog];
|
|
|
|
|
|
|
|
|
|
// Loki: Stop pollers
|
|
|
|
|
[self stopPoller];
|
|
|
|
|
[self stopClosedGroupPoller];
|
|
|
|
|
[self stopOpenGroupPollers];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)applicationWillEnterForeground:(UIApplication *)application
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"applicationWillEnterForeground");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"applicationDidReceiveMemoryWarning");
|
|
|
|
@ -188,11 +180,8 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
- (void)applicationWillTerminate:(UIApplication *)application
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"applicationWillTerminate");
|
|
|
|
|
|
|
|
|
|
[DDLog flushLog];
|
|
|
|
|
|
|
|
|
|
// Loki: Stop pollers
|
|
|
|
|
[self stopPoller];
|
|
|
|
|
[self stopClosedGroupPoller];
|
|
|
|
|
[self stopOpenGroupPollers];
|
|
|
|
@ -200,7 +189,7 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
|
|
|
|
|
|
|
|
|
// This should be the first thing we do.
|
|
|
|
|
// This should be the first thing we do
|
|
|
|
|
SetCurrentAppContext([MainAppContext new]);
|
|
|
|
|
|
|
|
|
|
launchStartedAt = CACurrentMediaTime();
|
|
|
|
@ -218,7 +207,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
[DebugLogger.sharedLogger enableFileLogging];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogWarn(@"application:didFinishLaunchingWithOptions");
|
|
|
|
|
[Cryptography seedRandom];
|
|
|
|
|
|
|
|
|
|
// XXX - careful when moving this. It must happen before we initialize OWSPrimaryStorage.
|
|
|
|
@ -233,18 +221,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// We need to do this _after_ we set up logging, when the keychain is unlocked,
|
|
|
|
|
// but before we access YapDatabase, files on disk, or NSUserDefaults
|
|
|
|
|
if (![self ensureIsReadyForAppExtensions]) {
|
|
|
|
|
// If this method has failed; do nothing.
|
|
|
|
|
//
|
|
|
|
|
// ensureIsReadyForAppExtensions will show a failure mode UI that
|
|
|
|
|
// lets users report this error.
|
|
|
|
|
OWSLogInfo(@"application:didFinishLaunchingWithOptions failed");
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[AppVersion sharedInstance];
|
|
|
|
|
|
|
|
|
|
[self startupLogging];
|
|
|
|
@ -257,7 +233,7 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
[AppSetup
|
|
|
|
|
setupEnvironmentWithAppSpecificSingletonBlock:^{
|
|
|
|
|
// Create AppEnvironment.
|
|
|
|
|
// Create AppEnvironment
|
|
|
|
|
[AppEnvironment.shared setup];
|
|
|
|
|
[SignalApp.sharedApp setup];
|
|
|
|
|
}
|
|
|
|
@ -328,11 +304,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
*/
|
|
|
|
|
- (void)verifyDBKeysAvailableBeforeBackgroundLaunch
|
|
|
|
|
{
|
|
|
|
|
if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) { return; }
|
|
|
|
|
|
|
|
|
|
if (![OWSPrimaryStorage isDatabasePasswordAccessible]) {
|
|
|
|
|
if (!OWSPrimaryStorage.isDatabasePasswordAccessible) {
|
|
|
|
|
OWSLogInfo(@"Exiting because we are in the background and the database password is not accessible.");
|
|
|
|
|
|
|
|
|
|
UILocalNotification *notification = [UILocalNotification new];
|
|
|
|
@ -354,72 +328,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)ensureIsReadyForAppExtensions
|
|
|
|
|
{
|
|
|
|
|
// Given how sensitive this migration is, we verbosely
|
|
|
|
|
// log the contents of all involved paths before and after.
|
|
|
|
|
//
|
|
|
|
|
// TODO: Remove this logging once we have high confidence
|
|
|
|
|
// in our migration logic.
|
|
|
|
|
NSArray<NSString *> *paths = @[
|
|
|
|
|
OWSPrimaryStorage.legacyDatabaseFilePath,
|
|
|
|
|
OWSPrimaryStorage.legacyDatabaseFilePath_SHM,
|
|
|
|
|
OWSPrimaryStorage.legacyDatabaseFilePath_WAL,
|
|
|
|
|
OWSPrimaryStorage.sharedDataDatabaseFilePath,
|
|
|
|
|
OWSPrimaryStorage.sharedDataDatabaseFilePath_SHM,
|
|
|
|
|
OWSPrimaryStorage.sharedDataDatabaseFilePath_WAL,
|
|
|
|
|
];
|
|
|
|
|
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
|
|
|
for (NSString *path in paths) {
|
|
|
|
|
if ([fileManager fileExistsAtPath:path]) {
|
|
|
|
|
OWSLogInfo(@"storage file: %@, %@", path, [OWSFileSystem fileSizeOfPath:path]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([OWSPreferences isReadyForAppExtensions]) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
|
|
|
|
SUPPRESS_DEADSTORE_WARNING(backgroundTask);
|
|
|
|
|
|
|
|
|
|
if ([NSFileManager.defaultManager fileExistsAtPath:OWSPrimaryStorage.legacyDatabaseFilePath]) {
|
|
|
|
|
OWSLogInfo(
|
|
|
|
|
@"Legacy Database file size: %@", [OWSFileSystem fileSizeOfPath:OWSPrimaryStorage.legacyDatabaseFilePath]);
|
|
|
|
|
OWSLogInfo(@"\t Legacy SHM file size: %@",
|
|
|
|
|
[OWSFileSystem fileSizeOfPath:OWSPrimaryStorage.legacyDatabaseFilePath_SHM]);
|
|
|
|
|
OWSLogInfo(@"\t Legacy WAL file size: %@",
|
|
|
|
|
[OWSFileSystem fileSizeOfPath:OWSPrimaryStorage.legacyDatabaseFilePath_WAL]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSError *_Nullable error = [self convertDatabaseIfNecessary];
|
|
|
|
|
|
|
|
|
|
if (!error) {
|
|
|
|
|
[NSUserDefaults migrateToSharedUserDefaults];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!error) {
|
|
|
|
|
error = [OWSPrimaryStorage migrateToSharedData];
|
|
|
|
|
}
|
|
|
|
|
if (!error) {
|
|
|
|
|
error = [OWSUserProfile migrateToSharedData];
|
|
|
|
|
}
|
|
|
|
|
if (!error) {
|
|
|
|
|
error = [TSAttachmentStream migrateToSharedData];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
OWSFailDebug(@"Database conversion failed: %@", error);
|
|
|
|
|
[self showLaunchFailureUI:error];
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSAssertDebug(backgroundTask);
|
|
|
|
|
backgroundTask = nil;
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)showLaunchFailureUI:(NSError *)error
|
|
|
|
|
{
|
|
|
|
|
// Disable normal functioning of app.
|
|
|
|
@ -455,53 +363,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
[fromViewController presentAlert:alert];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (nullable NSError *)convertDatabaseIfNecessary
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"");
|
|
|
|
|
|
|
|
|
|
NSString *databaseFilePath = [OWSPrimaryStorage legacyDatabaseFilePath];
|
|
|
|
|
if (![[NSFileManager defaultManager] fileExistsAtPath:databaseFilePath]) {
|
|
|
|
|
OWSLogVerbose(@"No legacy database file found");
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSError *_Nullable error;
|
|
|
|
|
NSData *_Nullable databasePassword = [OWSStorage tryToLoadDatabaseLegacyPassphrase:&error];
|
|
|
|
|
if (!databasePassword || error) {
|
|
|
|
|
return (error
|
|
|
|
|
?: OWSErrorWithCodeDescription(
|
|
|
|
|
OWSErrorCodeDatabaseConversionFatalError, @"Failed to load database password"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
YapRecordDatabaseSaltBlock recordSaltBlock = ^(NSData *saltData) {
|
|
|
|
|
OWSLogVerbose(@"saltData: %@", saltData.hexadecimalString);
|
|
|
|
|
|
|
|
|
|
// Derive and store the raw cipher key spec, to avoid the ongoing tax of future KDF
|
|
|
|
|
NSData *_Nullable keySpecData =
|
|
|
|
|
[YapDatabaseCryptoUtils deriveDatabaseKeySpecForPassword:databasePassword saltData:saltData];
|
|
|
|
|
|
|
|
|
|
if (!keySpecData) {
|
|
|
|
|
OWSLogError(@"Failed to derive key spec.");
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[OWSStorage storeDatabaseCipherKeySpec:keySpecData];
|
|
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
YapDatabaseOptions *dbOptions = [OWSStorage defaultDatabaseOptions];
|
|
|
|
|
error = [YapDatabaseCryptoUtils convertDatabaseIfNecessary:databaseFilePath
|
|
|
|
|
databasePassword:databasePassword
|
|
|
|
|
options:dbOptions
|
|
|
|
|
recordSaltBlock:recordSaltBlock];
|
|
|
|
|
if (!error) {
|
|
|
|
|
[OWSStorage removeLegacyPassphrase];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)startupLogging
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"iOS Version: %@", [UIDevice currentDevice].systemVersion);
|
|
|
|
@ -585,56 +446,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"Registered legacy notification settings.");
|
|
|
|
|
[self.notificationPresenter didRegisterLegacyNotificationSettings];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)application:(UIApplication *)application
|
|
|
|
|
openURL:(NSURL *)url
|
|
|
|
|
sourceApplication:(NSString *)sourceApplication
|
|
|
|
|
annotation:(id)annotation
|
|
|
|
|
{
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
if (self.didAppLaunchFail) {
|
|
|
|
|
OWSFailDebug(@"App launch failed");
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!AppReadiness.isAppReady) {
|
|
|
|
|
OWSLogWarn(@"Ignoring openURL: app not ready.");
|
|
|
|
|
// We don't need to use [AppReadiness runNowOrWhenAppDidBecomeReady:];
|
|
|
|
|
// the only URLs we handle in Signal iOS at the moment are used
|
|
|
|
|
// for resuming the verification step of the registration flow.
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([url.scheme isEqualToString:kURLSchemeSGNLKey]) {
|
|
|
|
|
if ([url.host hasPrefix:kURLHostVerifyPrefix] && ![self.tsAccountManager isRegistered]) {
|
|
|
|
|
id signupController = SignalApp.sharedApp.signUpFlowNavigationController;
|
|
|
|
|
if ([signupController isKindOfClass:[OWSNavigationController class]]) {
|
|
|
|
|
OWSNavigationController *navController = (OWSNavigationController *)signupController;
|
|
|
|
|
UIViewController *controller = [navController.childViewControllers lastObject];
|
|
|
|
|
if ([controller isKindOfClass:[OnboardingVerificationViewController class]]) {
|
|
|
|
|
OnboardingVerificationViewController *verificationView
|
|
|
|
|
= (OnboardingVerificationViewController *)controller;
|
|
|
|
|
NSString *verificationCode = [url.path substringFromIndex:1];
|
|
|
|
|
[verificationView setVerificationCodeAndTryToVerify:verificationCode];
|
|
|
|
|
return YES;
|
|
|
|
|
} else {
|
|
|
|
|
OWSLogWarn(@"Not the verification view controller we expected. Got %@ instead.",
|
|
|
|
|
NSStringFromClass(controller.class));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
OWSFailDebug(@"Application opened with an unknown URL action: %@", url.host);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
OWSFailDebug(@"Application opened with an unknown URL scheme: %@", url.scheme);
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
@ -643,7 +457,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogWarn(@"applicationDidBecomeActive");
|
|
|
|
|
if (CurrentAppContext().isRunningTests) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -662,27 +475,12 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
// On every activation, clear old temp directories.
|
|
|
|
|
ClearOldTemporaryDirectories();
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"applicationDidBecomeActive completed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)enableBackgroundRefreshIfNecessary
|
|
|
|
|
{
|
|
|
|
|
BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"];
|
|
|
|
|
if (isUsingFullAPNs) { return; }
|
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
|
|
|
|
|
[UIApplication.sharedApplication setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
|
|
|
|
|
// Loki: Original code
|
|
|
|
|
// ========
|
|
|
|
|
// if (OWS2FAManager.sharedManager.is2FAEnabled && [self.tsAccountManager isRegisteredAndReady]) {
|
|
|
|
|
// // Ping server once a day to keep-alive 2FA clients.
|
|
|
|
|
// const NSTimeInterval kBackgroundRefreshInterval = 24 * 60 * 60;
|
|
|
|
|
// [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:kBackgroundRefreshInterval];
|
|
|
|
|
// } else {
|
|
|
|
|
// [[UIApplication sharedApplication]
|
|
|
|
|
// setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalNever];
|
|
|
|
|
// }
|
|
|
|
|
// ========
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -690,8 +488,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
{
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
OWSLogWarn(@"handleActivation");
|
|
|
|
|
|
|
|
|
|
// Always check prekeys after app launches, and sometimes check on app activation.
|
|
|
|
|
[TSPreKeyManager checkPreKeysIfNecessary];
|
|
|
|
|
|
|
|
|
@ -744,19 +540,15 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
|
|
|
|
|
NSString *userHexEncodedPublicKey = self.tsAccountManager.localNumber;
|
|
|
|
|
|
|
|
|
|
// Loki: Start pollers
|
|
|
|
|
[self startPollerIfNeeded];
|
|
|
|
|
[self startClosedGroupPollerIfNeeded];
|
|
|
|
|
[self startOpenGroupPollersIfNeeded];
|
|
|
|
|
|
|
|
|
|
// Loki: Get device links
|
|
|
|
|
[[LKFileServerAPI getDeviceLinksAssociatedWithHexEncodedPublicKey:userHexEncodedPublicKey] retainUntilComplete];
|
|
|
|
|
|
|
|
|
|
// Loki: Update profile picture if needed
|
|
|
|
|
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
|
|
|
|
|
NSDate *now = [NSDate new];
|
|
|
|
|
NSDate *lastProfilePictureUpload = (NSDate *)[userDefaults objectForKey:@"lastProfilePictureUpload"];
|
|
|
|
|
if (lastProfilePictureUpload != nil && [now timeIntervalSinceDate:lastProfilePictureUpload] > 14 * 24 * 60 * 60) {
|
|
|
|
|
if (lastProfilePictureUpload != nil && [now timeIntervalSinceDate:lastProfilePictureUpload] > 4 * 24 * 60 * 60) {
|
|
|
|
|
OWSProfileManager *profileManager = OWSProfileManager.sharedManager;
|
|
|
|
|
NSString *displayName = [profileManager profileNameForRecipientWithID:userHexEncodedPublicKey];
|
|
|
|
|
UIImage *profilePicture = [profileManager profileAvatarForRecipientId:userHexEncodedPublicKey];
|
|
|
|
@ -777,22 +569,8 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
[OWSSyncPushTokensJob runWithAccountManager:AppEnvironment.shared.accountManager
|
|
|
|
|
preferences:Environment.shared.preferences];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([OWS2FAManager sharedManager].isDueForReminder) {
|
|
|
|
|
if (!self.hasInitialRootViewController || self.window.rootViewController == nil) {
|
|
|
|
|
OWSLogDebug(@"Skipping 2FA reminder since there isn't yet an initial view controller.");
|
|
|
|
|
} else {
|
|
|
|
|
UIViewController *rootViewController = self.window.rootViewController;
|
|
|
|
|
OWSNavigationController *reminderNavController =
|
|
|
|
|
[OWS2FAReminderViewController wrappedInNavController];
|
|
|
|
|
|
|
|
|
|
[rootViewController presentViewController:reminderNavController animated:YES completion:nil];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"handleActivation completed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)applicationWillResignActive:(UIApplication *)application
|
|
|
|
@ -804,8 +582,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogWarn(@"applicationWillResignActive");
|
|
|
|
|
|
|
|
|
|
[self clearAllNotificationsAndRestoreBadgeCount];
|
|
|
|
|
|
|
|
|
|
[DDLog flushLog];
|
|
|
|
@ -859,7 +635,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - Orientation
|
|
|
|
|
|
|
|
|
|
- (UIInterfaceOrientationMask)application:(UIApplication *)application
|
|
|
|
@ -868,97 +643,8 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
return UIInterfaceOrientationMaskPortrait;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL)hasCall
|
|
|
|
|
{
|
|
|
|
|
return self.windowManager.hasCall;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark Push Notifications Delegate Methods
|
|
|
|
|
|
|
|
|
|
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
if (self.didAppLaunchFail) {
|
|
|
|
|
OWSFailDebug(@"App launch failed");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!(AppReadiness.isAppReady && [self.tsAccountManager isRegisteredAndReady])) {
|
|
|
|
|
OWSLogInfo(@"Ignoring remote notification; app not ready.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[LKLogger print:@"[Loki] Silent push notification received; fetching messages."];
|
|
|
|
|
|
|
|
|
|
__block AnyPromise *fetchMessagesPromise = [AppEnvironment.shared.messageFetcherJob run].then(^{
|
|
|
|
|
fetchMessagesPromise = nil;
|
|
|
|
|
}).catch(^{
|
|
|
|
|
fetchMessagesPromise = nil;
|
|
|
|
|
});
|
|
|
|
|
[fetchMessagesPromise retainUntilComplete];
|
|
|
|
|
|
|
|
|
|
__block NSDictionary<NSString *, LKPublicChat *> *publicChats;
|
|
|
|
|
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
publicChats = [LKDatabaseUtilities getAllPublicChats:transaction];
|
|
|
|
|
}];
|
|
|
|
|
for (LKPublicChat *publicChat in publicChats) {
|
|
|
|
|
if (![publicChat isKindOfClass:LKPublicChat.class]) { continue; }
|
|
|
|
|
LKPublicChatPoller *poller = [[LKPublicChatPoller alloc] initForPublicChat:publicChat];
|
|
|
|
|
[poller stop];
|
|
|
|
|
AnyPromise *fetchGroupMessagesPromise = [poller pollForNewMessages];
|
|
|
|
|
[fetchGroupMessagesPromise retainUntilComplete];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)application:(UIApplication *)application
|
|
|
|
|
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
|
|
|
|
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
if (self.didAppLaunchFail) {
|
|
|
|
|
OWSFailDebug(@"App launch failed");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!(AppReadiness.isAppReady && [self.tsAccountManager isRegisteredAndReady])) {
|
|
|
|
|
OWSLogInfo(@"Ignoring remote notification; app not ready.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentAppContext().wasWokenUpBySilentPushNotification = true;
|
|
|
|
|
|
|
|
|
|
[LKLogger print:@"[Loki] Silent push notification received; fetching messages."];
|
|
|
|
|
|
|
|
|
|
NSMutableArray *promises = [NSMutableArray new];
|
|
|
|
|
|
|
|
|
|
__block AnyPromise *fetchMessagesPromise = [AppEnvironment.shared.messageFetcherJob run].then(^{
|
|
|
|
|
fetchMessagesPromise = nil;
|
|
|
|
|
}).catch(^{
|
|
|
|
|
fetchMessagesPromise = nil;
|
|
|
|
|
});
|
|
|
|
|
[promises addObject:fetchMessagesPromise];
|
|
|
|
|
[fetchMessagesPromise retainUntilComplete];
|
|
|
|
|
|
|
|
|
|
__block NSDictionary<NSString *, LKPublicChat *> *publicChats;
|
|
|
|
|
[OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
publicChats = [LKDatabaseUtilities getAllPublicChats:transaction];
|
|
|
|
|
}];
|
|
|
|
|
for (LKPublicChat *publicChat in publicChats.allValues) {
|
|
|
|
|
if (![publicChat isKindOfClass:LKPublicChat.class]) { continue; } // For some reason publicChat is sometimes a base 64 encoded string...
|
|
|
|
|
LKPublicChatPoller *poller = [[LKPublicChatPoller alloc] initForPublicChat:publicChat];
|
|
|
|
|
[poller stop];
|
|
|
|
|
AnyPromise *fetchGroupMessagesPromise = [poller pollForNewMessages];
|
|
|
|
|
[promises addObject:fetchGroupMessagesPromise];
|
|
|
|
|
[fetchGroupMessagesPromise retainUntilComplete];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PMKJoin(promises).then(^(id results) {
|
|
|
|
|
completionHandler(UIBackgroundFetchResultNewData);
|
|
|
|
|
CurrentAppContext().wasWokenUpBySilentPushNotification = false;
|
|
|
|
|
}).catch(^(id error) {
|
|
|
|
|
completionHandler(UIBackgroundFetchResultFailed);
|
|
|
|
|
CurrentAppContext().wasWokenUpBySilentPushNotification = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
@ -1022,8 +708,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
withResponseInfo:(NSDictionary *)responseInfo
|
|
|
|
|
completionHandler:(void (^)())completionHandler
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"Handling action with identifier: %@", identifier);
|
|
|
|
|
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
if (self.didAppLaunchFail) {
|
|
|
|
@ -1055,8 +739,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
- (void)application:(UIApplication *)application
|
|
|
|
|
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
|
|
|
|
|
{
|
|
|
|
|
BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"];
|
|
|
|
|
if (isUsingFullAPNs) { return; }
|
|
|
|
|
NSLog(@"[Loki] Performing background fetch.");
|
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
|
|
|
|
|
NSMutableArray *promises = [NSMutableArray new];
|
|
|
|
@ -1113,7 +795,7 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
{
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
// App isn't ready until storage is ready AND all version migrations are complete.
|
|
|
|
|
// App isn't ready until storage is ready AND all version migrations are complete
|
|
|
|
|
if (!self.areVersionMigrationsComplete) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -1121,12 +803,10 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ([AppReadiness isAppReady]) {
|
|
|
|
|
// Only mark the app as ready once.
|
|
|
|
|
// Only mark the app as ready once
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"checkIfAppIsReady");
|
|
|
|
|
|
|
|
|
|
// TODO: Once "app ready" logic is moved into AppSetup, move this line there.
|
|
|
|
|
[self.profileManager ensureLocalProfileCached];
|
|
|
|
|
|
|
|
|
@ -1134,13 +814,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
// it will also run all deferred blocks.
|
|
|
|
|
[AppReadiness setAppIsReady];
|
|
|
|
|
|
|
|
|
|
if (CurrentAppContext().isRunningTests) {
|
|
|
|
|
OWSLogVerbose(@"Skipping post-launch logic in tests.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (CurrentAppContext().isRunningTests) { return; }
|
|
|
|
|
|
|
|
|
|
if ([self.tsAccountManager isRegistered]) {
|
|
|
|
|
OWSLogInfo(@"localNumber: %@", [TSAccountManager localNumber]);
|
|
|
|
|
|
|
|
|
|
// This should happen at any launch, background or foreground
|
|
|
|
|
__unused AnyPromise *pushTokenpromise =
|
|
|
|
@ -1174,8 +850,8 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
//
|
|
|
|
|
// TODO: Release to production once we have analytics.
|
|
|
|
|
// TODO: Orphan cleanup is somewhat expensive - not least in doing a bunch
|
|
|
|
|
// of disk access. We might want to only run it "once per version"
|
|
|
|
|
// or something like that in production.
|
|
|
|
|
// TODO: of disk access. We might want to only run it "once per version"
|
|
|
|
|
// TODO: or something like that in production.
|
|
|
|
|
[OWSOrphanDataCleaner auditOnLaunchIfNecessary];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
@ -1232,17 +908,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
{
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"registrationStateDidChange");
|
|
|
|
|
|
|
|
|
|
[self enableBackgroundRefreshIfNecessary];
|
|
|
|
|
|
|
|
|
|
if ([self.tsAccountManager isRegistered]) {
|
|
|
|
|
OWSLogInfo(@"localNumber: %@", [self.tsAccountManager localNumber]);
|
|
|
|
|
|
|
|
|
|
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
|
|
|
|
[ExperienceUpgradeFinder.sharedManager markAllAsSeenWithTransaction:transaction];
|
|
|
|
|
} error:nil];
|
|
|
|
|
|
|
|
|
|
// Start running the disappearing messages job in case the newly registered user
|
|
|
|
|
// enables this feature
|
|
|
|
|
[self.disappearingMessagesJob startIfNecessary];
|
|
|
|
@ -1251,13 +919,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
// For non-legacy users, read receipts are on by default.
|
|
|
|
|
[self.readReceiptManager setAreReadReceiptsEnabled:YES];
|
|
|
|
|
|
|
|
|
|
// Loki: Start pollers
|
|
|
|
|
[self startPollerIfNeeded];
|
|
|
|
|
[self startClosedGroupPollerIfNeeded];
|
|
|
|
|
[self startOpenGroupPollersIfNeeded];
|
|
|
|
|
|
|
|
|
|
// Loki: Get device links
|
|
|
|
|
[[LKFileServerAPI getDeviceLinksAssociatedWithHexEncodedPublicKey:self.tsAccountManager.localNumber] retainUntilComplete]; // TODO: Is this even needed?
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1270,16 +934,9 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
{
|
|
|
|
|
OWSAssertIsOnMainThread();
|
|
|
|
|
|
|
|
|
|
OWSLogInfo(@"ensureRootViewController");
|
|
|
|
|
|
|
|
|
|
if (!AppReadiness.isAppReady || self.hasInitialRootViewController) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!AppReadiness.isAppReady || self.hasInitialRootViewController) { return; }
|
|
|
|
|
self.hasInitialRootViewController = YES;
|
|
|
|
|
|
|
|
|
|
NSTimeInterval startupDuration = CACurrentMediaTime() - launchStartedAt;
|
|
|
|
|
OWSLogInfo(@"Presenting app %.2f seconds after launch started.", startupDuration);
|
|
|
|
|
|
|
|
|
|
UIViewController *rootViewController;
|
|
|
|
|
BOOL navigationBarHidden = NO;
|
|
|
|
|
if ([self.tsAccountManager isRegistered]) {
|
|
|
|
@ -1298,8 +955,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
navigationController.navigationBarHidden = navigationBarHidden;
|
|
|
|
|
self.window.rootViewController = navigationController;
|
|
|
|
|
|
|
|
|
|
[AppUpdateNag.sharedInstance showAppUpgradeNagIfNecessary];
|
|
|
|
|
|
|
|
|
|
[UIViewController attemptRotationToDeviceOrientation];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1311,7 +966,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]];
|
|
|
|
|
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
|
|
|
|
|
if (CGRectContainsPoint(statusBarFrame, location)) {
|
|
|
|
|
OWSLogDebug(@"touched status bar");
|
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:TappedStatusBarNotification object:nil];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1327,7 +981,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
|
|
|
|
|
__IOS_AVAILABLE(10.0)__TVOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0)__OSX_AVAILABLE(10.14)
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"");
|
|
|
|
|
if (notification.request.content.userInfo[@"remote"]) {
|
|
|
|
|
OWSLogInfo(@"[Loki] Ignoring remote notifications while the app is in the foreground.");
|
|
|
|
|
return;
|
|
|
|
@ -1352,7 +1005,6 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
withCompletionHandler:(void (^)(void))completionHandler __IOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0)
|
|
|
|
|
__OSX_AVAILABLE(10.14)__TVOS_PROHIBITED
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"");
|
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^() {
|
|
|
|
|
[self.userNotificationActionHandler handleNotificationResponse:response completionHandler:completionHandler];
|
|
|
|
|
}];
|
|
|
|
@ -1366,7 +1018,7 @@ static NSTimeInterval launchStartedAt;
|
|
|
|
|
openSettingsForNotification:(nullable UNNotification *)notification __IOS_AVAILABLE(12.0)
|
|
|
|
|
__OSX_AVAILABLE(10.14)__WATCHOS_PROHIBITED __TVOS_PROHIBITED
|
|
|
|
|
{
|
|
|
|
|
OWSLogInfo(@"");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - Loki
|
|
|
|
|