#import "AppDelegate.h" #import "AppAudioManager.h" #import "CallLogViewController.h" #import "CategorizingLogger.h" #import "DebugLogger.h" #import "DialerViewController.h" #import "DiscardingLog.h" #import "Environment.h" #import "InCallViewController.h" #import "LeftSideMenuViewController.h" #import "MMDrawerController.h" #import "PreferencesUtil.h" #import "NotificationTracker.h" #import "PushManager.h" #import "PriorityQueue.h" #import "RecentCallManager.h" #import "Release.h" #import "SettingsViewController.h" #import "TabBarParentViewController.h" #import "Util.h" #import "VersionMigrations.h" #define kSignalVersionKey @"SignalUpdateVersionKey" #ifdef __APPLE__ #include "TargetConditionals.h" #endif @interface AppDelegate () @property (nonatomic, retain) UIWindow *blankWindow; @property (nonatomic, strong) MMDrawerController *drawerController; @property (nonatomic, strong) NotificationTracker *notificationTracker; @end @implementation AppDelegate #pragma mark Detect updates - perform migrations - (void)performUpdateCheck{ // We check if NSUserDefaults key for version exists. NSString *previousVersion = Environment.preferences.lastRanVersion; NSString *currentVersion = [Environment.preferences setAndGetCurrentVersion]; if (!previousVersion) { DDLogError(@"No previous version found. Possibly first launch since install."); [Environment resetAppData]; // We clean previous keychain entries in case their are some entries remaining. } else if ([currentVersion compare:previousVersion options:NSNumericSearch] == NSOrderedDescending){ // Application was updated, let's see if we have a migration scheme for it. if ([previousVersion isEqualToString:@"1.0.2"]) { // Migrate from custom preferences to NSUserDefaults [VersionMigrations migrationFrom1Dot0Dot2toLarger]; } } } /** * Protects the preference and logs file with disk encryption and prevents them to leak to iCloud. */ - (void)protectPreferenceFiles{ NSMutableArray *pathsToExclude = [NSMutableArray array]; NSString *preferencesPath =[NSHomeDirectory() stringByAppendingString:@"/Library/Preferences/"]; NSError *error; NSDictionary *attrs = @{NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication}; [[NSFileManager defaultManager] setAttributes:attrs ofItemAtPath:preferencesPath error:&error]; [pathsToExclude addObject:[[preferencesPath stringByAppendingString:NSBundle.mainBundle.bundleIdentifier] stringByAppendingString:@".plist"]]; NSString *logPath = [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/Logs/"]; NSArray *logsFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logPath error:&error]; attrs = @{NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication}; [[NSFileManager defaultManager] setAttributes:attrs ofItemAtPath:logPath error:&error]; for (NSUInteger i = 0; i < logsFiles.count; i++) { [pathsToExclude addObject:[logPath stringByAppendingString:logsFiles[i]]]; } for (NSUInteger i = 0; i < pathsToExclude.count; i++) { [[NSURL fileURLWithPath:pathsToExclude[i]] setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&error]; } if (error) { DDLogError(@"Error while removing log files from backup: %@", error.description); UIAlertView *alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"WARNING", @"") message:NSLocalizedString(@"DISABLING_BACKUP_FAILED", @"") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil, nil]; [alert show]; return; } } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BOOL loggingIsEnabled; #ifdef DEBUG // Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like // the phone directory being looked up during tests. if (getenv("runningTests_dontStartApp")) { return YES; } loggingIsEnabled = TRUE; [DebugLogger.sharedInstance enableTTYLogging]; #elif RELEASE loggingIsEnabled = Environment.preferences.loggingIsEnabled; #endif if (loggingIsEnabled) { [DebugLogger.sharedInstance enableFileLogging]; } [self performUpdateCheck]; [self protectPreferenceFiles]; self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; [self prepareScreenshotProtection]; self.notificationTracker = [NotificationTracker notificationTracker]; CategorizingLogger* logger = [CategorizingLogger categorizingLogger]; [logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}]; [Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]]; [Environment.getCurrent.phoneDirectoryManager startUntilCancelled:nil]; [Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup]; [UIApplication.sharedApplication setStatusBarStyle:UIStatusBarStyleDefault]; LeftSideMenuViewController *leftSideMenuViewController = [LeftSideMenuViewController new]; self.drawerController = [[MMDrawerController alloc] initWithCenterViewController:leftSideMenuViewController.centerTabBarViewController leftDrawerViewController:leftSideMenuViewController]; self.window.rootViewController = _drawerController; [self.window makeKeyAndVisible]; //Accept push notification when app is not open NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; if (remoteNotif) { DDLogInfo(@"Application was launched by tapping a push notification."); [self application:application didReceiveRemoteNotification:remoteNotif]; } [Environment.phoneManager.currentCallObservable watchLatestValue:^(CallState* latestCall) { if (latestCall == nil){ return; } InCallViewController *callViewController = [InCallViewController inCallViewControllerWithCallState:latestCall andOptionallyKnownContact:latestCall.potentiallySpecifiedContact]; [_drawerController.centerViewController presentViewController:callViewController animated:YES completion:nil]; } onThread:NSThread.mainThread untilCancelled:nil]; return YES; } - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { [PushManager.sharedManager registerForPushWithToken:deviceToken]; } - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { [PushManager.sharedManager verifyPushActivated]; DDLogError(@"Failed to register for push notifications: %@", error); } -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { ResponderSessionDescriptor* call; @try { call = [ResponderSessionDescriptor responderSessionDescriptorFromEncryptedRemoteNotification:userInfo]; DDLogDebug(@"Received remote notification. Parsed session descriptor: %@.", call); } @catch (OperationFailed* ex) { DDLogError(@"Error parsing remote notification. Error: %@.", ex); return; } if (!call) { DDLogError(@"Decryption of session descriptor failed"); return; } [Environment.phoneManager incomingCallWithSession:call]; } -(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { if([self.notificationTracker shouldProcessNotification:userInfo]){ [self application:application didReceiveRemoteNotification:userInfo]; } else{ DDLogDebug(@"Push already processed. Skipping."); } completionHandler(UIBackgroundFetchResultNewData); } -(void) applicationDidBecomeActive:(UIApplication *)application { [AppAudioManager.sharedInstance awake]; // Hacky way to clear notification center after processed push [UIApplication.sharedApplication setApplicationIconBadgeNumber:1]; [UIApplication.sharedApplication setApplicationIconBadgeNumber:0]; [self removeScreenProtection]; if (Environment.isRegistered) { [PushManager.sharedManager verifyPushActivated]; [AppAudioManager.sharedInstance requestRequiredPermissionsIfNeeded]; } } - (void)applicationWillResignActive:(UIApplication *)application{ [self protectScreen]; } - (void)prepareScreenshotProtection{ self.blankWindow = ({ UIWindow *window = [[UIWindow alloc] initWithFrame:self.window.bounds]; window.hidden = YES; window.opaque = YES; window.userInteractionEnabled = NO; window.windowLevel = CGFLOAT_MAX; window; }); } - (void)protectScreen{ if (Environment.preferences.screenSecurityIsEnabled) { self.blankWindow.rootViewController = [UIViewController new]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.blankWindow.bounds]; if (self.blankWindow.bounds.size.height == 568) { imageView.image = [UIImage imageNamed:@"Default-568h"]; } else { imageView.image = [UIImage imageNamed:@"Default"]; } imageView.opaque = YES; [self.blankWindow.rootViewController.view addSubview:imageView]; self.blankWindow.hidden = NO; } } - (void)removeScreenProtection{ if (Environment.preferences.screenSecurityIsEnabled) { self.blankWindow.rootViewController = nil; self.blankWindow.hidden = YES; } } @end