session-ios/Session/Meta/AppDelegate.m

800 lines
29 KiB
Mathematica
Raw Normal View History

2017-01-17 22:01:19 +01:00
//
2019-01-08 17:47:40 +01:00
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
2017-01-17 22:01:19 +01:00
//
2014-05-06 19:41:08 +02:00
#import "AppDelegate.h"
2017-11-29 20:51:39 +01:00
#import "MainAppContext.h"
2018-03-06 16:10:22 +01:00
#import "OWSBackup.h"
2018-08-02 21:18:40 +02:00
#import "OWSOrphanDataCleaner.h"
2018-03-21 20:46:23 +01:00
#import "OWSScreenLockUI.h"
2019-05-02 23:58:48 +02:00
#import "Session-Swift.h"
#import "SignalApp.h"
#import <PromiseKit/AnyPromise.h>
2020-11-12 00:41:45 +01:00
#import <SignalCoreKit/iOSVersions.h>
2020-11-11 07:45:50 +01:00
#import <SignalUtilitiesKit/AppSetup.h>
2020-11-26 00:37:56 +01:00
#import <SessionMessagingKit/Environment.h>
2020-11-11 07:45:50 +01:00
#import <SignalUtilitiesKit/OWSNavigationController.h>
2020-11-26 00:37:56 +01:00
#import <SessionMessagingKit/OWSPreferences.h>
2020-11-11 07:45:50 +01:00
#import <SignalUtilitiesKit/OWSProfileManager.h>
#import <SignalUtilitiesKit/VersionMigrations.h>
2020-11-25 06:15:16 +01:00
#import <SessionMessagingKit/AppReadiness.h>
#import <SessionUtilitiesKit/NSUserDefaults+OWS.h>
#import <SessionMessagingKit/OWSDisappearingMessagesJob.h>
2020-11-11 07:45:50 +01:00
#import <SignalUtilitiesKit/OWSFailedAttachmentDownloadsJob.h>
#import <SignalUtilitiesKit/OWSFailedMessagesJob.h>
2020-11-26 00:37:56 +01:00
#import <SessionUtilitiesKit/OWSMath.h>
2020-11-25 06:15:16 +01:00
#import <SessionMessagingKit/OWSReadReceiptManager.h>
#import <SessionMessagingKit/SSKEnvironment.h>
2020-11-11 07:45:50 +01:00
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
2020-11-25 06:15:16 +01:00
#import <SessionMessagingKit/TSAccountManager.h>
#import <SessionMessagingKit/TSDatabaseView.h>
2018-01-24 23:11:18 +01:00
#import <YapDatabase/YapDatabaseCryptoUtils.h>
2018-10-25 16:18:09 +02:00
#import <sys/utsname.h>
@import Intents;
NSString *const AppDelegateStoryboardMain = @"Main";
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
static NSString *const kURLSchemeSGNLKey = @"sgnl";
static NSString *const kURLHostVerifyPrefix = @"verify";
static NSTimeInterval launchStartedAt;
@interface AppDelegate () <UNUserNotificationCenterDelegate, LKAppModeManagerDelegate>
2014-05-06 19:41:08 +02:00
@property (nonatomic) BOOL hasInitialRootViewController;
@property (nonatomic) BOOL areVersionMigrationsComplete;
@property (nonatomic) BOOL didAppLaunchFail;
@property (nonatomic) LKPoller *poller;
2014-05-06 19:41:08 +02:00
@end
#pragma mark -
@implementation AppDelegate
2014-05-06 19:41:08 +02:00
@synthesize window = _window;
#pragma mark - Dependencies
- (OWSProfileManager *)profileManager
{
return [OWSProfileManager sharedManager];
}
- (OWSReadReceiptManager *)readReceiptManager
{
return [OWSReadReceiptManager sharedManager];
}
- (OWSPrimaryStorage *)primaryStorage
{
OWSAssertDebug(SSKEnvironment.shared.primaryStorage);
return SSKEnvironment.shared.primaryStorage;
}
- (PushRegistrationManager *)pushRegistrationManager
{
OWSAssertDebug(AppEnvironment.shared.pushRegistrationManager);
return AppEnvironment.shared.pushRegistrationManager;
}
- (TSAccountManager *)tsAccountManager
{
OWSAssertDebug(SSKEnvironment.shared.tsAccountManager);
return SSKEnvironment.shared.tsAccountManager;
}
- (OWSDisappearingMessagesJob *)disappearingMessagesJob
{
OWSAssertDebug(SSKEnvironment.shared.disappearingMessagesJob);
return SSKEnvironment.shared.disappearingMessagesJob;
}
2018-10-25 19:02:30 +02:00
- (OWSWindowManager *)windowManager
{
return Environment.shared.windowManager;
}
2018-11-21 23:52:34 +01:00
- (OWSBackup *)backup
{
return AppEnvironment.shared.backup;
}
- (OWSNotificationPresenter *)notificationPresenter
{
return AppEnvironment.shared.notificationPresenter;
}
- (OWSUserNotificationActionHandler *)userNotificationActionHandler
{
return AppEnvironment.shared.userNotificationActionHandler;
}
2020-07-23 06:48:08 +02:00
#pragma mark - Lifecycle
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[DDLog flushLog];
2019-06-11 08:22:35 +02:00
2020-06-30 08:05:35 +02:00
[self stopPoller];
[self stopClosedGroupPoller];
2020-06-30 08:05:35 +02:00
[self stopOpenGroupPollers];
2017-01-17 23:10:57 +01:00
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
OWSLogInfo(@"applicationDidReceiveMemoryWarning");
}
- (void)applicationWillTerminate:(UIApplication *)application
{
[DDLog flushLog];
2020-02-21 04:40:44 +01:00
2020-06-30 08:05:35 +02:00
[self stopPoller];
[self stopClosedGroupPoller];
2020-06-30 08:05:35 +02:00
[self stopOpenGroupPollers];
}
2014-05-06 19:41:08 +02:00
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
2017-11-29 17:01:30 +01:00
2020-07-22 09:48:12 +02:00
// This should be the first thing we do
2017-11-29 20:51:39 +01:00
SetCurrentAppContext([MainAppContext new]);
2017-11-29 17:01:30 +01:00
launchStartedAt = CACurrentMediaTime();
[LKAppModeManager configureWithDelegate:self];
2021-05-05 06:22:29 +02:00
// OWSLinkPreview is now in SessionMessagingKit, so to still be able to deserialize them we
2020-12-08 03:48:18 +01:00
// need to tell NSKeyedUnarchiver about the changes.
2020-12-01 23:51:26 +01:00
[NSKeyedUnarchiver setClass:OWSLinkPreview.class forClassName:@"SessionServiceKit.OWSLinkPreview"];
2018-08-03 01:21:01 +02:00
[Cryptography seedRandom];
// XXX - careful when moving this. It must happen before we initialize OWSPrimaryStorage.
[self verifyDBKeysAvailableBeforeBackgroundLaunch];
2017-11-28 19:46:26 +01:00
2018-08-02 21:18:40 +02:00
[AppVersion sharedInstance];
// Prevent the device from sleeping during database view async registration
// (e.g. long database upgrades).
//
2017-12-19 04:56:02 +01:00
// This block will be cleared in storageIsReady.
[DeviceSleepManager.sharedInstance addBlockWithBlockObject:self];
2018-09-17 15:27:58 +02:00
[AppSetup
setupEnvironmentWithAppSpecificSingletonBlock:^{
2020-07-22 09:48:12 +02:00
// Create AppEnvironment
2018-10-15 21:51:43 +02:00
[AppEnvironment.shared setup];
2018-10-15 20:34:41 +02:00
[SignalApp.sharedApp setup];
}
migrationCompletion:^{
OWSAssertIsOnMainThread();
[self versionMigrationsDidComplete];
2017-12-07 19:53:13 +01:00
}];
2020-11-12 00:41:45 +01:00
[SNConfiguration performMainSetup];
2021-02-17 00:14:48 +01:00
[SNAppearance switchToSessionAppearance];
2017-12-04 18:38:44 +01:00
if (CurrentAppContext().isRunningTests) {
return YES;
}
UIWindow *mainWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = mainWindow;
CurrentAppContext().mainWindow = mainWindow;
// Show LoadingViewController until the async database view registrations are complete.
mainWindow.rootViewController = [LoadingViewController new];
[mainWindow makeKeyAndVisible];
2020-08-24 06:08:56 +02:00
LKAppMode appMode = [NSUserDefaults.standardUserDefaults integerForKey:@"appMode"];
[self setCurrentAppMode:appMode];
if (@available(iOS 11, *)) {
// This must happen in appDidFinishLaunching or earlier to ensure we don't
// miss notifications.
// Setting the delegate also seems to prevent us from getting the legacy notification
// notification callbacks upon launch e.g. 'didReceiveLocalNotification'
UNUserNotificationCenter.currentNotificationCenter.delegate = self;
}
2018-03-21 20:46:23 +01:00
[OWSScreenLockUI.sharedManager setupWithRootWindow:self.window];
2018-04-24 23:00:39 +02:00
[[OWSWindowManager sharedManager] setupWithRootWindow:self.window
screenBlockingWindow:OWSScreenLockUI.sharedManager.screenBlockingWindow];
[OWSScreenLockUI.sharedManager startObserving];
[[NSNotificationCenter defaultCenter] addObserver:self
2017-12-19 04:56:02 +01:00
selector:@selector(storageIsReady)
name:StorageIsReadyNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(registrationStateDidChange)
2017-12-04 18:38:44 +01:00
name:RegistrationStateDidChangeNotification
object:nil];
2019-11-20 06:27:34 +01:00
// Loki - Observe data nuke request notifications
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleDataNukeRequested:) name:NSNotification.dataNukeRequested object:nil];
OWSLogInfo(@"application: didFinishLaunchingWithOptions completed.");
2014-05-06 19:41:08 +02:00
return YES;
}
2020-07-23 06:48:08 +02:00
- (void)applicationDidBecomeActive:(UIApplication *)application {
OWSAssertIsOnMainThread();
if (self.didAppLaunchFail) {
OWSFailDebug(@"App launch failed");
return;
}
if (CurrentAppContext().isRunningTests) {
return;
}
NSUserDefaults *sharedUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.loki-project.loki-messenger"];
2020-08-03 02:50:15 +02:00
[sharedUserDefaults setBool:YES forKey:@"isMainAppActive"];
[sharedUserDefaults synchronize];
2020-07-23 06:48:08 +02:00
[self ensureRootViewController];
2020-08-24 06:08:56 +02:00
LKAppMode appMode = [NSUserDefaults.standardUserDefaults integerForKey:@"appMode"];
[self setCurrentAppMode:appMode];
2020-07-23 06:48:08 +02:00
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
[self handleActivation];
}];
// Clear all notifications whenever we become active.
// When opening the app from a notification,
// AppDelegate.didReceiveLocalNotification will always
// be called _before_ we become active.
[self clearAllNotificationsAndRestoreBadgeCount];
// On every activation, clear old temp directories.
ClearOldTemporaryDirectories();
}
- (void)applicationWillResignActive:(UIApplication *)application
{
OWSAssertIsOnMainThread();
if (self.didAppLaunchFail) {
OWSFailDebug(@"App launch failed");
return;
}
[self clearAllNotificationsAndRestoreBadgeCount];
NSUserDefaults *sharedUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.loki-project.loki-messenger"];
2020-08-03 02:50:15 +02:00
[sharedUserDefaults setBool:NO forKey:@"isMainAppActive"];
[sharedUserDefaults synchronize];
2020-07-23 06:48:08 +02:00
[DDLog flushLog];
}
#pragma mark - Orientation
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait;
}
#pragma mark - Background Fetching
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
2020-09-15 03:30:45 +02:00
[LKBackgroundPoller pollWithCompletionHandler:completionHandler];
2020-07-23 06:48:08 +02:00
}];
}
#pragma mark - App Readiness
2017-12-05 17:35:43 +01:00
/**
* The user must unlock the device once after reboot before the database encryption key can be accessed.
*/
- (void)verifyDBKeysAvailableBeforeBackgroundLaunch
{
2020-07-22 09:48:12 +02:00
if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) { return; }
2017-12-05 17:35:43 +01:00
2020-07-22 09:48:12 +02:00
if (!OWSPrimaryStorage.isDatabasePasswordAccessible) {
OWSLogInfo(@"Exiting because we are in the background and the database password is not accessible.");
UILocalNotification *notification = [UILocalNotification new];
NSString *messageFormat = NSLocalizedString(@"NOTIFICATION_BODY_PHONE_LOCKED_FORMAT",
@"Lock screen notification text presented after user powers on their device without unlocking. Embeds "
@"{{device model}} (either 'iPad' or 'iPhone')");
notification.alertBody = [NSString stringWithFormat:messageFormat, UIDevice.currentDevice.localizedModel];
// Make sure we clear any existing notifications so that they don't start stacking up
// if the user receives multiple pushes.
[UIApplication.sharedApplication cancelAllLocalNotifications];
[UIApplication.sharedApplication setApplicationIconBadgeNumber:0];
[UIApplication.sharedApplication scheduleLocalNotification:notification];
[UIApplication.sharedApplication setApplicationIconBadgeNumber:1];
2018-11-19 18:20:19 +01:00
[DDLog flushLog];
exit(0);
2017-12-05 17:35:43 +01:00
}
}
- (void)enableBackgroundRefreshIfNecessary
{
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
[UIApplication.sharedApplication setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
}];
}
- (void)handleActivation
{
OWSAssertIsOnMainThread();
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if ([self.tsAccountManager isRegistered]) {
// At this point, potentially lengthy DB locking migrations could be running.
// Avoid blocking app launch by putting all further possible DB access in async block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
OWSLogInfo(@"Running post launch block for registered user: %@.", [self.tsAccountManager localNumber]);
2017-11-08 19:03:51 +01:00
// Clean up any messages that expired since last launch immediately
// and continue cleaning in the background.
[self.disappearingMessagesJob startIfNecessary];
[self enableBackgroundRefreshIfNecessary];
// Mark all "attempting out" messages as "unsent", i.e. any messages that were not successfully
// sent before the app exited should be marked as failures.
[[[OWSFailedMessagesJob alloc] initWithPrimaryStorage:self.primaryStorage] run];
[[[OWSFailedAttachmentDownloadsJob alloc] initWithPrimaryStorage:self.primaryStorage] run];
});
}
}); // end dispatchOnce for first time we become active
// Every time we become active...
if ([self.tsAccountManager isRegistered]) {
// At this point, potentially lengthy DB locking migrations could be running.
// Avoid blocking app launch by putting all further possible DB access in async block
dispatch_async(dispatch_get_main_queue(), ^{
2020-07-23 06:48:08 +02:00
NSString *userPublicKey = self.tsAccountManager.localNumber;
2020-02-20 06:59:05 +01:00
2021-03-26 03:28:40 +01:00
// Update profile picture if needed
2020-02-20 06:59:05 +01:00
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
NSDate *now = [NSDate new];
NSDate *lastProfilePictureUpload = (NSDate *)[userDefaults objectForKey:@"lastProfilePictureUpload"];
2021-04-27 00:53:18 +02:00
if (lastProfilePictureUpload != nil && [now timeIntervalSinceDate:lastProfilePictureUpload] > 14 * 24 * 60 * 60) {
2020-02-20 06:59:05 +01:00
OWSProfileManager *profileManager = OWSProfileManager.sharedManager;
2021-02-26 05:56:41 +01:00
NSString *name = [[LKStorage.shared getUser] name];
2020-07-23 06:48:08 +02:00
UIImage *profilePicture = [profileManager profileAvatarForRecipientId:userPublicKey];
2021-02-26 05:56:41 +01:00
[profileManager updateLocalProfileName:name avatarImage:profilePicture success:^{
2020-02-21 04:07:28 +01:00
// Do nothing; the user defaults flag is updated in LokiFileServerAPI
2020-02-20 06:59:05 +01:00
} failure:^(NSError *error) {
// Do nothing
} requiresSync:YES];
}
2021-03-26 03:28:40 +01:00
2021-05-05 06:22:29 +02:00
if (CurrentAppContext().isMainApp) {
2021-03-26 03:28:40 +01:00
[SNOpenGroupAPIV2 getDefaultRoomsIfNeeded];
}
2021-05-03 01:08:50 +02:00
[[SNSnodeAPI getSnodePool] retainUntilComplete];
2021-05-06 01:23:47 +02:00
[self startPollerIfNeeded];
[self startClosedGroupPoller];
2021-05-06 01:23:47 +02:00
[self startOpenGroupPollersIfNeeded];
2020-07-23 06:48:08 +02:00
if (![UIApplication sharedApplication].isRegisteredForRemoteNotifications) {
OWSLogInfo(@"Retrying remote notification registration since user hasn't registered yet.");
// Push tokens don't normally change while the app is launched, so checking once during launch is
// usually sufficient, but e.g. on iOS11, users who have disabled "Allow Notifications" and disabled
// "Background App Refresh" will not be able to obtain an APN token. Enabling those settings does not
// restart the app, so we check every activation for users who haven't yet registered.
2019-05-08 07:51:08 +02:00
__unused AnyPromise *promise =
[OWSSyncPushTokensJob runWithAccountManager:AppEnvironment.shared.accountManager
preferences:Environment.shared.preferences];
}
if (CurrentAppContext().isMainApp) {
[SNJobQueue.shared resumePendingJobs];
2021-01-25 04:46:47 +01:00
[self syncConfigurationIfNeeded];
}
});
}
}
- (void)versionMigrationsDidComplete
{
OWSAssertIsOnMainThread();
self.areVersionMigrationsComplete = YES;
[self checkIfAppIsReady];
}
2017-12-19 04:56:02 +01:00
- (void)storageIsReady
{
OWSAssertIsOnMainThread();
[self checkIfAppIsReady];
}
- (void)checkIfAppIsReady
{
OWSAssertIsOnMainThread();
2020-07-22 09:48:12 +02:00
// App isn't ready until storage is ready AND all version migrations are complete
if (!self.areVersionMigrationsComplete) {
return;
}
if (![OWSStorage isStorageReady]) {
return;
}
if ([AppReadiness isAppReady]) {
2020-07-22 09:48:12 +02:00
// Only mark the app as ready once
return;
}
2021-01-20 23:53:49 +01:00
[SNConfiguration performMainSetup];
2018-01-29 19:43:37 +01:00
// Note that this does much more than set a flag;
// it will also run all deferred blocks.
[AppReadiness setAppIsReady];
2020-07-22 09:48:12 +02:00
if (CurrentAppContext().isRunningTests) { return; }
2018-09-28 16:56:53 +02:00
if ([self.tsAccountManager isRegistered]) {
// This should happen at any launch, background or foreground
2019-05-08 07:51:08 +02:00
__unused AnyPromise *pushTokenpromise =
[OWSSyncPushTokensJob runWithAccountManager:AppEnvironment.shared.accountManager
preferences:Environment.shared.preferences];
2017-09-14 21:30:22 +02:00
}
[DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self];
2018-08-02 21:18:40 +02:00
[AppVersion.sharedInstance mainAppLaunchDidComplete];
[Environment.shared.audioSession setup];
2018-10-22 17:42:53 +02:00
[SSKEnvironment.shared.reachabilityManager setup];
2018-08-31 19:44:13 +02:00
if (!Environment.shared.preferences.hasGeneratedThumbnails) {
[self.primaryStorage.newDatabaseConnection
asyncReadWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
[TSAttachmentStream enumerateCollectionObjectsUsingBlock:^(id _Nonnull obj, BOOL *_Nonnull stop){
// no-op. It's sufficient to initWithCoder: each object.
}];
}
completionBlock:^{
2018-08-31 19:44:13 +02:00
[Environment.shared.preferences setHasGeneratedThumbnails:YES];
}];
}
2020-11-17 06:23:13 +01:00
[self.readReceiptManager prepareCachedValues];
2017-12-19 03:34:22 +01:00
// Disable the SAE until the main app has successfully completed launch process
// at least once in the post-SAE world.
[OWSPreferences setIsReadyForAppExtensions];
2017-12-19 04:56:02 +01:00
[self ensureRootViewController];
2018-03-06 16:10:22 +01:00
2018-12-13 17:40:52 +01:00
[self preheatDatabaseViews];
[self.primaryStorage touchDbAsync];
2019-01-29 22:32:30 +01:00
// Every time the user upgrades to a new version:
//
// * Update account attributes.
// * Sync configuration.
if ([self.tsAccountManager isRegistered]) {
AppVersion *appVersion = AppVersion.sharedInstance;
if (appVersion.lastAppVersion.length > 0
&& ![appVersion.lastAppVersion isEqualToString:appVersion.currentAppVersion]) {
[[self.tsAccountManager updateAccountAttributes] retainUntilComplete];
}
}
2018-12-13 17:40:52 +01:00
}
- (void)preheatDatabaseViews
{
[self.primaryStorage.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (NSString *viewName in @[
TSThreadDatabaseViewExtensionName,
TSMessageDatabaseViewExtensionName,
TSThreadOutgoingMessageDatabaseViewExtensionName,
2018-12-13 18:27:38 +01:00
TSUnreadDatabaseViewExtensionName,
TSUnseenDatabaseViewExtensionName,
2018-12-13 17:40:52 +01:00
]) {
YapDatabaseViewTransaction *databaseView = [transaction ext:viewName];
OWSAssertDebug([databaseView isKindOfClass:[YapDatabaseViewTransaction class]]);
}
}];
}
- (void)registrationStateDidChange
{
2017-12-19 17:38:25 +01:00
OWSAssertIsOnMainThread();
[self enableBackgroundRefreshIfNecessary];
if ([self.tsAccountManager isRegistered]) {
// Start running the disappearing messages job in case the newly registered user
// enables this feature
[self.disappearingMessagesJob startIfNecessary];
// For non-legacy users, read receipts are on by default.
[self.readReceiptManager setAreReadReceiptsEnabled:YES];
2020-07-22 09:48:12 +02:00
2020-03-25 00:27:43 +01:00
[self startPollerIfNeeded];
[self startClosedGroupPoller];
2020-02-21 04:40:44 +01:00
[self startOpenGroupPollersIfNeeded];
}
}
- (void)registrationLockDidChange:(NSNotification *)notification
{
[self enableBackgroundRefreshIfNecessary];
}
- (void)ensureRootViewController
{
OWSAssertIsOnMainThread();
2020-07-22 09:48:12 +02:00
if (!AppReadiness.isAppReady || self.hasInitialRootViewController) { return; }
self.hasInitialRootViewController = YES;
2018-11-21 23:52:34 +01:00
UIViewController *rootViewController;
2018-11-22 01:39:40 +01:00
BOOL navigationBarHidden = NO;
if ([self.tsAccountManager isRegistered]) {
2018-11-21 23:52:34 +01:00
if (self.backup.hasPendingRestoreDecision) {
rootViewController = [BackupRestoreViewController new];
} else {
2019-11-28 06:42:07 +01:00
rootViewController = [HomeVC new];
2018-11-21 23:52:34 +01:00
}
} else {
2020-07-23 02:01:49 +02:00
rootViewController = [LandingVC new];
2019-12-06 04:42:43 +01:00
navigationBarHidden = NO;
}
2018-11-21 23:52:34 +01:00
OWSAssertDebug(rootViewController);
OWSNavigationController *navigationController =
[[OWSNavigationController alloc] initWithRootViewController:rootViewController];
2018-11-22 01:39:40 +01:00
navigationController.navigationBarHidden = navigationBarHidden;
2018-11-21 23:52:34 +01:00
self.window.rootViewController = navigationController;
2019-01-16 21:24:19 +01:00
[UIViewController attemptRotationToDeviceOrientation];
}
2020-07-23 06:48:08 +02:00
#pragma mark - Notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
OWSAssertIsOnMainThread();
if (self.didAppLaunchFail) {
OWSFailDebug(@"App launch failed");
return;
}
[self.pushRegistrationManager didReceiveVanillaPushToken:deviceToken];
OWSLogInfo(@"Registering for push notifications with token: %@.", deviceToken);
BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"];
if (isUsingFullAPNs) {
__unused AnyPromise *promise = [LKPushNotificationAPI registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber isForcedUpdate:NO];
2020-07-23 06:48:08 +02:00
} else {
2020-12-14 04:43:17 +01:00
__unused AnyPromise *promise = [LKPushNotificationAPI unregisterToken:deviceToken];
2020-07-23 06:48:08 +02:00
}
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
OWSAssertIsOnMainThread();
if (self.didAppLaunchFail) {
OWSFailDebug(@"App launch failed");
return;
}
OWSLogError(@"Failed to register push token with error: %@.", error);
#ifdef DEBUG
OWSLogWarn(@"We're in debug mode. Faking success for remote registration with a fake push identifier.");
[self.pushRegistrationManager didReceiveVanillaPushToken:[[NSMutableData dataWithLength:32] copy]];
#else
[self.pushRegistrationManager didFailToReceiveVanillaPushTokenWithError:error];
#endif
}
- (void)clearAllNotificationsAndRestoreBadgeCount
{
OWSAssertIsOnMainThread();
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
[AppEnvironment.shared.notificationPresenter clearAllNotifications];
[OWSMessageUtils.sharedManager updateApplicationBadgeCount];
}];
}
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler
{
OWSAssertIsOnMainThread();
if (self.didAppLaunchFail) {
OWSFailDebug(@"App launch failed");
completionHandler(NO);
return;
}
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
if (![self.tsAccountManager isRegisteredAndReady]) { return; }
2021-03-04 23:18:45 +01:00
[SignalApp.sharedApp.homeViewController createNewDM];
2020-07-23 06:48:08 +02:00
completionHandler(YES);
}];
}
// The method will be called on the delegate only if the application is in the foreground. If the method is not
// implemented or the handler is not called in a timely manner then the notification will not be presented. The
// application can choose to have the notification presented as a sound, badge, alert and/or in the notification list.
// This decision should be based on whether the information in the notification is otherwise visible to the user.
2020-07-23 06:48:08 +02:00
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
__IOS_AVAILABLE(10.0)__TVOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0)__OSX_AVAILABLE(10.14)
{
if (notification.request.content.userInfo[@"remote"]) {
2020-03-27 05:13:24 +01:00
OWSLogInfo(@"[Loki] Ignoring remote notifications while the app is in the foreground.");
return;
}
[AppReadiness runNowOrWhenAppDidBecomeReady:^() {
2019-01-30 23:27:53 +01:00
// We need to respect the in-app notification sound preference. This method, which is called
// for modern UNUserNotification users, could be a place to do that, but since we'd still
// need to handle this behavior for legacy UINotification users anyway, we "allow" all
// notification options here, and rely on the shared logic in NotificationPresenter to
// honor notification sound preferences for both modern and legacy users.
2020-07-23 06:48:08 +02:00
UNNotificationPresentationOptions options = UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound;
completionHandler(options);
}];
}
// The method will be called on the delegate when the user responded to the notification by opening the application,
// dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application
// returns from application:didFinishLaunchingWithOptions:.
2020-07-23 06:48:08 +02:00
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler __IOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0)
__OSX_AVAILABLE(10.14)__TVOS_PROHIBITED
{
[AppReadiness runNowOrWhenAppDidBecomeReady:^() {
[self.userNotificationActionHandler handleNotificationResponse:response completionHandler:completionHandler];
}];
}
// The method will be called on the delegate when the application is launched in response to the user's request to view
// in-app notification settings. Add UNAuthorizationOptionProvidesAppNotificationSettings as an option in
// requestAuthorizationWithOptions:completionHandler: to add a button to inline notification settings view and the
// notification settings view in Settings. The notification will be nil when opened from Settings.
2020-07-23 06:48:08 +02:00
- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification __IOS_AVAILABLE(12.0)
__OSX_AVAILABLE(10.14)__WATCHOS_PROHIBITED __TVOS_PROHIBITED
{
2020-07-22 09:48:12 +02:00
}
2020-07-23 06:48:08 +02:00
#pragma mark - Polling
2020-03-25 00:27:43 +01:00
- (void)startPollerIfNeeded
2019-08-29 07:21:45 +02:00
{
if (self.poller == nil) {
2021-01-11 04:37:49 +01:00
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
2020-07-14 03:27:16 +02:00
if (userPublicKey != nil) {
self.poller = [[LKPoller alloc] init];
}
}
[self.poller startIfNeeded];
2019-08-29 07:21:45 +02:00
}
2020-06-30 08:05:35 +02:00
- (void)stopPoller { [self.poller stop]; }
2020-02-21 04:40:44 +01:00
- (void)startOpenGroupPollersIfNeeded
{
2021-03-24 04:36:26 +01:00
[SNOpenGroupManagerV2.shared startPolling];
2020-02-21 04:40:44 +01:00
}
2021-03-24 04:36:26 +01:00
- (void)stopOpenGroupPollers {
[SNOpenGroupManagerV2.shared stopPolling];
}
2020-02-21 04:40:44 +01:00
# pragma mark - App Mode
2020-08-24 06:08:56 +02:00
- (LKAppMode)getCurrentAppMode
{
2021-02-10 04:43:57 +01:00
return [NSUserDefaults.standardUserDefaults integerForKey:@"appMode"];
}
2020-08-24 06:08:56 +02:00
- (void)setCurrentAppMode:(LKAppMode)appMode
{
UIWindow *window = UIApplication.sharedApplication.keyWindow;
if (window == nil) { return; }
2020-08-24 06:08:56 +02:00
[NSUserDefaults.standardUserDefaults setInteger:appMode forKey:@"appMode"];
switch (appMode) {
case LKAppModeLight: {
if (@available(iOS 13.0, *)) {
2020-08-24 06:08:56 +02:00
window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
2020-08-26 04:02:27 +02:00
window.backgroundColor = UIColor.whiteColor;
break;
}
case LKAppModeDark: {
if (@available(iOS 13.0, *)) {
window.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
}
2020-08-26 04:02:27 +02:00
window.backgroundColor = UIColor.blackColor;
break;
}
}
2020-08-24 06:08:56 +02:00
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.appModeChanged object:nil];
}
2020-07-23 06:48:08 +02:00
# pragma mark - Other
- (void)handleDataNukeRequested:(NSNotification *)notification
{
NSUserDefaults *userDefaults = NSUserDefaults.standardUserDefaults;
BOOL isUsingFullAPNs = [userDefaults boolForKey:@"isUsingFullAPNs"];
NSString *hexEncodedDeviceToken = [userDefaults stringForKey:@"deviceToken"];
if (isUsingFullAPNs && hexEncodedDeviceToken != nil) {
NSData *deviceToken = [NSData dataFromHexString:hexEncodedDeviceToken];
2020-12-14 04:43:17 +01:00
[[LKPushNotificationAPI unregisterToken:deviceToken] retainUntilComplete];
}
2019-11-20 06:27:34 +01:00
[ThreadUtil deleteAllContent];
[SSKEnvironment.shared.identityManager clearIdentityKey];
2020-11-11 07:45:50 +01:00
[SNSnodeAPI clearSnodePool];
2020-06-30 08:05:35 +02:00
[self stopPoller];
[self stopClosedGroupPoller];
2020-06-30 08:05:35 +02:00
[self stopOpenGroupPollers];
BOOL wasUnlinked = [NSUserDefaults.standardUserDefaults boolForKey:@"wasUnlinked"];
2019-12-03 00:28:09 +01:00
[SignalApp resetAppData:^{
// Resetting the data clears the old user defaults. We need to restore the unlink default.
[NSUserDefaults.standardUserDefaults setBool:wasUnlinked forKey:@"wasUnlinked"];
}];
2019-11-20 06:27:34 +01:00
}
2021-06-01 09:39:11 +02:00
# pragma mark - App Link
2021-06-03 03:39:52 +02:00
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
2021-06-01 09:39:11 +02:00
{
2021-06-03 03:39:52 +02:00
NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:true];
2021-06-01 09:39:11 +02:00
// URL Scheme is sessionmessenger://DM?sessionID=1234
// We can later add more parameters like message etc.
NSString *intent = components.host;
2021-06-03 03:39:52 +02:00
if (intent != nil && [intent isEqualToString:@"DM"]) {
NSArray<NSURLQueryItem*> *params = [components queryItems];
NSPredicate *sessionIDPredicate = [NSPredicate predicateWithFormat:@"name == %@", @"sessionID"];
NSArray<NSURLQueryItem*> *matches = [params filteredArrayUsingPredicate:sessionIDPredicate];
if (matches.count > 0) {
NSString *sessionID = matches.firstObject.value;
[self createNewDMFromDeepLink:sessionID];
return YES;
2021-06-01 09:39:11 +02:00
}
}
2021-06-03 03:39:52 +02:00
return NO;
2021-06-01 09:39:11 +02:00
}
2021-06-03 03:39:52 +02:00
- (void)createNewDMFromDeepLink:(NSString *)sessionID
2021-06-01 09:39:11 +02:00
{
UIViewController *viewController = self.window.rootViewController;
2021-06-03 03:39:52 +02:00
if ([viewController class] == [OWSNavigationController class]) {
UIViewController *visibleVC = ((OWSNavigationController *)viewController).visibleViewController;
if ([visibleVC isKindOfClass:HomeVC.class]) {
HomeVC *homeVC = (HomeVC *)visibleVC;
[homeVC createNewDMFromDeepLink:sessionID];
2021-06-01 09:39:11 +02:00
}
}
}
2014-05-06 19:41:08 +02:00
@end