From f1d2c0c476ec0cb90606d3dfb4fda15ae66c50c9 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Fri, 16 Jun 2017 19:21:07 +0300 Subject: [PATCH 01/58] Add call section to settings screen --- Riot/Assets/en.lproj/Vector.strings | 4 + Riot/ViewController/SettingsViewController.m | 91 ++++++++++++++++---- 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 04e01d3bc..90e3367bb 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -260,6 +260,7 @@ "settings_user_settings" = "USER SETTINGS"; "settings_notifications_settings" = "NOTIFICATION SETTINGS"; +"settings_calls_settings" = "CALLS"; "settings_ignored_users" = "IGNORED USERS"; "settings_contacts" = "LOCAL CONTACTS"; "settings_advanced" = "ADVANCED"; @@ -298,6 +299,9 @@ //"settings_join_leave_rooms" = "When people join or leave rooms"; //"settings_call_invitations" = "Call invitations"; +"settings_enable_callkit" = "Integrated calling"; +"settings_callkit_info" = "Receive incoming calls on your lock screen. See your Riot calls in the system's call history. If iCloud is enabled, this call history will be shared with Apple."; + "settings_unignore_user" = "Show all messages from %@?"; "settings_contacts_discover_matrix_users" = "Use emails and phone numbers to discover users"; diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 5d3cb9cd6..9524af54c 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -17,34 +17,29 @@ #import "SettingsViewController.h" -#import "RageShakeManager.h" - -#import "AppDelegate.h" - -#import "RiotDesignValues.h" - -#import "AvatarGenerator.h" - -#import +#import #import #import +#import +#import -#import "MXKEncryptionKeysExportView.h" - +#import "AppDelegate.h" +#import "AvatarGenerator.h" #import "CountryPickerViewController.h" +#import "MXKEncryptionKeysExportView.h" +#import "NBPhoneNumberUtil.h" +#import "RageShakeManager.h" +#import "RiotDesignValues.h" #import "TableViewCellWithPhoneNumberTextField.h" -#import "NBPhoneNumberUtil.h" - -#import "OLMKit/OLMKit.h" - -NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId"; +static NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId"; enum { SETTINGS_SECTION_SIGN_OUT_INDEX = 0, SETTINGS_SECTION_USER_SETTINGS_INDEX, SETTINGS_SECTION_NOTIFICATIONS_SETTINGS_INDEX, + SETTINGS_SECTION_CALLS_INDEX, SETTINGS_SECTION_IGNORED_USERS_INDEX, SETTINGS_SECTION_CONTACTS_INDEX, SETTINGS_SECTION_ADVANCED_INDEX, @@ -68,6 +63,13 @@ enum NOTIFICATION_SETTINGS_COUNT }; +enum +{ + CALLS_ENABLE_CALLKIT_INDEX = 0, + CALLS_DESCRIPTION_INDEX, + CALLS_COUNT +}; + enum { OTHER_VERSION_INDEX = 0, @@ -1075,6 +1077,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); { count = NOTIFICATION_SETTINGS_COUNT; } + else if (section == SETTINGS_SECTION_CALLS_INDEX) + { + if ([MXCallKitAdapter callKitAvailable]) + { + count = CALLS_COUNT; + } + } else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX) { if ([AppDelegate theDelegate].mxSessions.count > 0) @@ -1516,6 +1525,29 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); cell = globalInfoCell; } } + else if (section == SETTINGS_SECTION_CALLS_INDEX) + { + if (row == CALLS_ENABLE_CALLKIT_INDEX) + { + MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_callkit", @"Vector", nil); + labelAndSwitchCell.mxkSwitch.on = [MXKAppSettings standardAppSettings].isCallKitEnabled; + labelAndSwitchCell.mxkSwitch.enabled = YES; + [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleCallKit:) forControlEvents:UIControlEventTouchUpInside]; + + cell = labelAndSwitchCell; + } + else if (row == CALLS_DESCRIPTION_INDEX) + { + MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView]; + globalInfoCell.textLabel.text = NSLocalizedStringFromTable(@"settings_callkit_info", @"Vector", nil); + globalInfoCell.textLabel.numberOfLines = 0; + globalInfoCell.selectionStyle = UITableViewCellSelectionStyleNone; + + cell = globalInfoCell; + } + } else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX) { MXKTableViewCell *ignoredUserCell = [self getDefaultTableViewCell:tableView]; @@ -1798,6 +1830,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); { return NSLocalizedStringFromTable(@"settings_notifications_settings", @"Vector", nil); } + else if (section == SETTINGS_SECTION_CALLS_INDEX) + { + if ([MXCallKitAdapter callKitAvailable]) + { + return NSLocalizedStringFromTable(@"settings_calls_settings", @"Vector", nil); + } + } else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX) { // Check whether this section is visible @@ -1892,6 +1931,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } } + else if (section == SETTINGS_SECTION_CALLS_INDEX) + { + if (![MXCallKitAdapter callKitAvailable]) + { + return SECTION_TITLE_PADDING_WHEN_HIDDEN; + } + } return 24; } @@ -1910,6 +1956,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } } + else if (section == SETTINGS_SECTION_CALLS_INDEX) + { + if (![MXCallKitAdapter callKitAvailable]) + { + return SECTION_TITLE_PADDING_WHEN_HIDDEN; + } + } return 24; } @@ -2311,6 +2364,12 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } +- (void)toggleCallKit:(id)sender +{ + UISwitch *switchButton = (UISwitch*)sender; + [MXKAppSettings standardAppSettings].enableCallKit = switchButton.isOn; +} + - (void)toggleLocalContactsSync:(id)sender { UISwitch *switchButton = (UISwitch*)sender; From 005be9f175d79305685fbd31a988f1d70dbb8ff9 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 20 Jun 2017 23:16:54 +0300 Subject: [PATCH 02/58] Add CallKit support --- Riot/AppDelegate.m | 154 +++++++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 54 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 72c8def0f..2b2ad6567 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -37,8 +37,6 @@ #import -#import "CallViewController.h" - //#define MX_CALL_STACK_OPENWEBRTC #ifdef MX_CALL_STACK_OPENWEBRTC #import @@ -48,10 +46,16 @@ #import #endif -#include - #include +// Calls +#import "CallViewController.h" + +#import +#import +#import +#import + #define CALL_STATUS_BAR_HEIGHT 44 #define MAKE_STRING(x) #x @@ -1416,6 +1420,19 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN if (callStack) { [mxSession enableVoIPWithCallStack:callStack]; + + // Setup CallKit + if ([MXCallKitAdapter callKitAvailable]) + { + BOOL isCallKitEnabled = [MXKAppSettings standardAppSettings].isCallKitEnabled; + [self enableCallKit:isCallKitEnabled forCallManager:mxSession.callManager]; + + // Register for changes performed by the user + [[MXKAppSettings standardAppSettings] addObserver:self + forKeyPath:@"enableCallKit" + options:NSKeyValueObservingOptionNew + context:NULL]; + } } else { @@ -1701,6 +1718,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { [self enableInAppNotificationsForAccount:(MXKAccount*)object]; } + else if (object == [MXKAppSettings standardAppSettings] && [keyPath isEqualToString:@"enableCallKit"]) + { + BOOL isCallKitEnabled = [MXKAppSettings standardAppSettings].isCallKitEnabled; + MXCallManager *callManager = [[[[[MXKAccountManager sharedManager] activeAccounts] firstObject] mxSession] callManager]; + [self enableCallKit:isCallKitEnabled forCallManager:callManager]; + } } - (void)addMatrixCallObserver @@ -1710,21 +1733,27 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver]; } - // Register call observer in order to handle new opened session - matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) - { - + void (^handleNotification)(NSNotification *) = ^(NSNotification *notif) { // Ignore the call if a call is already in progress if (!currentCallViewController) { MXCall *mxCall = (MXCall*)notif.object; + BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled; + // Prepare the call view controller - currentCallViewController = [CallViewController callViewController:mxCall]; + currentCallViewController = [CallViewController callViewController:nil]; + currentCallViewController.playRingtone = !isCallKitAvailable; + currentCallViewController.mxCall = mxCall; currentCallViewController.delegate = self; if (mxCall.isIncoming) { + if (isCallKitAvailable) + { + return; + } + // Prompt user before presenting the call view controller NSString *callPromptFormat = mxCall.isVideoCall ? NSLocalizedStringFromTable(@"call_incoming_video_prompt", @"Vector", nil) : NSLocalizedStringFromTable(@"call_incoming_voice_prompt", @"Vector", nil); NSString *callerName = currentCallViewController.peer.displayname; @@ -1734,59 +1763,48 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } NSString *callPrompt = [NSString stringWithFormat:callPromptFormat, callerName]; - __weak typeof(self) weakSelf = self; - // Removing existing notification (if any) [_incomingCallNotification dismiss:NO]; - - _incomingCallNotification = [[MXKAlert alloc] initWithTitle:callPrompt message:nil style:MXKAlertStyleAlert]; - _incomingCallNotification.cancelButtonIndex = [_incomingCallNotification addActionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) - style:MXKAlertActionStyleDefault - handler:^(MXKAlert *alert) { - - if (weakSelf) - { - typeof(self) self = weakSelf; - - // Reject the call. - // Note: Do not reset the incoming call notification before this operation, because it is used to release properly the dismissed call view controller. - if (self->currentCallViewController) - { - [self->currentCallViewController onButtonPressed:self->currentCallViewController.rejectCallButton]; - - currentCallViewController = nil; - } - - self.incomingCallNotification = nil; - - mxCall.delegate = nil; - } - - }]; + _incomingCallNotification.cancelButtonIndex = 0; + + // Decline action + void (^declineAction)(MXKAlert *) = ^(MXKAlert *alert) { + // Reject the call. + // Note: Do not reset the incoming call notification before this operation, because it is used to release properly the dismissed call view controller. + if (currentCallViewController) + { + [currentCallViewController onButtonPressed:currentCallViewController.rejectCallButton]; + currentCallViewController = nil; + } + + _incomingCallNotification = nil; + + mxCall.delegate = nil; + }; + + [_incomingCallNotification addActionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) + style:MXKAlertActionStyleDefault + handler:declineAction]; + + // Accept action + void (^acceptAction)(MXKAlert *) = ^(MXKAlert *alert) { + _incomingCallNotification = nil; + + if (currentCallViewController) + { + [currentCallViewController onButtonPressed:currentCallViewController.answerCallButton]; + [self presentCallViewController:nil]; + } + }; [_incomingCallNotification addActionWithTitle:NSLocalizedStringFromTable(@"accept", @"Vector", nil) style:MXKAlertActionStyleDefault - handler:^(MXKAlert *alert) { - if (weakSelf) - { - typeof(self) self = weakSelf; - - self.incomingCallNotification = nil; - - if (self->currentCallViewController) - { - [self->currentCallViewController onButtonPressed:self->currentCallViewController.answerCallButton]; - - [self presentCallViewController:nil]; - } - - } - }]; + handler:acceptAction]; _incomingCallNotification.mxkAccessibilityIdentifier = @"AppDelegateIncomingCallAlert"; [self showNotificationAlert:_incomingCallNotification]; @@ -1796,8 +1814,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [self presentCallViewController:nil]; } } - - }]; + }; + + // Register call observer in order to handle new opened session + matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:handleNotification]; } - (void)handleLaunchAnimation @@ -1956,6 +1979,29 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } +- (void)enableCallKit:(BOOL)enable forCallManager:(MXCallManager *)callManager +{ + if (enable) + { + // Create adapter with default configuration for a while + MXCallKitAdapter *callKitAdapter = [[MXCallKitAdapter alloc] init]; + + id audioSessionConfigurator; + +#ifdef MX_CALL_STACK_JINGLE + audioSessionConfigurator = [[MXJingleCallAudioSessionConfigurator alloc] init]; +#endif + + callKitAdapter.audioSessionConfigurator = audioSessionConfigurator; + + callManager.callKitAdapter = callKitAdapter; + } + else + { + callManager.callKitAdapter = nil; + } +} + #pragma mark - /** From bf35f4ebee37a323b4786d2c2b4f778c28a5f985 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 20 Jun 2017 23:40:15 +0300 Subject: [PATCH 03/58] Small fix in condition --- Riot/AppDelegate.m | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 2b2ad6567..230bf32bb 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1747,13 +1747,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN currentCallViewController.mxCall = mxCall; currentCallViewController.delegate = self; - if (mxCall.isIncoming) + if (mxCall.isIncoming && !isCallKitAvailable) { - if (isCallKitAvailable) - { - return; - } - // Prompt user before presenting the call view controller NSString *callPromptFormat = mxCall.isVideoCall ? NSLocalizedStringFromTable(@"call_incoming_video_prompt", @"Vector", nil) : NSLocalizedStringFromTable(@"call_incoming_voice_prompt", @"Vector", nil); NSString *callerName = currentCallViewController.peer.displayname; From 45428b9fbffc3cb238ef7a17daeb70000cfc3f92 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Wed, 21 Jun 2017 13:02:49 +0300 Subject: [PATCH 04/58] Return inline blocks and improve imports --- Riot/AppDelegate.m | 82 ++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 230bf32bb..bb2932fcc 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -37,6 +37,14 @@ #import +#include + +// Calls +#import "CallViewController.h" + +#import +#import + //#define MX_CALL_STACK_OPENWEBRTC #ifdef MX_CALL_STACK_OPENWEBRTC #import @@ -46,15 +54,10 @@ #import #endif -#include - -// Calls -#import "CallViewController.h" - -#import -#import +#ifdef MX_CALL_STACK_JINGLE #import #import +#endif #define CALL_STATUS_BAR_HEIGHT 44 @@ -1733,7 +1736,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver]; } - void (^handleNotification)(NSNotification *) = ^(NSNotification *notif) { + // Register call observer in order to handle new opened session + matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall + object:nil + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification *notif) + { // Ignore the call if a call is already in progress if (!currentCallViewController) { @@ -1767,39 +1775,33 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _incomingCallNotification.cancelButtonIndex = 0; - // Decline action - void (^declineAction)(MXKAlert *) = ^(MXKAlert *alert) { - // Reject the call. - // Note: Do not reset the incoming call notification before this operation, because it is used to release properly the dismissed call view controller. - if (currentCallViewController) - { - [currentCallViewController onButtonPressed:currentCallViewController.rejectCallButton]; - currentCallViewController = nil; - } - - _incomingCallNotification = nil; - - mxCall.delegate = nil; - }; - [_incomingCallNotification addActionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) style:MXKAlertActionStyleDefault - handler:declineAction]; - - // Accept action - void (^acceptAction)(MXKAlert *) = ^(MXKAlert *alert) { - _incomingCallNotification = nil; - - if (currentCallViewController) - { - [currentCallViewController onButtonPressed:currentCallViewController.answerCallButton]; - [self presentCallViewController:nil]; - } - }; + handler:^(MXKAlert *alert) { + // Reject the call. + // Note: Do not reset the incoming call notification before this operation, because it is used to release properly the dismissed call view controller. + if (currentCallViewController) + { + [currentCallViewController onButtonPressed:currentCallViewController.rejectCallButton]; + currentCallViewController = nil; + } + + _incomingCallNotification = nil; + + mxCall.delegate = nil; + }]; [_incomingCallNotification addActionWithTitle:NSLocalizedStringFromTable(@"accept", @"Vector", nil) style:MXKAlertActionStyleDefault - handler:acceptAction]; + handler:^(MXKAlert *alert) { + _incomingCallNotification = nil; + + if (currentCallViewController) + { + [currentCallViewController onButtonPressed:currentCallViewController.answerCallButton]; + [self presentCallViewController:nil]; + } + }]; _incomingCallNotification.mxkAccessibilityIdentifier = @"AppDelegateIncomingCallAlert"; [self showNotificationAlert:_incomingCallNotification]; @@ -1809,13 +1811,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [self presentCallViewController:nil]; } } - }; - - // Register call observer in order to handle new opened session - matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall - object:nil - queue:[NSOperationQueue mainQueue] - usingBlock:handleNotification]; + }]; } - (void)handleLaunchAnimation From 2d11fbc40f8bf8b78091de2937a8dedf83628259 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Wed, 26 Jul 2017 16:59:14 +0300 Subject: [PATCH 05/58] Enable Siri in Capabilities tab --- Riot.xcodeproj/project.pbxproj | 3 +++ Riot/Riot.entitlements | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index c7682c902..20ff5aefe 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -2118,6 +2118,9 @@ com.apple.Push = { enabled = 1; }; + com.apple.Siri = { + enabled = 1; + }; }; }; F094A9BD1B78D8F000B1FBBF = { diff --git a/Riot/Riot.entitlements b/Riot/Riot.entitlements index 4cbad96a1..3a9826778 100644 --- a/Riot/Riot.entitlements +++ b/Riot/Riot.entitlements @@ -11,5 +11,7 @@ applinks:riot.im applinks:www.riot.im + com.apple.developer.siri + From 52c3989ec21fa842416ec73e543be9717c5472b8 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Wed, 26 Jul 2017 17:08:00 +0300 Subject: [PATCH 06/58] Add IntentHandler --- Riot.xcodeproj/project.pbxproj | 134 +++++++++++++++++++++++++++++++++ SiriIntents/Info.plist | 42 +++++++++++ SiriIntents/IntentHandler.h | 21 ++++++ SiriIntents/IntentHandler.m | 111 +++++++++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 SiriIntents/Info.plist create mode 100644 SiriIntents/IntentHandler.h create mode 100644 SiriIntents/IntentHandler.m diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 20ff5aefe..124ff3656 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -43,6 +43,8 @@ 32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; }; 32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; }; 32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; }; + 92E963B51F28D907008FDAF5 /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92E963B41F28D907008FDAF5 /* IntentHandler.m */; }; + 92E963B91F28D907008FDAF5 /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92E963B11F28D906008FDAF5 /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E2EAC1A4FBD6FE5228584591 /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D8737F782E108CFD6908691 /* libPods-Riot.a */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F02C1A861E8EB04C0045A404 /* PeopleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F02C1A841E8EB04C0045A404 /* PeopleViewController.m */; }; @@ -485,6 +487,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 92E963B71F28D907008FDAF5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; + proxyType = 1; + remoteGlobalIDString = 92E963B01F28D906008FDAF5; + remoteInfo = SiriIntents; + }; F094A9BF1B78D8F000B1FBBF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; @@ -494,6 +503,20 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 92E963BD1F28D907008FDAF5 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 92E963B91F28D907008FDAF5 /* SiriIntents.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 1129C74A281B080432B1A1A1 /* Pods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.debug.xcconfig"; sourceTree = ""; }; 24B5103C1EFA7083004C6AD2 /* ReadReceiptsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReadReceiptsViewController.h; sourceTree = ""; }; @@ -545,6 +568,10 @@ 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = ""; }; 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = ""; }; 7D8737F782E108CFD6908691 /* libPods-Riot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Riot.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 92E963B11F28D906008FDAF5 /* SiriIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SiriIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 92E963B31F28D907008FDAF5 /* IntentHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntentHandler.h; sourceTree = ""; }; + 92E963B41F28D907008FDAF5 /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = ""; }; + 92E963B61F28D907008FDAF5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = ""; }; F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = ""; }; F02C1A831E8EB04C0045A404 /* PeopleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeopleViewController.h; sourceTree = ""; }; @@ -1111,6 +1138,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 92E963AE1F28D906008FDAF5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F094A99F1B78D8F000B1FBBF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1190,6 +1224,16 @@ name = Frameworks; sourceTree = ""; }; + 92E963B21F28D907008FDAF5 /* SiriIntents */ = { + isa = PBXGroup; + children = ( + 92E963B31F28D907008FDAF5 /* IntentHandler.h */, + 92E963B41F28D907008FDAF5 /* IntentHandler.m */, + 92E963B61F28D907008FDAF5 /* Info.plist */, + ); + path = SiriIntents; + sourceTree = ""; + }; E1451F540F8BC02A7FB7AA31 /* Pods */ = { isa = PBXGroup; children = ( @@ -2045,6 +2089,7 @@ children = ( F083BB081E7009EC00A9B29C /* Riot */, F083BB021E7005FD00A9B29C /* RiotTests */, + 92E963B21F28D907008FDAF5 /* SiriIntents */, F094A9A31B78D8F000B1FBBF /* Products */, E1451F540F8BC02A7FB7AA31 /* Pods */, 6567B0BBF3C05D7F7A7F79CC /* Frameworks */, @@ -2056,6 +2101,7 @@ children = ( F094A9A21B78D8F000B1FBBF /* Riot.app */, F094A9BE1B78D8F000B1FBBF /* RiotTests.xctest */, + 92E963B11F28D906008FDAF5 /* SiriIntents.appex */, ); name = Products; sourceTree = ""; @@ -2063,6 +2109,23 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 92E963B01F28D906008FDAF5 /* SiriIntents */ = { + isa = PBXNativeTarget; + buildConfigurationList = 92E963BA1F28D907008FDAF5 /* Build configuration list for PBXNativeTarget "SiriIntents" */; + buildPhases = ( + 92E963AD1F28D906008FDAF5 /* Sources */, + 92E963AE1F28D906008FDAF5 /* Frameworks */, + 92E963AF1F28D906008FDAF5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SiriIntents; + productName = SiriIntents; + productReference = 92E963B11F28D906008FDAF5 /* SiriIntents.appex */; + productType = "com.apple.product-type.app-extension"; + }; F094A9A11B78D8F000B1FBBF /* Riot */ = { isa = PBXNativeTarget; buildConfigurationList = F094A9C81B78D8F000B1FBBF /* Build configuration list for PBXNativeTarget "Riot" */; @@ -2073,10 +2136,12 @@ F094A9A01B78D8F000B1FBBF /* Resources */, 44C35695CFA4F9799C449367 /* [CP] Copy Pods Resources */, 381DA4CC07D2104BFA23E45A /* [CP] Embed Pods Frameworks */, + 92E963BD1F28D907008FDAF5 /* Embed App Extensions */, ); buildRules = ( ); dependencies = ( + 92E963B81F28D907008FDAF5 /* PBXTargetDependency */, ); name = Riot; productName = Vector; @@ -2110,6 +2175,11 @@ LastUpgradeCheck = 0800; ORGANIZATIONNAME = matrix.org; TargetAttributes = { + 92E963B01F28D906008FDAF5 = { + CreatedOnToolsVersion = 8.3.3; + DevelopmentTeam = 7J4U792NQT; + ProvisioningStyle = Automatic; + }; F094A9A11B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; DevelopmentTeam = 7J4U792NQT; @@ -2148,11 +2218,19 @@ targets = ( F094A9A11B78D8F000B1FBBF /* Riot */, F094A9BD1B78D8F000B1FBBF /* RiotTests */, + 92E963B01F28D906008FDAF5 /* SiriIntents */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 92E963AF1F28D906008FDAF5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; F094A9A01B78D8F000B1FBBF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2558,6 +2636,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 92E963AD1F28D906008FDAF5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92E963B51F28D907008FDAF5 /* IntentHandler.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F094A99E1B78D8F000B1FBBF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2709,6 +2795,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 92E963B81F28D907008FDAF5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 92E963B01F28D906008FDAF5 /* SiriIntents */; + targetProxy = 92E963B71F28D907008FDAF5 /* PBXContainerItemProxy */; + }; F094A9C01B78D8F000B1FBBF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = F094A9A11B78D8F000B1FBBF /* Riot */; @@ -2832,6 +2923,41 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 92E963BB1F28D907008FDAF5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 7J4U792NQT; + INFOPLIST_FILE = SiriIntents/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 92E963BC1F28D907008FDAF5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 7J4U792NQT; + INFOPLIST_FILE = SiriIntents/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; F094A9C61B78D8F000B1FBBF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2993,6 +3119,14 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 92E963BA1F28D907008FDAF5 /* Build configuration list for PBXNativeTarget "SiriIntents" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92E963BB1F28D907008FDAF5 /* Debug */, + 92E963BC1F28D907008FDAF5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/SiriIntents/Info.plist b/SiriIntents/Info.plist new file mode 100644 index 000000000..f0d8ab808 --- /dev/null +++ b/SiriIntents/Info.plist @@ -0,0 +1,42 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + SiriIntents + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsSupported + + INSendMessageIntent + INSearchForMessagesIntent + INSetMessageAttributeIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + IntentHandler + + + diff --git a/SiriIntents/IntentHandler.h b/SiriIntents/IntentHandler.h new file mode 100644 index 000000000..66da341a6 --- /dev/null +++ b/SiriIntents/IntentHandler.h @@ -0,0 +1,21 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface IntentHandler : INExtension + +@end diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m new file mode 100644 index 000000000..5e3fa7d20 --- /dev/null +++ b/SiriIntents/IntentHandler.m @@ -0,0 +1,111 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "IntentHandler.h" + +#import "MXKAccountManager.h" +#import "MXKAccount.h" +#import "MXSession.h" +#import "MXFileStore.h" +//#import + +// As an example, this class is set up to handle Message intents. +// You will want to replace this or add other intents as appropriate. +// The intents you wish to handle must be declared in the extension's Info.plist. + +// You can test your example integration by saying things to Siri like: +// "Send a message using " +// " John saying hello" +// "Search for messages in " + +@interface IntentHandler () + +@end + +@implementation IntentHandler + +- (id)handlerForIntent:(INIntent *)intent { + id handler = nil; + + if ([intent isKindOfClass:INStartAudioCallIntent.class]) + { + handler = self; + } + + return handler; +} + +#pragma mark - INStartAudioCallIntentHandling + +- (void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent withCompletion:(void (^)(NSArray * _Nonnull))completion +{ + MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:account.mxRestClient]; + [session setStore:[[MXFileStore alloc] init] success:^{ + NSLog(@"Super"); + } failure:^(NSError *error) { + NSLog(@"Fail"); + }]; + + // NSArray *recipients = intent.contacts; + // // If no recipients were provided we'll need to prompt for a value. + // if (recipients.count == 0) { + // completion(@[[INPersonResolutionResult needsValue]]); + // return; + // } + // NSMutableArray *resolutionResults = [NSMutableArray array]; + // + // for (INPerson *recipient in recipients) { + // NSArray *matchingContacts = @[recipient]; // Implement your contact matching logic here to create an array of matching contacts + // if (matchingContacts.count > 1) { + // // We need Siri's help to ask user to pick one from the matches. + // [resolutionResults addObject:[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingContacts]]; + // + // } else if (matchingContacts.count == 1) { + // // We have exactly one matching contact + // [resolutionResults addObject:[INPersonResolutionResult successWithResolvedPerson:recipient]]; + // } else { + // // We have no contacts matching the description provided + // [resolutionResults addObject:[INPersonResolutionResult unsupported]]; + // } + // } + // + // completion(resolutionResults); +} + +- (void)confirmStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion +{ + INStartAudioCallIntentResponse *response = nil; + +#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity]; +#else + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; +#endif + + completion(response); +} + +- (void)handleStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion +{ + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + // userActivity.userInfo = @{ @"handle": [NSString stringWithFormat:@"TGCA%d", next.firstObject.userId] }; + INStartAudioCallIntentResponse *response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp userActivity:userActivity]; + completion(response); +} + +@end From bd5c9ca31b968ed4e6ae9823f5a2842acce7d5f2 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 29 Jul 2017 16:28:52 +0300 Subject: [PATCH 07/58] Update plist file for intents extension --- SiriIntents/Info.plist | 74 ++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/SiriIntents/Info.plist b/SiriIntents/Info.plist index f0d8ab808..87df545b8 100644 --- a/SiriIntents/Info.plist +++ b/SiriIntents/Info.plist @@ -1,42 +1,40 @@ - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - SiriIntents - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - XPC! - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSExtension - - NSExtensionAttributes - - IntentsRestrictedWhileLocked - - IntentsSupported - - INSendMessageIntent - INSearchForMessagesIntent - INSetMessageAttributeIntent - - - NSExtensionPointIdentifier - com.apple.intents-service - NSExtensionPrincipalClass - IntentHandler - - + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + SiriIntents + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsSupported + + INStartAudioCallIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + IntentHandler + + From 349a3d454b9d04fb486be494dba991aaf2fd80ba Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 29 Jul 2017 16:30:31 +0300 Subject: [PATCH 08/58] Update project file --- Riot.xcodeproj/project.pbxproj | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 124ff3656..0c45d567d 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -43,6 +43,8 @@ 32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; }; 32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; }; 32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; }; + 7A5A792D23877A47F33ADF07 /* libPods-SiriIntents.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */; }; + 9297595D1F2C8D4500535D3B /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9297595C1F2C8D4500535D3B /* Intents.framework */; }; 92E963B51F28D907008FDAF5 /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92E963B41F28D907008FDAF5 /* IntentHandler.m */; }; 92E963B91F28D907008FDAF5 /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92E963B11F28D906008FDAF5 /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; E2EAC1A4FBD6FE5228584591 /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D8737F782E108CFD6908691 /* libPods-Riot.a */; }; @@ -567,11 +569,16 @@ 32FD0A3A1EB0CD9B0072B066 /* BugReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugReportViewController.h; sourceTree = ""; }; 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = ""; }; 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = ""; }; + 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SiriIntents.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.debug.xcconfig"; sourceTree = ""; }; 7D8737F782E108CFD6908691 /* libPods-Riot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Riot.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 9297595B1F2C8A9A00535D3B /* SiriIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SiriIntents.entitlements; sourceTree = ""; }; + 9297595C1F2C8D4500535D3B /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; 92E963B11F28D906008FDAF5 /* SiriIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SiriIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 92E963B31F28D907008FDAF5 /* IntentHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntentHandler.h; sourceTree = ""; }; 92E963B41F28D907008FDAF5 /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = ""; }; 92E963B61F28D907008FDAF5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.release.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.release.xcconfig"; sourceTree = ""; }; F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = ""; }; F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = ""; }; F02C1A831E8EB04C0045A404 /* PeopleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeopleViewController.h; sourceTree = ""; }; @@ -1142,6 +1149,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 9297595D1F2C8D4500535D3B /* Intents.framework in Frameworks */, + 7A5A792D23877A47F33ADF07 /* libPods-SiriIntents.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1219,7 +1228,9 @@ 6567B0BBF3C05D7F7A7F79CC /* Frameworks */ = { isa = PBXGroup; children = ( + 9297595C1F2C8D4500535D3B /* Intents.framework */, 7D8737F782E108CFD6908691 /* libPods-Riot.a */, + 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */, ); name = Frameworks; sourceTree = ""; @@ -1230,6 +1241,7 @@ 92E963B31F28D907008FDAF5 /* IntentHandler.h */, 92E963B41F28D907008FDAF5 /* IntentHandler.m */, 92E963B61F28D907008FDAF5 /* Info.plist */, + 9297595B1F2C8A9A00535D3B /* SiriIntents.entitlements */, ); path = SiriIntents; sourceTree = ""; @@ -1239,6 +1251,8 @@ children = ( 1129C74A281B080432B1A1A1 /* Pods-Riot.debug.xcconfig */, F9D678EF54918C036FDEDBF9 /* Pods-Riot.release.xcconfig */, + 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */, + E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -2113,9 +2127,11 @@ isa = PBXNativeTarget; buildConfigurationList = 92E963BA1F28D907008FDAF5 /* Build configuration list for PBXNativeTarget "SiriIntents" */; buildPhases = ( + B1481C3FD667495EEBD83C1D /* [CP] Check Pods Manifest.lock */, 92E963AD1F28D906008FDAF5 /* Sources */, 92E963AE1F28D906008FDAF5 /* Frameworks */, 92E963AF1F28D906008FDAF5 /* Resources */, + D7AE9EDB223D9ED53DF15ABF /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -2179,6 +2195,11 @@ CreatedOnToolsVersion = 8.3.3; DevelopmentTeam = 7J4U792NQT; ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; }; F094A9A11B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; @@ -2633,6 +2654,36 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; + B1481C3FD667495EEBD83C1D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + D7AE9EDB223D9ED53DF15ABF /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -2925,12 +2976,15 @@ /* Begin XCBuildConfiguration section */ 92E963BB1F28D907008FDAF5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 7J4U792NQT; + ENABLE_BITCODE = NO; INFOPLIST_FILE = SiriIntents/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; @@ -2942,13 +2996,16 @@ }; 92E963BC1F28D907008FDAF5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 7J4U792NQT; + ENABLE_BITCODE = NO; INFOPLIST_FILE = SiriIntents/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; @@ -3126,6 +3183,7 @@ 92E963BC1F28D907008FDAF5 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = { isa = XCConfigurationList; From 9296e1772a45068d83c95078b8d2a8bf405c7210 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 29 Jul 2017 16:34:51 +0300 Subject: [PATCH 09/58] Update App group info --- Riot.xcodeproj/project.pbxproj | 3 +++ Riot/Riot.entitlements | 4 ++++ SiriIntents/SiriIntents.entitlements | 10 ++++++++++ 3 files changed, 17 insertions(+) create mode 100644 SiriIntents/SiriIntents.entitlements diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 0c45d567d..95556f166 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -2206,6 +2206,9 @@ DevelopmentTeam = 7J4U792NQT; ProvisioningStyle = Automatic; SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; com.apple.Push = { enabled = 1; }; diff --git a/Riot/Riot.entitlements b/Riot/Riot.entitlements index 3a9826778..4094cf66e 100644 --- a/Riot/Riot.entitlements +++ b/Riot/Riot.entitlements @@ -13,5 +13,9 @@ com.apple.developer.siri + com.apple.security.application-groups + + group.org.matrix + diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements new file mode 100644 index 000000000..95ba9ff62 --- /dev/null +++ b/SiriIntents/SiriIntents.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.org.matrix + + + From 8329f284110abecdbd023dcfb22348773bb71c4c Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sun, 30 Jul 2017 16:19:27 +0300 Subject: [PATCH 10/58] Update IntentHandler --- SiriIntents/IntentHandler.m | 171 +++++++++++++++++++++++------------- 1 file changed, 112 insertions(+), 59 deletions(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 5e3fa7d20..ea9d8a943 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -16,20 +16,10 @@ #import "IntentHandler.h" -#import "MXKAccountManager.h" #import "MXKAccount.h" -#import "MXSession.h" +#import "MXKAccountManager.h" #import "MXFileStore.h" -//#import - -// As an example, this class is set up to handle Message intents. -// You will want to replace this or add other intents as appropriate. -// The intents you wish to handle must be declared in the extension's Info.plist. - -// You can test your example integration by saying things to Siri like: -// "Send a message using " -// " John saying hello" -// "Search for messages in " +#import "MXSession.h" @interface IntentHandler () @@ -37,74 +27,137 @@ @implementation IntentHandler -- (id)handlerForIntent:(INIntent *)intent { - id handler = nil; - - if ([intent isKindOfClass:INStartAudioCallIntent.class]) - { - handler = self; - } - - return handler; +- (id)handlerForIntent:(INIntent *)intent +{ + return self; } #pragma mark - INStartAudioCallIntentHandling - (void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent withCompletion:(void (^)(NSArray * _Nonnull))completion { - MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:account.mxRestClient]; - [session setStore:[[MXFileStore alloc] init] success:^{ - NSLog(@"Super"); - } failure:^(NSError *error) { - NSLog(@"Fail"); - }]; - - // NSArray *recipients = intent.contacts; - // // If no recipients were provided we'll need to prompt for a value. - // if (recipients.count == 0) { - // completion(@[[INPersonResolutionResult needsValue]]); - // return; - // } - // NSMutableArray *resolutionResults = [NSMutableArray array]; - // - // for (INPerson *recipient in recipients) { - // NSArray *matchingContacts = @[recipient]; // Implement your contact matching logic here to create an array of matching contacts - // if (matchingContacts.count > 1) { - // // We need Siri's help to ask user to pick one from the matches. - // [resolutionResults addObject:[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingContacts]]; - // - // } else if (matchingContacts.count == 1) { - // // We have exactly one matching contact - // [resolutionResults addObject:[INPersonResolutionResult successWithResolvedPerson:recipient]]; - // } else { - // // We have no contacts matching the description provided - // [resolutionResults addObject:[INPersonResolutionResult unsupported]]; - // } - // } - // - // completion(resolutionResults); + NSArray *contacts = intent.contacts; + if (contacts.count == 0) + { + completion(@[[INPersonResolutionResult needsValue]]); + return; + } + else + { + // We don't iterate over array of contacts from passed intent + // since it's hard to imagine scenario with several callee + // so we just extract the first one + INPerson *callee = contacts.firstObject; + + // Check if the user has selected right callee among several candidates from previous resolution process run + if (callee.customIdentifier && callee.customIdentifier.length) + { + completion(@[[INPersonResolutionResult successWithResolvedPerson:callee]]); + return; + } + + MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + if (account) + { + MXSession *session = [[MXSession alloc] initWithMatrixRestClient:account.mxRestClient]; + [session setStore:[[MXFileStore alloc] init] success:^{ + + // Find all users with whom direct chats are existed + NSMutableSet *directUserIDs = [NSMutableSet set]; + for (MXRoom *room in session.rooms) + { + if (room.directUserId) + [directUserIDs addObject:room.directUserId]; + } + + NSMutableArray *matchingPersons = [NSMutableArray array]; + for (NSString *userID in directUserIDs.allObjects) + { + MXUser *user = [session userWithUserId:userID]; + if (!user.displayname) + continue; + + if (!NSEqualRanges([user.displayname rangeOfString:callee.displayName options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0})) + { + INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; + INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle + nameComponents:nil + displayName:user.displayname + image:nil + contactIdentifier:nil + customIdentifier:user.userId]; + + [matchingPersons addObject:person]; + } + } + + if (matchingPersons.count == 0) + { + completion(@[[INPersonResolutionResult unsupported]]); + } + else if (matchingPersons.count == 1) + { + completion(@[[INPersonResolutionResult successWithResolvedPerson:matchingPersons.firstObject]]); + } + else + { + completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingPersons]]); + } + + } failure:^(NSError *error) { + // TODO: Maybe handle this in another way + completion(@[[INPersonResolutionResult unsupported]]); + }]; + } + else + { + // If user hasn't logged in yet just pass a blank INPerson instance and handle this situation in confirmStartAudioCall:completion: + completion(@[[INPersonResolutionResult successWithResolvedPerson:[INPerson new]]]); + } + } } - (void)confirmStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion { INStartAudioCallIntentResponse *response = nil; + MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + if (account) + { #if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE - NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity]; + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity]; #else - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; #endif + } + else + { + // User hasn't logged in + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]; + } completion(response); } - (void)handleStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion { - NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; - // userActivity.userInfo = @{ @"handle": [NSString stringWithFormat:@"TGCA%d", next.firstObject.userId] }; - INStartAudioCallIntentResponse *response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp userActivity:userActivity]; + INStartAudioCallIntentResponse *response = nil; + + INPerson *person = intent.contacts.firstObject; + if (person && person.customIdentifier) + { + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + userActivity.userInfo = @{ @"userID" : person.customIdentifier }; + + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp + userActivity:userActivity]; + } + else + { + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailure userActivity:nil]; + } + completion(response); } From d6ba5f190c8dd6231bb0270c823bbd18eaad7268 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sun, 30 Jul 2017 19:49:19 +0300 Subject: [PATCH 11/58] Add NSSiriUsageDescription to Info.plist --- Riot/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Info.plist b/Riot/Info.plist index 5346ea088..fde652af4 100644 --- a/Riot/Info.plist +++ b/Riot/Info.plist @@ -49,6 +49,8 @@ The microphone is used to take videos, make calls. NSPhotoLibraryUsageDescription The photo library is used to send photos and videos. + NSSiriUsageDescription + Use Siri to make calls UIBackgroundModes audio From 1936d4e1935feb4c199f5d11adc5e6286b21af0f Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 1 Aug 2017 16:05:53 +0300 Subject: [PATCH 12/58] Update IntentHandler to reflect last changes in MatrixSDK --- SiriIntents/IntentHandler.m | 93 +++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index ea9d8a943..0190db099 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -27,6 +27,16 @@ @implementation IntentHandler +- (instancetype)init +{ + self = [super init]; + if (self) + { + [MXSDKOptions sharedInstance].applicationGroupIdentifier = @"group.org.matrix"; + } + return self; +} + - (id)handlerForIntent:(INIntent *)intent { return self; @@ -59,55 +69,58 @@ MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; if (account) { - MXSession *session = [[MXSession alloc] initWithMatrixRestClient:account.mxRestClient]; - [session setStore:[[MXFileStore alloc] init] success:^{ + MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:account.mxCredentials]; + [fileStore asyncRoomsSummaries:^(NSArray * _Nonnull roomsSummaries) { // Find all users with whom direct chats are existed NSMutableSet *directUserIDs = [NSMutableSet set]; - for (MXRoom *room in session.rooms) + for (MXRoomSummary *summary in roomsSummaries) { - if (room.directUserId) - [directUserIDs addObject:room.directUserId]; + if (summary.isDirect) + [directUserIDs addObject:summary.directUserId]; } - NSMutableArray *matchingPersons = [NSMutableArray array]; - for (NSString *userID in directUserIDs.allObjects) - { - MXUser *user = [session userWithUserId:userID]; - if (!user.displayname) - continue; + [fileStore asyncUsers:^(NSArray * _Nonnull users) { - if (!NSEqualRanges([user.displayname rangeOfString:callee.displayName options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0})) + // Find users with whom we have a direct chat and whose display name contains string presented us by Siri + NSMutableArray *matchingPersons = [NSMutableArray array]; + for (MXUser *user in users) { - INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; - INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle - nameComponents:nil - displayName:user.displayname - image:nil - contactIdentifier:nil - customIdentifier:user.userId]; - - [matchingPersons addObject:person]; + if ([directUserIDs containsObject:user.userId]) + { + if (!user.displayname) + continue; + + if (!NSEqualRanges([user.displayname rangeOfString:callee.displayName options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0})) + { + INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; + INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle + nameComponents:nil + displayName:user.displayname + image:nil + contactIdentifier:nil + customIdentifier:user.userId]; + + [matchingPersons addObject:person]; + } + } } - } - - if (matchingPersons.count == 0) - { - completion(@[[INPersonResolutionResult unsupported]]); - } - else if (matchingPersons.count == 1) - { - completion(@[[INPersonResolutionResult successWithResolvedPerson:matchingPersons.firstObject]]); - } - else - { - completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingPersons]]); - } - - } failure:^(NSError *error) { - // TODO: Maybe handle this in another way - completion(@[[INPersonResolutionResult unsupported]]); - }]; + + if (matchingPersons.count == 0) + { + completion(@[[INPersonResolutionResult unsupported]]); + } + else if (matchingPersons.count == 1) + { + completion(@[[INPersonResolutionResult successWithResolvedPerson:matchingPersons.firstObject]]); + } + else + { + completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingPersons]]); + } + + } failure:nil]; + } failure:nil]; } else { From b0d99bee60b65b52341a8b640ce29b9d60ee0565 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Fri, 4 Aug 2017 10:59:46 +0300 Subject: [PATCH 13/58] Set App Group ID to MXSDKOptions singleton instance --- Riot/AppDelegate.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index b29c573b3..63a6e687a 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1447,6 +1447,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Use UIKit BackgroundTask for handling background tasks in the SDK sdkOptions.backgroundModeHandler = [[MXUIKitBackgroundModeHandler alloc] init]; + // Use shared container to share data with app extensions + sdkOptions.applicationGroupIdentifier = @"group.org.matrix"; + // Disable long press on event in bubble cells [MXKRoomBubbleTableViewCell disableLongPressGestureOnEvent:YES]; From e4f735e4bc9c6707d89720380b775db6d8159573 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Mon, 21 Aug 2017 13:28:05 +0300 Subject: [PATCH 14/58] Replace remote notifications with PushKit notifications --- Riot/AppDelegate.m | 346 +++++++++++++++++++++++++++++++-------------- 1 file changed, 243 insertions(+), 103 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index b29c573b3..3c085c363 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -17,6 +17,8 @@ #import "AppDelegate.h" +#import + #import "RecentsDataSource.h" #import "RoomDataSource.h" @@ -62,7 +64,7 @@ NSString *const kAppDelegateDidTapStatusBarNotification = @"kAppDelegateDidTapStatusBarNotification"; NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateNetworkStatusDidChangeNotification"; -@interface AppDelegate () +@interface AppDelegate () { /** Reachability observer @@ -105,11 +107,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN */ NSMutableArray *mxSessionArray; - /** - The room id of the current handled remote notification (if any) - */ - NSString *remoteNotificationRoomId; - /** The fragment of the universal link being processing. Only one fragment is handled at a time. @@ -166,6 +163,15 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN @property (strong, nonatomic) UIAlertController *mxInAppNotification; @property (strong, nonatomic) UIAlertController *incomingCallNotification; +@property (nonatomic, strong) PKPushRegistry *pushRegistry; + +@property (nonatomic, getter=isHandlingPushNotification) BOOL handlingPushNotification; +@property (nonatomic) NSUInteger pushNotificationHandlingTaskIdentifier; + +@property (nonatomic, nullable) MXOnNotification notificationListenerBlock; +@property (nonatomic, nullable) dispatch_block_t pushNotificationHandlingCompletionBlock; +@property (nonatomic, nullable) dispatch_block_t pushNotificationHandlingTimeoutBlock; + @end @implementation AppDelegate @@ -433,10 +439,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - // cancel any background sync before resuming - // i.e. warn IOS that there is no new data with any received push. - [self cancelBackgroundSync]; - // Open account session(s) if this is not already done (see [initMatrixSessions] in case of background launch). [[MXKAccountManager sharedManager] prepareSessionForActiveAccounts]; @@ -450,8 +452,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { NSLog(@"[AppDelegate] applicationDidBecomeActive"); - remoteNotificationRoomId = nil; - // Check if there is crash log to send if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) { @@ -889,45 +889,14 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { - [application registerForRemoteNotifications]; + self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil]; + self.pushRegistry.delegate = self; + self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; } -- (void)application:(UIApplication*)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { - NSUInteger len = ((deviceToken.length > 8) ? 8 : deviceToken.length / 2); - NSLog(@"[AppDelegate] Got APNS token! (%@ ...)", [deviceToken subdataWithRange:NSMakeRange(0, len)]); - - MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; - [accountManager setApnsDeviceToken:deviceToken]; - - isAPNSRegistered = YES; -} - -- (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error -{ - NSLog(@"[AppDelegate] Failed to register for APNS: %@", error); -} - -- (void)cancelBackgroundSync -{ - if (_completionHandler) - { - _completionHandler(UIBackgroundFetchResultNoData); - _completionHandler = nil; - } -} - -- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler -{ -#ifdef DEBUG - // log the full userInfo only in DEBUG - NSLog(@"[AppDelegate] didReceiveRemoteNotification: %@", userInfo); -#else - NSLog(@"[AppDelegate] didReceiveRemoteNotification"); -#endif - - // Look for the room id - NSString* roomId = [userInfo objectForKey:@"room_id"]; + NSString* roomId = notification.userInfo[@"room_id"]; if (roomId.length) { // TODO retrieve the right matrix session @@ -957,71 +926,242 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // sanity checks if (dedicatedAccount && dedicatedAccount.mxSession) { - UIApplicationState state = [UIApplication sharedApplication].applicationState; + NSLog(@"[AppDelegate] didReceiveLocalNotification: open the roomViewController %@", roomId); - // Jump to the concerned room only if the app is transitioning from the background - if (state == UIApplicationStateInactive) - { - // Check whether another remote notification is not already processed - if (!remoteNotificationRoomId) - { - remoteNotificationRoomId = roomId; - - NSLog(@"[AppDelegate] didReceiveRemoteNotification: open the roomViewController %@", roomId); - - [self showRoom:roomId andEventId:nil withMatrixSession:dedicatedAccount.mxSession]; - } - else - { - NSLog(@"[AppDelegate] didReceiveRemoteNotification: busy"); - } - } - else if (!_completionHandler && (state == UIApplicationStateBackground)) - { - _completionHandler = completionHandler; - - NSLog(@"[AppDelegate] didReceiveRemoteNotification: starts a background sync"); - - [dedicatedAccount backgroundSync:20000 success:^{ - NSLog(@"[AppDelegate] didReceiveRemoteNotification: the background sync succeeds"); - - if (_completionHandler) - { - _completionHandler(UIBackgroundFetchResultNewData); - _completionHandler = nil; - } - } failure:^(NSError *error) { - NSLog(@"[AppDelegate] didReceiveRemoteNotification: the background sync fails"); - - if (_completionHandler) - { - _completionHandler(UIBackgroundFetchResultNoData); - _completionHandler = nil; - } - }]; - - // wait that the background sync is done - return; - } + [self showRoom:roomId andEventId:nil withMatrixSession:dedicatedAccount.mxSession]; } else { - NSLog(@"[AppDelegate] didReceiveRemoteNotification : no linked session / account has been found."); + NSLog(@"[AppDelegate] didReceiveLocalNotification : no linked session / account has been found."); } } - completionHandler(UIBackgroundFetchResultNoData); + } -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo +- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type { - // iOS 10 (at least up to GM beta release) does not call application:didReceiveRemoteNotification:fetchCompletionHandler: - // when the user clicks on a notification but it calls this deprecated version - // of didReceiveRemoteNotification. - // Use this method as a workaround as adviced at http://stackoverflow.com/a/39419245 - NSLog(@"[AppDelegate] didReceiveRemoteNotification (deprecated version)"); + NSData *token = credentials.token; - [self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) { + NSUInteger len = ((token.length > 8) ? 8 : token.length / 2); + NSLog(@"[AppDelegate] Got APNS token! (%@ ...)", [token subdataWithRange:NSMakeRange(0, len)]); + + MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; + [accountManager setApnsDeviceToken:token]; + + isAPNSRegistered = YES; +} + +- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type +{ + MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; + [accountManager setApnsDeviceToken:nil]; +} + +- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type +{ + // If it isn't a first push + if (self.isHandlingPushNotification) + { + // If we have processed push notification and we're waiting to complete after a timeout + if (self.pushNotificationHandlingCompletionBlock) + { + // Cancel completion of previous push notification. + // The new completion block will be created when this push notification will be processed if timeout block wouldn't be called + dispatch_block_cancel(self.pushNotificationHandlingCompletionBlock); + self.pushNotificationHandlingCompletionBlock = nil; + } + + // On every new push cancel timeout block if any. + // This situation is possible when we sequentially receive a series of push notifications in a short amount of time. + if (self.pushNotificationHandlingTimeoutBlock) + { + dispatch_block_cancel(self.pushNotificationHandlingTimeoutBlock); + self.pushNotificationHandlingTimeoutBlock = nil; + } + + // Create and run timeout block since we don't know how much time will take a new sync request + // There is also a case when we receive push event earlier than push and we need to stop execution somehow + // so timeoutBlock will help us in this situation + dispatch_block_t timeoutBlock = [self createPushNotificationHandlingStateCleaningBlock]; + self.pushNotificationHandlingTimeoutBlock = timeoutBlock; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(120 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + timeoutBlock(); + }); + + return; + } + + UIApplication *application = [UIApplication sharedApplication]; + + if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateInactive) + return; + + MXSession *session = mxSessionArray.firstObject; + + if (session.state == MXSessionStateHomeserverNotReachable) + return; + + if (session.state == MXSessionStatePaused) + [session resume:^{}]; + + self.handlingPushNotification = YES; + + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; + self.pushNotificationHandlingTaskIdentifier = [handler startBackgroundTaskWithName:nil completion:^{ + // Maybe do smth here... }]; + + // Listen events from MXNotificationCenter + __block MXOnNotification notificationsListenerBlock = nil; + + // This variable will be point to notificationsListenerBlock but won't retain it. + // It's very important since notificationsListenerBlock is required in two another blocks which also + // are being referenced inside notificationsListenerBlock's body. + // So this weak variable allows us to avoid retain cycle. + __weak __block MXOnNotification weakNotificationsListenerBlock = nil; + + // The block which is called when a sync with server takes a lot of time + dispatch_block_t timeoutBlock = [self createPushNotificationHandlingStateCleaningBlock]; + self.pushNotificationHandlingTimeoutBlock = timeoutBlock; + + __weak typeof(self) weakSelf = self; + + notificationsListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) { + if (weakSelf.pushNotificationHandlingTimeoutBlock) + { + dispatch_block_cancel(weakSelf.pushNotificationHandlingTimeoutBlock); + weakSelf.pushNotificationHandlingTimeoutBlock = nil; + } + + if (weakSelf.pushNotificationHandlingCompletionBlock) + { + dispatch_block_cancel(weakSelf.pushNotificationHandlingCompletionBlock); + weakSelf.pushNotificationHandlingCompletionBlock = nil; + } + + BOOL isEventRoomDirect = [session roomWithRoomId:event.roomId].isDirect; + NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; + if (notificationBody) + { + UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; + eventNotification.fireDate = [NSDate date]; + eventNotification.alertBody = notificationBody; + eventNotification.userInfo = @{ @"room_id" : event.roomId }; + + [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; + } + + dispatch_block_t completionBlock = [weakSelf createPushNotificationHandlingStateCleaningBlock]; + weakSelf.pushNotificationHandlingCompletionBlock = completionBlock; + + // This delay will help us to process push events which we receive earlier than push notifications associated with them + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + completionBlock(); + }); + }; + + weakNotificationsListenerBlock = notificationsListenerBlock; + self.notificationListenerBlock = notificationsListenerBlock; + + [session.notificationCenter listenToNotifications:notificationsListenerBlock]; + + // Run timeout block + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(120.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + timeoutBlock(); + }); +} + +/** + Create and return a block which clean all state associated wiht push notifications handling + */ +- (dispatch_block_t)createPushNotificationHandlingStateCleaningBlock +{ + __weak typeof(self) weakSelf = self; + MXSession *session = mxSessionArray.firstObject; + + return dispatch_block_create(0, ^{ + [session.notificationCenter removeListener:weakSelf.notificationListenerBlock]; + + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; + + NSUInteger identifier = weakSelf.pushNotificationHandlingTaskIdentifier; + + weakSelf.handlingPushNotification = NO; + weakSelf.pushNotificationHandlingTaskIdentifier = [handler invalidIdentifier]; + + weakSelf.notificationListenerBlock = nil; + weakSelf.pushNotificationHandlingTimeoutBlock = nil; + weakSelf.pushNotificationHandlingCompletionBlock = nil; + + [handler endBackgrounTaskWithIdentifier:identifier]; + }); +} + +- (nullable NSString *)notificationBodyForEvent:(MXEvent *)event inDirectRoom:(BOOL)isDirect withRoomState:(MXRoomState *)roomState +{ + if (!event.content || !event.content.count) + return nil; + + NSString *notificationBody; + NSString *eventSenderName = [roomState memberName:event.sender]; + + if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted) + { + NSString *msgType = event.content[@"msgtype"]; + NSString *content = event.content[@"body"]; + + if (!isDirect) + { + NSString *roomDisplayName = roomState.displayname; + + if ([msgType isEqualToString:@"m.text"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM_WITH_CONTENT", nil), eventSenderName,roomDisplayName, content]; + else if ([msgType isEqualToString:@"m.emote"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content]; + else if ([msgType isEqualToString:@"m.image"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName]; + else + // Unencrypted messages falls here + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName]; + } + else + { + if ([msgType isEqualToString:@"m.text"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_WITH_CONTENT", nil), eventSenderName, content]; + else if ([msgType isEqualToString:@"m.emote"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content]; + else if ([msgType isEqualToString:@"m.image"]) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName]; + else + // Unencrypted messages falls here + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName]; + } + } + else if (event.eventType == MXEventTypeCallInvite) + { + NSString *sdp = event.content[@"offer"][@"sdp"]; + BOOL isVideoCall = [sdp rangeOfString:@"m=video"].location != NSNotFound; + + if (!isVideoCall) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VOICE_CALL_FROM_USER", nil), eventSenderName]; + else + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"VIDEO_CALL_FROM_USER", nil), eventSenderName]; + } + else if (event.eventType == MXEventTypeRoomMember) + { + NSString *roomName = roomState.name; + NSString *roomAlias = roomState.aliases.firstObject; + + if (roomName) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomName]; + else if (roomAlias) + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_NAMED_ROOM", nil), eventSenderName, roomAlias]; + else + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"USER_INVITE_TO_CHAT", nil), eventSenderName]; + } + + return notificationBody; } - (void)refreshApplicationIconBadgeNumber @@ -1730,7 +1870,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)logout { - [[UIApplication sharedApplication] unregisterForRemoteNotifications]; + self.pushRegistry = nil; isAPNSRegistered = NO; // Clear cache From 7a0a919651a8a58f828a0afea5920933767ac7aa Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 22 Aug 2017 10:46:53 +0300 Subject: [PATCH 15/58] Create app level category for MXSession to count missed notifications count --- Riot.xcodeproj/project.pbxproj | 6 +++ Riot/Categories/MXSession+Riot.h | 28 +++++++++++ Riot/Categories/MXSession+Riot.m | 51 ++++++++++++++++++++ Riot/ViewController/MasterTabBarController.m | 22 +-------- 4 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 Riot/Categories/MXSession+Riot.h create mode 100644 Riot/Categories/MXSession+Riot.m diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index c7682c902..8d78c98df 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; }; 32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; }; 32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; }; + 926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = 926FA53E1F4C132000F826C2 /* MXSession+Riot.m */; }; E2EAC1A4FBD6FE5228584591 /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D8737F782E108CFD6908691 /* libPods-Riot.a */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F02C1A861E8EB04C0045A404 /* PeopleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F02C1A841E8EB04C0045A404 /* PeopleViewController.m */; }; @@ -545,6 +546,8 @@ 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = ""; }; 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = ""; }; 7D8737F782E108CFD6908691 /* libPods-Riot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Riot.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 926FA53D1F4C132000F826C2 /* MXSession+Riot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MXSession+Riot.h"; sourceTree = ""; }; + 926FA53E1F4C132000F826C2 /* MXSession+Riot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MXSession+Riot.m"; sourceTree = ""; }; F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = ""; }; F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = ""; }; F02C1A831E8EB04C0045A404 /* PeopleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeopleViewController.h; sourceTree = ""; }; @@ -1521,6 +1524,8 @@ F083BBEA1E7009EC00A9B29C /* UINavigationController+Riot.m */, F083BBEB1E7009EC00A9B29C /* UIViewController+RiotSearch.h */, F083BBEC1E7009EC00A9B29C /* UIViewController+RiotSearch.m */, + 926FA53D1F4C132000F826C2 /* MXSession+Riot.h */, + 926FA53E1F4C132000F826C2 /* MXSession+Riot.m */, ); path = Categories; sourceTree = ""; @@ -2668,6 +2673,7 @@ F083BDF81E7009ED00A9B29C /* RoomDataSource.m in Sources */, F083BE371E7009ED00A9B29C /* RoomActivitiesView.m in Sources */, F083BE131E7009ED00A9B29C /* HomeMessagesSearchViewController.m in Sources */, + 926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */, F083BE8C1E7009ED00A9B29C /* PreviewRoomTitleView.m in Sources */, F083BE271E7009ED00A9B29C /* SettingsViewController.m in Sources */, F083BE9A1E7009ED00A9B29C /* TableViewCellWithButton.m in Sources */, diff --git a/Riot/Categories/MXSession+Riot.h b/Riot/Categories/MXSession+Riot.h new file mode 100644 index 000000000..9bc296a98 --- /dev/null +++ b/Riot/Categories/MXSession+Riot.h @@ -0,0 +1,28 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +#import + +@interface MXSession (Riot) + +/** + The current number of rooms with missed notifications, including the invites. + */ +- (NSUInteger)riot_missedDiscussionsCount; + +@end diff --git a/Riot/Categories/MXSession+Riot.m b/Riot/Categories/MXSession+Riot.m new file mode 100644 index 000000000..3d8805b5e --- /dev/null +++ b/Riot/Categories/MXSession+Riot.m @@ -0,0 +1,51 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXSession+Riot.h" + +#import "MXRoom+Riot.h" + +@implementation MXSession (Riot) + +- (NSUInteger)riot_missedDiscussionsCount +{ + NSUInteger missedDiscussionsCount = 0; + + // Sum all the rooms with missed notifications. + for (MXRoomSummary *roomSummary in self.roomsSummaries) + { + NSUInteger notificationCount = roomSummary.notificationCount; + + // Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level. + if (roomSummary.room.isMentionsOnly) + { + // Only the highlighted missed messages must be considered here. + notificationCount = roomSummary.highlightCount; + } + + if (notificationCount) + { + missedDiscussionsCount++; + } + } + + // Add the invites count + missedDiscussionsCount += [self invitedRooms].count; + + return missedDiscussionsCount; +} + +@end diff --git a/Riot/ViewController/MasterTabBarController.m b/Riot/ViewController/MasterTabBarController.m index 7f4f48b9b..d2da007be 100644 --- a/Riot/ViewController/MasterTabBarController.m +++ b/Riot/ViewController/MasterTabBarController.m @@ -23,6 +23,7 @@ #import "AppDelegate.h" #import "MXRoom+Riot.h" +#import "MXSession+Riot.h" @interface MasterTabBarController () { @@ -424,26 +425,7 @@ // Considering all the current sessions. for (MXSession *session in mxSessionArray) { - // Sum all the rooms with missed notifications. - for (MXRoomSummary *roomSummary in session.roomsSummaries) - { - NSUInteger notificationCount = roomSummary.notificationCount; - - // Ignore the regular notification count if the room is in 'mentions only" mode at the Riot level. - if (roomSummary.room.isMentionsOnly) - { - // Only the highlighted missed messages must be considered here. - notificationCount = roomSummary.highlightCount; - } - - if (notificationCount) - { - roomCount ++; - } - } - - // Add the invites count - roomCount += [session invitedRooms].count; + roomCount += [session riot_missedDiscussionsCount]; } return roomCount; From 216696887a9412fdb758988c466e85488f59def1 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 22 Aug 2017 10:48:59 +0300 Subject: [PATCH 16/58] Update app icon badge number on each received push notification --- Riot/AppDelegate.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 3c085c363..e3b87eb0d 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -43,6 +43,8 @@ #import "CallViewController.h" +#import "MXSession+Riot.h" + //#define MX_CALL_STACK_OPENWEBRTC #ifdef MX_CALL_STACK_OPENWEBRTC #import @@ -1052,6 +1054,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; } + // Update icon badge number + [UIApplication sharedApplication].applicationIconBadgeNumber = [session riot_missedDiscussionsCount]; + dispatch_block_t completionBlock = [weakSelf createPushNotificationHandlingStateCleaningBlock]; weakSelf.pushNotificationHandlingCompletionBlock = completionBlock; From c6f13b3729104caedfc46717948c5a350d4a5bc2 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 22 Aug 2017 11:10:35 +0300 Subject: [PATCH 17/58] Move code for updating icon badge number to completion block --- Riot/AppDelegate.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index e3b87eb0d..65bb292b0 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1054,9 +1054,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; } - // Update icon badge number - [UIApplication sharedApplication].applicationIconBadgeNumber = [session riot_missedDiscussionsCount]; - dispatch_block_t completionBlock = [weakSelf createPushNotificationHandlingStateCleaningBlock]; weakSelf.pushNotificationHandlingCompletionBlock = completionBlock; @@ -1088,6 +1085,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN return dispatch_block_create(0, ^{ [session.notificationCenter removeListener:weakSelf.notificationListenerBlock]; + // Update icon badge number + [UIApplication sharedApplication].applicationIconBadgeNumber = [session riot_missedDiscussionsCount]; + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; NSUInteger identifier = weakSelf.pushNotificationHandlingTaskIdentifier; From fb57b024ce448a92e8152f18f86b2246a4b27737 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 22 Aug 2017 12:05:28 +0300 Subject: [PATCH 18/58] Check available notification types before starting register on PushKit notifications --- Riot/AppDelegate.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 65bb292b0..12dd507cb 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -891,6 +891,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { + if (notificationSettings.types == UIUserNotificationTypeNone) + return; + self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil]; self.pushRegistry.delegate = self; self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; @@ -937,7 +940,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"[AppDelegate] didReceiveLocalNotification : no linked session / account has been found."); } } - } - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type From 32caf1951f6ef8aa4507ab6989128d5ecf19b81f Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 22 Aug 2017 16:02:16 +0300 Subject: [PATCH 19/58] Add Intents handling --- Riot/AppDelegate.m | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 705825569..b693cf159 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -17,6 +17,8 @@ #import "AppDelegate.h" +#import + #import "RecentsDataSource.h" #import "RoomDataSource.h" @@ -526,6 +528,41 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { continueUserActivity = [self handleUniversalLink:userActivity]; } + else if ([userActivity.activityType isEqualToString:INStartAudioCallIntentIdentifier] || + [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier]) + { + INInteraction *interaction = userActivity.interaction; + + // roomID provided by Siri intent + NSString *roomID = userActivity.userInfo[@"roomID"]; + + // We've launched from calls history list + if (!roomID) + { + INPerson *person; + + if ([interaction.intent isKindOfClass:INStartAudioCallIntent.class]) + { + person = [[(INStartAudioCallIntent *)(interaction.intent) contacts] firstObject]; + } + else if ([interaction.intent isKindOfClass:INStartVideoCallIntent.class]) + { + person = [[(INStartVideoCallIntent *)(interaction.intent) contacts] firstObject]; + } + + roomID = person.personHandle.value; + } + + BOOL isVideoCall = [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier]; + + MXSession *session = mxSessionArray.firstObject; + [session.callManager placeCallInRoom:roomID + withVideo:isVideoCall + success:^(MXCall *call) {} + failure:^(NSError *error) {}]; + + continueUserActivity = YES; + } return continueUserActivity; } From 4b0a88d6c9ad82315f3e6c6a2216a7cc2be25b3a Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Wed, 23 Aug 2017 12:53:32 +0300 Subject: [PATCH 20/58] Add new option to notification settings --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/ViewController/SettingsViewController.m | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6c73d198d..33f2aece5 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -327,6 +327,7 @@ "settings_fail_to_update_profile" = "Fail to update profile"; "settings_enable_push_notif" = "Notifications on this device"; +"settings_show_decrypted_content" = "Show decrypted content"; "settings_global_settings_info" = "Global notification settings are available on your %@ web client"; "settings_pin_rooms_with_missed_notif" = "Pin rooms with missed notifications"; "settings_pin_rooms_with_unread" = "Pin rooms with unread messages"; diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index dfc8ad67d..5d66e5882 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -62,6 +62,7 @@ enum enum { NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0, + NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT, NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX, NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX, NOTIFICATION_SETTINGS_PIN_UNREAD_INDEX, @@ -1613,6 +1614,18 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); cell = labelAndSwitchCell; } + else if (row == NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT) + { + MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + + labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil); + labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications; + labelAndSwitchCell.mxkSwitch.enabled = account.pushNotificationServiceIsActive; + [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged]; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventValueChanged]; + + cell = labelAndSwitchCell; + } else if (row == NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX) { MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView]; @@ -2601,6 +2614,12 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } +- (void)toggleShowDecodedContent:(id)sender +{ + MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + account.showDecryptedContentInNotifications = !account.showDecryptedContentInNotifications; +} + - (void)toggleLocalContactsSync:(id)sender { UISwitch *switchButton = (UISwitch*)sender; From 576466bb1373ae376fa86a4a76bb066f8ca809b8 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Thu, 24 Aug 2017 14:03:05 +0300 Subject: [PATCH 21/58] Add background mode handling --- Riot/AppDelegate.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index b693cf159..8466b4769 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1792,6 +1792,36 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN currentCallViewController.mxCall = mxCall; currentCallViewController.delegate = self; + UIApplicationState applicationState = UIApplication.sharedApplication.applicationState; + + // App has been woken by PushKit notification in the background + if (applicationState == UIApplicationStateBackground && mxCall.isIncoming) + { + // Create backgound task. + // Without CallKit this will allow us to play vibro until the call was ended + // With CallKit we'll inform the system when the call is ended to let the system terminate our app to save resources + id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; + NSUInteger callTaskIdentifier = [handler startBackgroundTaskWithName:nil completion:^{}]; + + // Start listening for call state change notifications + __weak NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + __block id token = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallStateDidChange + object:mxCall + queue:nil + usingBlock:^(NSNotification * _Nonnull note) { + MXCall *call = (MXCall *)note.object; + + if (call.state == MXCallStateEnded) + { + // Set call vc to nil to let our app handle new incoming calls even it wasn't killed by the system + currentCallViewController = nil; + [notificationCenter removeObserver:token]; + + [handler endBackgrounTaskWithIdentifier:callTaskIdentifier]; + } + }]; + } + if (mxCall.isIncoming && !isCallKitAvailable) { // Prompt user before presenting the call view controller From 6cff918820e4b3aff5f3bdcd01024ff926f018e3 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 25 Aug 2017 13:36:25 +0300 Subject: [PATCH 22/58] Change control event value --- Riot/ViewController/SettingsViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 5d66e5882..7ec1ad9b3 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -1621,8 +1621,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil); labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications; labelAndSwitchCell.mxkSwitch.enabled = account.pushNotificationServiceIsActive; - [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged]; - [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventValueChanged]; + [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventTouchUpInside]; cell = labelAndSwitchCell; } From 6679da2ed89d2dd65b63f0167952f9bd9e7ba30b Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Fri, 25 Aug 2017 23:43:38 +0300 Subject: [PATCH 23/58] Improvements in resolution process --- SiriIntents/IntentHandler.m | 122 ++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 34 deletions(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 0190db099..9a5c146d9 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -59,12 +59,19 @@ // so we just extract the first one INPerson *callee = contacts.firstObject; - // Check if the user has selected right callee among several candidates from previous resolution process run + // If this method is called after selection of the appropriate user, it will hold userId of an user to whom we must call + NSString *selectedUserId; + + // Check if the user has selected appropriate room among several candidates from previous resolution process run if (callee.customIdentifier && callee.customIdentifier.length) { completion(@[[INPersonResolutionResult successWithResolvedPerson:callee]]); return; } + else + { + selectedUserId = callee.personHandle.value; + } MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; if (account) @@ -72,61 +79,108 @@ MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:account.mxCredentials]; [fileStore asyncRoomsSummaries:^(NSArray * _Nonnull roomsSummaries) { - // Find all users with whom direct chats are existed - NSMutableSet *directUserIDs = [NSMutableSet set]; + // Contains userIds of all users with whom the current user has direct chats + NSMutableArray *directUserIds = [NSMutableArray array]; + + // Contains room summaries for all direct rooms connected with particular userId + NSMutableDictionary *> *roomSummaries = [NSMutableDictionary dictionary]; + for (MXRoomSummary *summary in roomsSummaries) { + // TODO: We also need to check if joined room members count equals 2 + // It is pointlessly to save rooms with 1 joined member or room with more than 2 joined members if (summary.isDirect) - [directUserIDs addObject:summary.directUserId]; + { + NSString *diretUserId = summary.directUserId; + + // Collect room summaries only for specified user + if (selectedUserId && ![diretUserId isEqualToString:selectedUserId]) + continue; + + // Save userId + [directUserIds addObject:diretUserId]; + + // Save associated with diretUserId room summary + NSMutableArray *userRoomSummaries = roomSummaries[diretUserId]; + if (userRoomSummaries) + [userRoomSummaries addObject:summary]; + else + roomSummaries[diretUserId] = [NSMutableArray arrayWithObject:summary]; + } } - [fileStore asyncUsers:^(NSArray * _Nonnull users) { + [fileStore UsersWithUserIds:directUserIds success:^(NSArray * _Nonnull users) { - // Find users with whom we have a direct chat and whose display name contains string presented us by Siri - NSMutableArray *matchingPersons = [NSMutableArray array]; + // Find users whose display name contains string presented us by Siri + NSMutableArray *matchingUsers = [NSMutableArray array]; for (MXUser *user in users) { - if ([directUserIDs containsObject:user.userId]) + if (!user.displayname) + continue; + + if (!NSEqualRanges([callee.displayName rangeOfString:user.displayname options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0})) { - if (!user.displayname) - continue; + [matchingUsers addObject:user]; + } + } + + NSMutableArray *persons = [NSMutableArray array]; + + if (matchingUsers.count == 1) + { + MXUser *user = matchingUsers.firstObject; + + // Provide to the user a list of direct rooms to choose from + NSArray *summaries = roomSummaries[user.userId]; + for (MXRoomSummary *summary in summaries) + { + INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; - if (!NSEqualRanges([user.displayname rangeOfString:callee.displayName options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0})) - { - INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; - INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle - nameComponents:nil - displayName:user.displayname - image:nil - contactIdentifier:nil - customIdentifier:user.userId]; - - [matchingPersons addObject:person]; - } + NSString *displayName = summary.displayname ? summary.displayname : user.displayname; + + INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle + nameComponents:nil + displayName:displayName + image:nil + contactIdentifier:nil + customIdentifier:summary.roomId]; + + [persons addObject:person]; + } + } + else if (matchingUsers.count > 1) + { + // Provide to the user a list of users to choose from + // This is the case when there are several users with the same name + for (MXUser *user in matchingUsers) + { + INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; + INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle + nameComponents:nil + displayName:user.displayname + image:nil + contactIdentifier:nil + customIdentifier:nil]; + + [persons addObject:person]; } } - if (matchingPersons.count == 0) + if (persons.count == 0) { completion(@[[INPersonResolutionResult unsupported]]); } - else if (matchingPersons.count == 1) + else if (persons.count == 1) { - completion(@[[INPersonResolutionResult successWithResolvedPerson:matchingPersons.firstObject]]); + completion(@[[INPersonResolutionResult successWithResolvedPerson:persons.firstObject]]); } else { - completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:matchingPersons]]); + completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:persons]]); } - - } failure:nil]; + }]; } failure:nil]; } - else - { - // If user hasn't logged in yet just pass a blank INPerson instance and handle this situation in confirmStartAudioCall:completion: - completion(@[[INPersonResolutionResult successWithResolvedPerson:[INPerson new]]]); - } } } @@ -161,7 +215,7 @@ if (person && person.customIdentifier) { NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; - userActivity.userInfo = @{ @"userID" : person.customIdentifier }; + userActivity.userInfo = @{ @"roomID" : person.customIdentifier }; response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp userActivity:userActivity]; From 3569917571b2d2ba6dd39ae4375d4fac535feb67 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:03:32 +0300 Subject: [PATCH 24/58] Handle multiple contacts passed to intent --- SiriIntents/IntentHandler.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 9a5c146d9..48a7d41d5 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -65,7 +65,14 @@ // Check if the user has selected appropriate room among several candidates from previous resolution process run if (callee.customIdentifier && callee.customIdentifier.length) { - completion(@[[INPersonResolutionResult successWithResolvedPerson:callee]]); + // If callee will have the same name as one of the contact in the system contacts app + // Siri will pass us this contact in the intent.contacts array and we must provide the same count of + // resolution results as elements count in the intent.contact. + // So we just pass the same result at all iterations + NSMutableArray *resolutionResults = [NSMutableArray array]; + for (NSInteger i = 0; i < contacts.count; ++i) + [resolutionResults addObject:[INPersonResolutionResult successWithResolvedPerson:callee]]; + completion(resolutionResults); return; } else From 636cfbda8cc721c7fc425926cc87840c85c4fd2d Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:11:03 +0300 Subject: [PATCH 25/58] Update comments --- SiriIntents/IntentHandler.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 48a7d41d5..a455a82f4 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -62,7 +62,7 @@ // If this method is called after selection of the appropriate user, it will hold userId of an user to whom we must call NSString *selectedUserId; - // Check if the user has selected appropriate room among several candidates from previous resolution process run + // Check if the user has selected right room among several direct rooms from previous resolution process run if (callee.customIdentifier && callee.customIdentifier.length) { // If callee will have the same name as one of the contact in the system contacts app @@ -77,6 +77,7 @@ } else { + // This resolution process run after selecting appropriate user among suggested user list selectedUserId = callee.personHandle.value; } @@ -143,6 +144,7 @@ { INPersonHandle *personHandle = [[INPersonHandle alloc] initWithValue:user.userId type:INPersonHandleTypeUnknown]; + // For rooms we try to use room display name NSString *displayName = summary.displayname ? summary.displayname : user.displayname; INPerson *person = [[INPerson alloc] initWithPersonHandle:personHandle From e0d838cab3bf819af449f805725c2da2bea3d4a6 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:14:18 +0300 Subject: [PATCH 26/58] Use set for directUserIds --- SiriIntents/IntentHandler.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index a455a82f4..ed50d2cb6 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -88,7 +88,8 @@ [fileStore asyncRoomsSummaries:^(NSArray * _Nonnull roomsSummaries) { // Contains userIds of all users with whom the current user has direct chats - NSMutableArray *directUserIds = [NSMutableArray array]; + // Use set to avoid duplicates + NSMutableSet *directUserIds = [NSMutableSet set]; // Contains room summaries for all direct rooms connected with particular userId NSMutableDictionary *> *roomSummaries = [NSMutableDictionary dictionary]; @@ -117,7 +118,7 @@ } } - [fileStore UsersWithUserIds:directUserIds success:^(NSArray * _Nonnull users) { + [fileStore UsersWithUserIds:directUserIds.allObjects success:^(NSArray * _Nonnull users) { // Find users whose display name contains string presented us by Siri NSMutableArray *matchingUsers = [NSMutableArray array]; From 54fc9b669d57e583e2b9e5cbfd6ea92fa8223ea1 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:19:59 +0300 Subject: [PATCH 27/58] Fix method name --- SiriIntents/IntentHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index ed50d2cb6..d4b97acdb 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -118,7 +118,7 @@ } } - [fileStore UsersWithUserIds:directUserIds.allObjects success:^(NSArray * _Nonnull users) { + [fileStore asyncUsersWithUserIds:directUserIds.allObjects success:^(NSArray * _Nonnull users) { // Find users whose display name contains string presented us by Siri NSMutableArray *matchingUsers = [NSMutableArray array]; From 9e83f5d1ef1df6f42a7ad69b6651127948b47700 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:32:12 +0300 Subject: [PATCH 28/58] Change application group id --- Riot/AppDelegate.m | 2 +- SiriIntents/IntentHandler.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 63a6e687a..da95f73e2 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1448,7 +1448,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN sdkOptions.backgroundModeHandler = [[MXUIKitBackgroundModeHandler alloc] init]; // Use shared container to share data with app extensions - sdkOptions.applicationGroupIdentifier = @"group.org.matrix"; + sdkOptions.applicationGroupIdentifier = @"group.im.vector"; // Disable long press on event in bubble cells [MXKRoomBubbleTableViewCell disableLongPressGestureOnEvent:YES]; diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index d4b97acdb..53bea36c0 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -32,7 +32,7 @@ self = [super init]; if (self) { - [MXSDKOptions sharedInstance].applicationGroupIdentifier = @"group.org.matrix"; + [MXSDKOptions sharedInstance].applicationGroupIdentifier = @"group.im.vector"; } return self; } From b4dc36bbb43f91a54e0281100e9edb0de774913a Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:40:40 +0300 Subject: [PATCH 29/58] Update entitlements --- Riot/Riot.entitlements | 2 +- SiriIntents/SiriIntents.entitlements | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Riot.entitlements b/Riot/Riot.entitlements index 4094cf66e..edee34b65 100644 --- a/Riot/Riot.entitlements +++ b/Riot/Riot.entitlements @@ -15,7 +15,7 @@ com.apple.security.application-groups - group.org.matrix + group.im.vector diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index 95ba9ff62..e540aaaec 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.org.matrix + group.im.vector From 05850d28f9520468cfb084a2c908ce942c713c8c Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 15:41:15 +0300 Subject: [PATCH 30/58] Update Siri usage description --- Riot/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Info.plist b/Riot/Info.plist index fde652af4..10aa3a880 100644 --- a/Riot/Info.plist +++ b/Riot/Info.plist @@ -50,7 +50,7 @@ NSPhotoLibraryUsageDescription The photo library is used to send photos and videos. NSSiriUsageDescription - Use Siri to make calls + Siri is used to perform calls even from the lock screen UIBackgroundModes audio From 71b56c044180b812fdad66a5c7b6787a97ea2ab6 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 16:04:31 +0300 Subject: [PATCH 31/58] Update Podfile --- Podfile | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Podfile b/Podfile index dee294bb5..bc29ced59 100644 --- a/Podfile +++ b/Podfile @@ -5,10 +5,9 @@ source 'https://github.com/CocoaPods/Specs.git' target "Riot" do - # Different flavours of pods to MatrixKit # The tagged version on which this version of Riot has been built -pod 'MatrixKit', '0.5.2' +pod 'MatrixKit', '0.6.2' # The lastest release available on the CocoaPods repository #pod 'MatrixKit' @@ -41,3 +40,33 @@ pod 'DTCoreText', :inhibit_warnings => true end +target "SiriIntents" do + +pod 'GoogleAnalytics' +# The Google WebRTC stack +pod 'WebRTC', '58.17.16937' +# OLMKit for crypto +pod 'OLMKit' +#pod 'OLMKit', :path => '../olm/OLMKit.podspec' +pod 'Realm', '~> 2.8.1' + +# The tagged version on which this version of Riot share extension has been built +pod 'MatrixKit/AppExtension', '0.6.2' + +# The lastest release available on the CocoaPods repository +#pod 'MatrixKit/AppExtension' + +# The develop branch version +#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop' +#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'develop' + +# The one used for developing both MatrixSDK and MatrixKit +# Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder +#pod 'MatrixSDK', :path => '../matrix-ios-sdk/MatrixSDK.podspec' +#pod 'MatrixKit/AppExtension', :path => '../matrix-ios-kit/MatrixKit.podspec' + +# Remove warnings from "bad" pods +pod 'OLMKit', :inhibit_warnings => true +pod 'cmark', :inhibit_warnings => true + +end From a27f8372682d49185547f57afc3c566c510c0bc6 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 16:35:35 +0300 Subject: [PATCH 32/58] Update async method signature --- SiriIntents/IntentHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 53bea36c0..8ccd42f5d 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -188,7 +188,7 @@ { completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:persons]]); } - }]; + } failure:nil]; } failure:nil]; } } From 5ad000f65940251a304e4c36ed1805af9f75d70b Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sat, 26 Aug 2017 17:46:12 +0300 Subject: [PATCH 33/58] Add video calls support --- SiriIntents/Info.plist | 1 + SiriIntents/IntentHandler.m | 149 +++++++++++++++++++++++++----------- 2 files changed, 104 insertions(+), 46 deletions(-) diff --git a/SiriIntents/Info.plist b/SiriIntents/Info.plist index 87df545b8..9fa5f075e 100644 --- a/SiriIntents/Info.plist +++ b/SiriIntents/Info.plist @@ -29,6 +29,7 @@ IntentsSupported INStartAudioCallIntent + INStartVideoCallIntent NSExtensionPointIdentifier diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 8ccd42f5d..8b561895b 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -21,7 +21,7 @@ #import "MXFileStore.h" #import "MXSession.h" -@interface IntentHandler () +@interface IntentHandler () @end @@ -46,7 +46,108 @@ - (void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent withCompletion:(void (^)(NSArray * _Nonnull))completion { - NSArray *contacts = intent.contacts; + [self resolveContacts:intent.contacts withCompletion:completion]; +} + +- (void)confirmStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion +{ + INStartAudioCallIntentResponse *response = nil; + + MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + if (account) + { +#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity]; +#else + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; +#endif + } + else + { + // User hasn't logged in + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]; + } + + completion(response); +} + +- (void)handleStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion +{ + INStartAudioCallIntentResponse *response = nil; + + INPerson *person = intent.contacts.firstObject; + if (person && person.customIdentifier) + { + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; + userActivity.userInfo = @{ @"roomID" : person.customIdentifier }; + + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp + userActivity:userActivity]; + } + else + { + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailure userActivity:nil]; + } + + completion(response); +} + +#pragma mark - INStartVideoCallIntentHandling + +- (void)resolveContactsForStartVideoCall:(INStartVideoCallIntent *)intent withCompletion:(void (^)(NSArray * _Nonnull))completion +{ + [self resolveContacts:intent.contacts withCompletion:completion]; +} + +- (void)confirmStartVideoCall:(INStartVideoCallIntent *)intent completion:(void (^)(INStartVideoCallIntentResponse * _Nonnull))completion +{ + INStartVideoCallIntentResponse *response = nil; + + MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + if (account) + { +#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartVideoCallIntent.class)]; + response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeReady userActivity:userActivity]; +#else + response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; +#endif + } + else + { + // User hasn't logged in + response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]; + } + + completion(response); +} + +- (void)handleStartVideoCall:(INStartVideoCallIntent *)intent completion:(void (^)(INStartVideoCallIntentResponse * _Nonnull))completion +{ + INStartVideoCallIntentResponse *response = nil; + + INPerson *person = intent.contacts.firstObject; + if (person && person.customIdentifier) + { + NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartVideoCallIntent.class)]; + userActivity.userInfo = @{ @"roomID" : person.customIdentifier }; + + response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeContinueInApp + userActivity:userActivity]; + } + else + { + response = [[INStartVideoCallIntentResponse alloc] initWithCode:INStartVideoCallIntentResponseCodeFailure userActivity:nil]; + } + + completion(response); +} + +#pragma mark - Private + +- (void)resolveContacts:(nullable NSArray *)contacts withCompletion:(void (^)(NSArray * _Nonnull))completion +{ if (contacts.count == 0) { completion(@[[INPersonResolutionResult needsValue]]); @@ -194,48 +295,4 @@ } } -- (void)confirmStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion -{ - INStartAudioCallIntentResponse *response = nil; - - MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject; - if (account) - { -#if defined MX_CALL_STACK_OPENWEBRTC || defined MX_CALL_STACK_ENDPOINT || defined MX_CALL_STACK_JINGLE - NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeReady userActivity:userActivity]; -#else - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureCallingServiceNotAvailable userActivity:nil]; -#endif - } - else - { - // User hasn't logged in - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]; - } - - completion(response); -} - -- (void)handleStartAudioCall:(INStartAudioCallIntent *)intent completion:(void (^)(INStartAudioCallIntentResponse * _Nonnull))completion -{ - INStartAudioCallIntentResponse *response = nil; - - INPerson *person = intent.contacts.firstObject; - if (person && person.customIdentifier) - { - NSUserActivity *userActivity = [[NSUserActivity alloc] initWithActivityType:NSStringFromClass(INStartAudioCallIntent.class)]; - userActivity.userInfo = @{ @"roomID" : person.customIdentifier }; - - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeContinueInApp - userActivity:userActivity]; - } - else - { - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailure userActivity:nil]; - } - - completion(response); -} - @end From 1aee1d02c43d621f9a3219b7f7365144dfc4c01d Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 28 Aug 2017 18:14:10 +0300 Subject: [PATCH 34/58] Start background task when handling call intent in the background --- Riot/AppDelegate.m | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 8466b4769..b4bc70d98 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -555,11 +555,37 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN BOOL isVideoCall = [userActivity.activityType isEqualToString:INStartVideoCallIntentIdentifier]; + UIApplication *application = UIApplication.sharedApplication; + NSNumber *backgroundTaskIdentifier; + + // Start background task since we need time for MXSession preparasion because our app can be launched in the background + if (application.applicationState == UIApplicationStateBackground) + backgroundTaskIdentifier = @([application beginBackgroundTaskWithExpirationHandler:^{}]); + MXSession *session = mxSessionArray.firstObject; [session.callManager placeCallInRoom:roomID withVideo:isVideoCall - success:^(MXCall *call) {} - failure:^(NSError *error) {}]; + success:^(MXCall *call) { + if (application.applicationState == UIApplicationStateBackground) + { + __weak NSNotificationCenter *center = NSNotificationCenter.defaultCenter; + __block id token = + [center addObserverForName:kMXCallStateDidChange + object:call + queue:nil + usingBlock:^(NSNotification * _Nonnull note) { + if (call.state == MXCallStateEnded) + { + [application endBackgroundTask:backgroundTaskIdentifier.unsignedIntegerValue]; + [center removeObserver:token]; + } + }]; + } + } + failure:^(NSError *error) { + if (backgroundTaskIdentifier) + [application endBackgroundTask:backgroundTaskIdentifier.unsignedIntegerValue]; + }]; continueUserActivity = YES; } From 7f0832185bd3c3aead2a15ebd1f5ff3abf22aca0 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Tue, 29 Aug 2017 11:50:22 +0300 Subject: [PATCH 35/58] Add content to notification body connected with image --- Riot/AppDelegate.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 12dd507cb..b9dd9bf2f 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1127,7 +1127,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN else if ([msgType isEqualToString:@"m.emote"]) notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER_IN_ROOM", nil), roomDisplayName, eventSenderName, content]; else if ([msgType isEqualToString:@"m.image"]) - notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName]; + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName]; else // Unencrypted messages falls here notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName]; @@ -1139,7 +1139,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN else if ([msgType isEqualToString:@"m.emote"]) notificationBody = [NSString stringWithFormat:NSLocalizedString(@"ACTION_FROM_USER", nil), eventSenderName, content]; else if ([msgType isEqualToString:@"m.image"]) - notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName]; + notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content]; else // Unencrypted messages falls here notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName]; From dc53ef495d159c92bd470bc9851f6b6b8f7b38ec Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 22 Aug 2017 14:22:46 +0300 Subject: [PATCH 36/58] Don't show display notifications for call invites when CallKit is active --- Riot/AppDelegate.m | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index b9dd9bf2f..3e4d79559 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1044,16 +1044,22 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN weakSelf.pushNotificationHandlingCompletionBlock = nil; } - BOOL isEventRoomDirect = [session roomWithRoomId:event.roomId].isDirect; - NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; - if (notificationBody) + // For all type of event show local notifications besides the situation + // when the type of event is call invite and we have CallKit support + BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled; + if (!(event.eventType == MXEventTypeCallInvite && isCallKitActive)) { - UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; - eventNotification.fireDate = [NSDate date]; - eventNotification.alertBody = notificationBody; - eventNotification.userInfo = @{ @"room_id" : event.roomId }; - - [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; + BOOL isEventRoomDirect = [session roomWithRoomId:event.roomId].isDirect; + NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; + if (notificationBody) + { + UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; + eventNotification.fireDate = [NSDate date]; + eventNotification.alertBody = notificationBody; + eventNotification.userInfo = @{ @"room_id" : event.roomId }; + + [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; + } } dispatch_block_t completionBlock = [weakSelf createPushNotificationHandlingStateCleaningBlock]; From 12fa3d8a2af7d8028f166b51f6b42e22d261f9e0 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 22 Aug 2017 19:15:09 +0300 Subject: [PATCH 37/58] Set local notification sound --- Riot/AppDelegate.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 3e4d79559..c62d383bd 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1057,6 +1057,22 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN eventNotification.fireDate = [NSDate date]; eventNotification.alertBody = notificationBody; eventNotification.userInfo = @{ @"room_id" : event.roomId }; + + // Set sound name based on the value provided in action of MXPushRule + for (MXPushRuleAction *action in rule.actions) + { + if (action.actionType == MXPushRuleActionTypeSetTweak) + { + if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"]) + { + NSString *soundName = action.parameters[@"value"]; + if ([soundName isEqualToString:@"default"]) + soundName = UILocalNotificationDefaultSoundName; + + eventNotification.soundName = soundName; + } + } + } [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; } From 82810f9c17ba5c8b9e97b8d53da8c8ee5f294823 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Wed, 23 Aug 2017 12:53:32 +0300 Subject: [PATCH 38/58] Add new option to notification settings --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/ViewController/SettingsViewController.m | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 3fbf71646..bed104ea3 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -318,6 +318,7 @@ "settings_fail_to_update_profile" = "Fail to update profile"; "settings_enable_push_notif" = "Notifications on this device"; +"settings_show_decrypted_content" = "Show decrypted content"; "settings_global_settings_info" = "Global notification settings are available on your %@ web client"; "settings_pin_rooms_with_missed_notif" = "Pin rooms with missed notifications"; "settings_pin_rooms_with_unread" = "Pin rooms with unread messages"; diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index c2a2b7cad..08ed53408 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -58,6 +58,7 @@ enum enum { NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0, + NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT, NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX, NOTIFICATION_SETTINGS_PIN_MISSED_NOTIFICATIONS_INDEX, NOTIFICATION_SETTINGS_PIN_UNREAD_INDEX, @@ -1564,6 +1565,18 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); cell = labelAndSwitchCell; } + else if (row == NOTIFICATION_SETTINGS_SHOW_DECODED_CONTENT) + { + MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + + labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil); + labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications; + labelAndSwitchCell.mxkSwitch.enabled = account.pushNotificationServiceIsActive; + [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventValueChanged]; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventValueChanged]; + + cell = labelAndSwitchCell; + } else if (row == NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX) { MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView]; @@ -2509,6 +2522,12 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } +- (void)toggleShowDecodedContent:(id)sender +{ + MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + account.showDecryptedContentInNotifications = !account.showDecryptedContentInNotifications; +} + - (void)toggleLocalContactsSync:(id)sender { UISwitch *switchButton = (UISwitch*)sender; From bdd653c6594ddcac8d92072afcccaaea3bf29436 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Thu, 31 Aug 2017 11:11:09 +0300 Subject: [PATCH 39/58] Simplify customIdentifier check --- SiriIntents/IntentHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index 8b561895b..c21d84401 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -164,7 +164,7 @@ NSString *selectedUserId; // Check if the user has selected right room among several direct rooms from previous resolution process run - if (callee.customIdentifier && callee.customIdentifier.length) + if (callee.customIdentifier.length) { // If callee will have the same name as one of the contact in the system contacts app // Siri will pass us this contact in the intent.contacts array and we must provide the same count of From 5fcc0544761b55df529302d22e9a6ceff214aee9 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Thu, 31 Aug 2017 11:12:18 +0300 Subject: [PATCH 40/58] Update Siri usage description --- Riot/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Info.plist b/Riot/Info.plist index 10aa3a880..893054b9a 100644 --- a/Riot/Info.plist +++ b/Riot/Info.plist @@ -50,7 +50,7 @@ NSPhotoLibraryUsageDescription The photo library is used to send photos and videos. NSSiriUsageDescription - Siri is used to perform calls even from the lock screen + Siri is used to perform calls even from the lock screen. UIBackgroundModes audio From 49defaef8a55102556f82433e8f313a75a4ec8a8 Mon Sep 17 00:00:00 2001 From: manuroe Date: Thu, 31 Aug 2017 15:51:05 +0200 Subject: [PATCH 41/58] CallKit branch: fixed compilation issues --- Riot/AppDelegate.m | 2 ++ Riot/ViewController/SettingsViewController.m | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 26acf5497..47109d84d 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1983,6 +1983,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _incomingCallNotification = [UIAlertController alertControllerWithTitle:callPrompt message:nil preferredStyle:UIAlertControllerStyleAlert]; + + __weak typeof(self) weakSelf = self; [_incomingCallNotification addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil) style:UIAlertActionStyleDefault diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 38f44f36f..3858e6c01 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -25,6 +25,8 @@ #import "AppDelegate.h" #import "AvatarGenerator.h" + +#import "MXKEncryptionKeysExportView.h" #import "BugReportViewController.h" #import "WebViewViewController.h" From 074974a0da90bb4fe04d4fce434b77edb7608d6e Mon Sep 17 00:00:00 2001 From: manuroe Date: Thu, 31 Aug 2017 16:20:32 +0200 Subject: [PATCH 42/58] CallKit branch: fixed compilation issues --- Riot/AppDelegate.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index d4161f072..3ba39be57 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -175,6 +175,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } @property (strong, nonatomic) UIAlertController *mxInAppNotification; +@property (strong, nonatomic) UIAlertController *incomingCallNotification; @property (nonatomic, nullable, copy) void (^registrationForRemoteNotificationsCompletion)(NSError *); From ffdb866348e0e3c38b335873e07a20002a48f1b7 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 1 Sep 2017 10:38:54 +0200 Subject: [PATCH 43/58] Callkit branch: fix merge conflict --- Riot.xcodeproj/project.pbxproj | 341 +++++++++++++-------------------- 1 file changed, 132 insertions(+), 209 deletions(-) mode change 100644 => 100755 Riot.xcodeproj/project.pbxproj diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index bf2eaa8bc..554b4ceb1 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -27,7 +27,7 @@ 24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; }; 24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; }; 24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC111E7009EC00A9B29C /* AvatarGenerator.m */; }; - 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */ = {isa = PBXBuildFile; }; + 24EEE5A41F24C06E00B3C705 /* (null) in Resources */ = {isa = PBXBuildFile; }; 24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A121EDEE65000F5DC9A /* cancel@3x.png */; }; 24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A111EDEE65000F5DC9A /* cancel@2x.png */; }; 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A101EDEE65000F5DC9A /* cancel.png */; }; @@ -76,13 +76,11 @@ 32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; }; 32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; }; 32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; }; - 7A5A792D23877A47F33ADF07 /* libPods-SiriIntents.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */; }; - 9297595D1F2C8D4500535D3B /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9297595C1F2C8D4500535D3B /* Intents.framework */; }; - 92E963B51F28D907008FDAF5 /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92E963B41F28D907008FDAF5 /* IntentHandler.m */; }; - 92E963B91F28D907008FDAF5 /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92E963B11F28D906008FDAF5 /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - E2EAC1A4FBD6FE5228584591 /* libPods-Riot.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D8737F782E108CFD6908691 /* libPods-Riot.a */; }; 92324BE31F4F66D3009DE194 /* IncomingCallView.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE21F4F66D3009DE194 /* IncomingCallView.m */; }; 92324BE61F4F6A60009DE194 /* CircleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE51F4F6A60009DE194 /* CircleButton.m */; }; + 92726A471F58737A004AD26F /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92726A461F58737A004AD26F /* IntentHandler.m */; }; + 92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 92726A431F58737A004AD26F /* SiriIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 92726A511F587410004AD26F /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92726A501F587410004AD26F /* Intents.framework */; }; A27ECCE3FC4971745D2CB78D /* libPods-RiotShareExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */; }; F0131DE51F2200D600CBF707 /* RiotSplitViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */; }; F02C1A861E8EB04C0045A404 /* PeopleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F02C1A841E8EB04C0045A404 /* PeopleViewController.m */; }; @@ -532,13 +530,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 92E963B71F28D907008FDAF5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; - proxyType = 1; - remoteGlobalIDString = 92E963B01F28D906008FDAF5; - remoteInfo = SiriIntents; - }; 242661F51F12B1BA00D3FC08 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; @@ -546,6 +537,13 @@ remoteGlobalIDString = 24CBEC4D1F0EAD310093EABB; remoteInfo = "Riot Share Extension"; }; + 92726A491F58737A004AD26F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; + proxyType = 1; + remoteGlobalIDString = 92726A421F58737A004AD26F; + remoteInfo = SiriIntents; + }; F094A9BF1B78D8F000B1FBBF /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F094A99A1B78D8F000B1FBBF /* Project object */; @@ -556,17 +554,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 92E963BD1F28D907008FDAF5 /* Embed App Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - 92E963B91F28D907008FDAF5 /* SiriIntents.appex in Embed App Extensions */, - ); - name = "Embed App Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; 24CBEC5D1F0EAD310093EABB /* Embed App Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -574,10 +561,11 @@ dstSubfolderSpec = 13; files = ( 24CBEC591F0EAD310093EABB /* RiotShareExtension.appex in Embed App Extensions */, + 92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; - }; + }; 3233F7481F3497E2006ACA81 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -668,16 +656,6 @@ 32FD0A3A1EB0CD9B0072B066 /* BugReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugReportViewController.h; sourceTree = ""; }; 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = ""; }; 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = ""; }; - 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SiriIntents.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.debug.xcconfig"; sourceTree = ""; }; - 7D8737F782E108CFD6908691 /* libPods-Riot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Riot.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 9297595B1F2C8A9A00535D3B /* SiriIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SiriIntents.entitlements; sourceTree = ""; }; - 9297595C1F2C8D4500535D3B /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - 92E963B11F28D906008FDAF5 /* SiriIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SiriIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 92E963B31F28D907008FDAF5 /* IntentHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntentHandler.h; sourceTree = ""; }; - 92E963B41F28D907008FDAF5 /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = ""; }; - 92E963B61F28D907008FDAF5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.release.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.release.xcconfig"; sourceTree = ""; }; 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RiotShareExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotShareExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-RiotShareExtension/Pods-RiotShareExtension.release.xcconfig"; sourceTree = ""; }; 839BB91240D350D5607D55BA /* Pods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.debug.xcconfig"; sourceTree = ""; }; @@ -685,6 +663,12 @@ 92324BE21F4F66D3009DE194 /* IncomingCallView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IncomingCallView.m; sourceTree = ""; }; 92324BE41F4F6A60009DE194 /* CircleButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleButton.h; sourceTree = ""; }; 92324BE51F4F6A60009DE194 /* CircleButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleButton.m; sourceTree = ""; }; + 92726A431F58737A004AD26F /* SiriIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SiriIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 92726A451F58737A004AD26F /* IntentHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntentHandler.h; sourceTree = ""; }; + 92726A461F58737A004AD26F /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = ""; }; + 92726A481F58737A004AD26F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 92726A4F1F587393004AD26F /* SiriIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SiriIntents.entitlements; sourceTree = ""; }; + 92726A501F587410004AD26F /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.release.xcconfig"; sourceTree = ""; }; F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = ""; }; F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = ""; }; @@ -1262,15 +1246,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 92E963AE1F28D906008FDAF5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 9297595D1F2C8D4500535D3B /* Intents.framework in Frameworks */, - 7A5A792D23877A47F33ADF07 /* libPods-SiriIntents.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 24CBEC4B1F0EAD310093EABB /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1279,6 +1254,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 92726A401F58737A004AD26F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 92726A511F587410004AD26F /* Intents.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F094A99F1B78D8F000B1FBBF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1443,37 +1426,13 @@ 5FC42FA41F5186AFFB6A2404 /* Frameworks */ = { isa = PBXGroup; children = ( - 9297595C1F2C8D4500535D3B /* Intents.framework */, - 7D8737F782E108CFD6908691 /* libPods-Riot.a */, - 372FB22949C5652FF01D9793 /* libPods-SiriIntents.a */, + 92726A501F587410004AD26F /* Intents.framework */, FD9D0BDE9232898950554DD5 /* libPods-Riot.a */, 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */, ); name = Frameworks; sourceTree = ""; }; - 92E963B21F28D907008FDAF5 /* SiriIntents */ = { - isa = PBXGroup; - children = ( - 92E963B31F28D907008FDAF5 /* IntentHandler.h */, - 92E963B41F28D907008FDAF5 /* IntentHandler.m */, - 92E963B61F28D907008FDAF5 /* Info.plist */, - 9297595B1F2C8A9A00535D3B /* SiriIntents.entitlements */, - ); - path = SiriIntents; - sourceTree = ""; - }; - E1451F540F8BC02A7FB7AA31 /* Pods */ = { - isa = PBXGroup; - children = ( - 1129C74A281B080432B1A1A1 /* Pods-Riot.debug.xcconfig */, - F9D678EF54918C036FDEDBF9 /* Pods-Riot.release.xcconfig */, - 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */, - E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 7471DF3720D498384A068DA7 /* Pods */ = { isa = PBXGroup; children = ( @@ -1496,6 +1455,17 @@ path = Calls; sourceTree = ""; }; + 92726A441F58737A004AD26F /* SiriIntents */ = { + isa = PBXGroup; + children = ( + 92726A4F1F587393004AD26F /* SiriIntents.entitlements */, + 92726A451F58737A004AD26F /* IntentHandler.h */, + 92726A461F58737A004AD26F /* IntentHandler.m */, + 92726A481F58737A004AD26F /* Info.plist */, + ); + path = SiriIntents; + sourceTree = ""; + }; F083BB021E7005FD00A9B29C /* RiotTests */ = { isa = PBXGroup; children = ( @@ -2354,8 +2324,8 @@ children = ( F083BB081E7009EC00A9B29C /* Riot */, F083BB021E7005FD00A9B29C /* RiotTests */, - 92E963B21F28D907008FDAF5 /* SiriIntents */, 24CBEC4F1F0EAD310093EABB /* RiotShareExtension */, + 92726A441F58737A004AD26F /* SiriIntents */, F094A9A31B78D8F000B1FBBF /* Products */, 7471DF3720D498384A068DA7 /* Pods */, 5FC42FA41F5186AFFB6A2404 /* Frameworks */, @@ -2367,8 +2337,8 @@ children = ( F094A9A21B78D8F000B1FBBF /* Riot.app */, F094A9BE1B78D8F000B1FBBF /* RiotTests.xctest */, - 92E963B11F28D906008FDAF5 /* SiriIntents.appex */, 24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */, + 92726A431F58737A004AD26F /* SiriIntents.appex */, ); name = Products; sourceTree = ""; @@ -2386,25 +2356,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 92E963B01F28D906008FDAF5 /* SiriIntents */ = { - isa = PBXNativeTarget; - buildConfigurationList = 92E963BA1F28D907008FDAF5 /* Build configuration list for PBXNativeTarget "SiriIntents" */; - buildPhases = ( - B1481C3FD667495EEBD83C1D /* [CP] Check Pods Manifest.lock */, - 92E963AD1F28D906008FDAF5 /* Sources */, - 92E963AE1F28D906008FDAF5 /* Frameworks */, - 92E963AF1F28D906008FDAF5 /* Resources */, - D7AE9EDB223D9ED53DF15ABF /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SiriIntents; - productName = SiriIntents; - productReference = 92E963B11F28D906008FDAF5 /* SiriIntents.appex */; - productType = "com.apple.product-type.app-extension"; - }; 24CBEC4D1F0EAD310093EABB /* RiotShareExtension */ = { isa = PBXNativeTarget; buildConfigurationList = 24CBEC5C1F0EAD310093EABB /* Build configuration list for PBXNativeTarget "RiotShareExtension" */; @@ -2424,6 +2375,23 @@ productReference = 24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + 92726A421F58737A004AD26F /* SiriIntents */ = { + isa = PBXNativeTarget; + buildConfigurationList = 92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */; + buildPhases = ( + 92726A3F1F58737A004AD26F /* Sources */, + 92726A401F58737A004AD26F /* Frameworks */, + 92726A411F58737A004AD26F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SiriIntents; + productName = SiriIntents; + productReference = 92726A431F58737A004AD26F /* SiriIntents.appex */; + productType = "com.apple.product-type.app-extension"; + }; F094A9A11B78D8F000B1FBBF /* Riot */ = { isa = PBXNativeTarget; buildConfigurationList = F094A9C81B78D8F000B1FBBF /* Build configuration list for PBXNativeTarget "Riot" */; @@ -2432,9 +2400,6 @@ F094A99E1B78D8F000B1FBBF /* Sources */, F094A99F1B78D8F000B1FBBF /* Frameworks */, F094A9A01B78D8F000B1FBBF /* Resources */, - 44C35695CFA4F9799C449367 /* [CP] Copy Pods Resources */, - 381DA4CC07D2104BFA23E45A /* [CP] Embed Pods Frameworks */, - 92E963BD1F28D907008FDAF5 /* Embed App Extensions */, 24CBEC5D1F0EAD310093EABB /* Embed App Extensions */, 7FFD40AA75DB32D83350D225 /* [CP] Embed Pods Frameworks */, 68D6013FA64A4507DC9DB95B /* [CP] Copy Pods Resources */, @@ -2443,8 +2408,8 @@ buildRules = ( ); dependencies = ( - 92E963B81F28D907008FDAF5 /* PBXTargetDependency */, 242661F61F12B1BA00D3FC08 /* PBXTargetDependency */, + 92726A4A1F58737A004AD26F /* PBXTargetDependency */, ); name = Riot; productName = Vector; @@ -2478,16 +2443,6 @@ LastUpgradeCheck = 0800; ORGANIZATIONNAME = matrix.org; TargetAttributes = { - 92E963B01F28D906008FDAF5 = { - CreatedOnToolsVersion = 8.3.3; - DevelopmentTeam = 7J4U792NQT; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.ApplicationGroups.iOS = { - enabled = 1; - }; - }; - }; 24CBEC4D1F0EAD310093EABB = { CreatedOnToolsVersion = 8.3.2; DevelopmentTeam = 7J4U792NQT; @@ -2498,6 +2453,11 @@ }; }; }; + 92726A421F58737A004AD26F = { + CreatedOnToolsVersion = 8.3.3; + DevelopmentTeam = 7J4U792NQT; + ProvisioningStyle = Automatic; + }; F094A9A11B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; DevelopmentTeam = 7J4U792NQT; @@ -2509,9 +2469,6 @@ com.apple.Push = { enabled = 1; }; - com.apple.Siri = { - enabled = 1; - }; }; }; F094A9BD1B78D8F000B1FBBF = { @@ -2540,20 +2497,13 @@ targets = ( F094A9A11B78D8F000B1FBBF /* Riot */, F094A9BD1B78D8F000B1FBBF /* RiotTests */, - 92E963B01F28D906008FDAF5 /* SiriIntents */, 24CBEC4D1F0EAD310093EABB /* RiotShareExtension */, + 92726A421F58737A004AD26F /* SiriIntents */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 92E963AF1F28D906008FDAF5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 24CBEC4C1F0EAD310093EABB /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2569,7 +2519,14 @@ 24EEE5AF1F25F0F500B3C705 /* Images.xcassets in Resources */, 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */, 24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */, - 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */, + 24EEE5A41F24C06E00B3C705 /* (null) in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 92726A411F58737A004AD26F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3039,7 +2996,7 @@ "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleView.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/Search/MXKSearchTableViewCell.xib", - "$PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle", + $PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle, "${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld", ); name = "[CP] Copy Pods Resources"; @@ -3087,47 +3044,9 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RiotShareExtension/Pods-RiotShareExtension-resources.sh\"\n"; showEnvVarsInLog = 0; }; - B1481C3FD667495EEBD83C1D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; - showEnvVarsInLog = 0; - }; - D7AE9EDB223D9ED53DF15ABF /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 92E963AD1F28D906008FDAF5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 92E963B51F28D907008FDAF5 /* IntentHandler.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 24CBEC4A1F0EAD310093EABB /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3147,6 +3066,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 92726A3F1F58737A004AD26F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 92726A471F58737A004AD26F /* IntentHandler.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; F094A99E1B78D8F000B1FBBF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -3306,15 +3233,16 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 92E963B81F28D907008FDAF5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 92E963B01F28D906008FDAF5 /* SiriIntents */; - targetProxy = 92E963B71F28D907008FDAF5 /* PBXContainerItemProxy */; 242661F61F12B1BA00D3FC08 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 24CBEC4D1F0EAD310093EABB /* RiotShareExtension */; targetProxy = 242661F51F12B1BA00D3FC08 /* PBXContainerItemProxy */; }; + 92726A4A1F58737A004AD26F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 92726A421F58737A004AD26F /* SiriIntents */; + targetProxy = 92726A491F58737A004AD26F /* PBXContainerItemProxy */; + }; F094A9C01B78D8F000B1FBBF /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = F094A9A11B78D8F000B1FBBF /* Riot */; @@ -3454,26 +3382,6 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 92E963BB1F28D907008FDAF5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 47EC817AA9DA11B39694B1E0 /* Pods-SiriIntents.debug.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 7J4U792NQT; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = SiriIntents/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; 24CBEC5A1F0EAD310093EABB /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 12AA0005C8B3D8D8162584C5 /* Pods-RiotShareExtension.debug.xcconfig */; @@ -3496,27 +3404,6 @@ }; name = Debug; }; - 92E963BC1F28D907008FDAF5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = E22DCA997BE673CD67E839B9 /* Pods-SiriIntents.release.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 7J4U792NQT; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = SiriIntents/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; 24CBEC5B1F0EAD310093EABB /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */; @@ -3540,6 +3427,43 @@ }; name = Release; }; + 92726A4C1F58737A004AD26F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 7J4U792NQT; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = SiriIntents/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 92726A4D1F58737A004AD26F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 7J4U792NQT; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = SiriIntents/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; F094A9C61B78D8F000B1FBBF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3711,15 +3635,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 92E963BA1F28D907008FDAF5 /* Build configuration list for PBXNativeTarget "SiriIntents" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 92E963BB1F28D907008FDAF5 /* Debug */, - 92E963BC1F28D907008FDAF5 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 24CBEC5C1F0EAD310093EABB /* Build configuration list for PBXNativeTarget "RiotShareExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3729,6 +3644,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 92726A4C1F58737A004AD26F /* Debug */, + 92726A4D1F58737A004AD26F /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = { isa = XCConfigurationList; buildConfigurations = ( From 099049153181c48ad5cede518163895553820937 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 1 Sep 2017 15:43:18 +0200 Subject: [PATCH 44/58] Callkit branch: fix merge conflicts in pbxproj --- Riot.xcodeproj/project.pbxproj | 54 ++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 554b4ceb1..d5d661460 100755 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -27,7 +27,7 @@ 24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; }; 24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; }; 24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC111E7009EC00A9B29C /* AvatarGenerator.m */; }; - 24EEE5A41F24C06E00B3C705 /* (null) in Resources */ = {isa = PBXBuildFile; }; + 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */ = {isa = PBXBuildFile; }; 24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A121EDEE65000F5DC9A /* cancel@3x.png */; }; 24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A111EDEE65000F5DC9A /* cancel@2x.png */; }; 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A101EDEE65000F5DC9A /* cancel.png */; }; @@ -76,6 +76,7 @@ 32D392191EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32D392171EB9B7AB009A2BAF /* DirectoryServerDetailTableViewCell.xib */; }; 32FD0A3D1EB0CD9B0072B066 /* BugReportViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */; }; 32FD0A3E1EB0CD9B0072B066 /* BugReportViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */; }; + 714F6391AC0AA86C0AEB3F43 /* libPods-SiriIntents.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */; }; 92324BE31F4F66D3009DE194 /* IncomingCallView.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE21F4F66D3009DE194 /* IncomingCallView.m */; }; 92324BE61F4F6A60009DE194 /* CircleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE51F4F6A60009DE194 /* CircleButton.m */; }; 92726A471F58737A004AD26F /* IntentHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 92726A461F58737A004AD26F /* IntentHandler.m */; }; @@ -656,6 +657,9 @@ 32FD0A3A1EB0CD9B0072B066 /* BugReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugReportViewController.h; sourceTree = ""; }; 32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = ""; }; 32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = ""; }; + 397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.debug.xcconfig"; sourceTree = ""; }; + 4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SiriIntents.release.xcconfig"; path = "Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents.release.xcconfig"; sourceTree = ""; }; + 5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SiriIntents.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RiotShareExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotShareExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-RiotShareExtension/Pods-RiotShareExtension.release.xcconfig"; sourceTree = ""; }; 839BB91240D350D5607D55BA /* Pods-Riot.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Riot.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Riot/Pods-Riot.debug.xcconfig"; sourceTree = ""; }; @@ -1259,6 +1263,7 @@ buildActionMask = 2147483647; files = ( 92726A511F587410004AD26F /* Intents.framework in Frameworks */, + 714F6391AC0AA86C0AEB3F43 /* libPods-SiriIntents.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1429,6 +1434,7 @@ 92726A501F587410004AD26F /* Intents.framework */, FD9D0BDE9232898950554DD5 /* libPods-Riot.a */, 7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */, + 5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */, ); name = Frameworks; sourceTree = ""; @@ -1440,6 +1446,8 @@ C195C53961EA28E6900AEB68 /* Pods-Riot.release.xcconfig */, 12AA0005C8B3D8D8162584C5 /* Pods-RiotShareExtension.debug.xcconfig */, 765F5104DB3EC39713DEB3A4 /* Pods-RiotShareExtension.release.xcconfig */, + 397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */, + 4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -2379,9 +2387,11 @@ isa = PBXNativeTarget; buildConfigurationList = 92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */; buildPhases = ( + 6AA0024D4D5FAE30C2E1F311 /* [CP] Check Pods Manifest.lock */, 92726A3F1F58737A004AD26F /* Sources */, 92726A401F58737A004AD26F /* Frameworks */, 92726A411F58737A004AD26F /* Resources */, + 807A0ABF153A23C2FC22F977 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -2519,7 +2529,7 @@ 24EEE5AF1F25F0F500B3C705 /* Images.xcassets in Resources */, 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */, 24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */, - 24EEE5A41F24C06E00B3C705 /* (null) in Resources */, + 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2996,7 +3006,7 @@ "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleView.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/Search/MXKSearchTableViewCell.xib", - $PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle, + "$PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle", "${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld", ); name = "[CP] Copy Pods Resources"; @@ -3008,6 +3018,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Riot/Pods-Riot-resources.sh\"\n"; showEnvVarsInLog = 0; }; + 6AA0024D4D5FAE30C2E1F311 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-SiriIntents-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 7FFD40AA75DB32D83350D225 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3026,6 +3054,24 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Riot/Pods-Riot-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 807A0ABF153A23C2FC22F977 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh", + "${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SiriIntents/Pods-SiriIntents-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 8EA19F5011654D3BD5EDAC33 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3429,6 +3475,7 @@ }; 92726A4C1F58737A004AD26F /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 397BCA987893439918EBF330 /* Pods-SiriIntents.debug.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; @@ -3447,6 +3494,7 @@ }; 92726A4D1F58737A004AD26F /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4D1164C2F07EF74950DCDA7A /* Pods-SiriIntents.release.xcconfig */; buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; From 53d412d26cee40b8f86d1570389d49e6e44bf655 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 1 Sep 2017 16:42:58 +0200 Subject: [PATCH 45/58] Callkit branch: Siri: enable app group capabilities in Siri target --- Riot.xcodeproj/project.pbxproj | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index d5d661460..0c07f643d 100755 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -27,7 +27,7 @@ 24EEE5A11F23A09A00B3C705 /* RiotDesignValues.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC171E7009EC00A9B29C /* RiotDesignValues.m */; }; 24EEE5A21F23A8B400B3C705 /* MXRoom+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BBE81E7009EC00A9B29C /* MXRoom+Riot.m */; }; 24EEE5A31F23A8C300B3C705 /* AvatarGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = F083BC111E7009EC00A9B29C /* AvatarGenerator.m */; }; - 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */ = {isa = PBXBuildFile; }; + 24EEE5A41F24C06E00B3C705 /* (null) in Resources */ = {isa = PBXBuildFile; }; 24EEE5A81F25529600B3C705 /* cancel@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A121EDEE65000F5DC9A /* cancel@3x.png */; }; 24EEE5A91F25529900B3C705 /* cancel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A111EDEE65000F5DC9A /* cancel@2x.png */; }; 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = F0614A101EDEE65000F5DC9A /* cancel.png */; }; @@ -2467,6 +2467,11 @@ CreatedOnToolsVersion = 8.3.3; DevelopmentTeam = 7J4U792NQT; ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; + }; }; F094A9A11B78D8F000B1FBBF = { CreatedOnToolsVersion = 6.2; @@ -2529,7 +2534,7 @@ 24EEE5AF1F25F0F500B3C705 /* Images.xcassets in Resources */, 24EEE5AA1F25529C00B3C705 /* cancel.png in Resources */, 24D6B35E1F3CA03E00FC7A71 /* FallbackViewController.xib in Resources */, - 24EEE5A41F24C06E00B3C705 /* BuildFile in Resources */, + 24EEE5A41F24C06E00B3C705 /* (null) in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3006,7 +3011,7 @@ "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleView.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/RoomTitle/MXKRoomTitleViewWithTopic.xib", "${PODS_ROOT}/MatrixKit/MatrixKit/Views/Search/MXKSearchTableViewCell.xib", - "$PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle", + $PODS_CONFIGURATION_BUILD_DIR/MatrixKit/MatrixKit.bundle, "${PODS_ROOT}/MatrixSDK/MatrixSDK/Data/Store/MXCoreDataStore/MXCoreDataStore.xcdatamodeld", ); name = "[CP] Copy Pods Resources"; @@ -3480,6 +3485,7 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; @@ -3499,6 +3505,7 @@ CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_ENTITLEMENTS = SiriIntents/SiriIntents.entitlements; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 7J4U792NQT; @@ -3699,6 +3706,7 @@ 92726A4D1F58737A004AD26F /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = { isa = XCConfigurationList; From 0d62f6a8344a4b32089c4d3331d900c80512284d Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Fri, 1 Sep 2017 18:20:26 +0300 Subject: [PATCH 46/58] Handle situation with user that hasn't signed in yet --- SiriIntents/IntentHandler.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SiriIntents/IntentHandler.m b/SiriIntents/IntentHandler.m index c21d84401..5031ac70a 100644 --- a/SiriIntents/IntentHandler.m +++ b/SiriIntents/IntentHandler.m @@ -66,7 +66,7 @@ else { // User hasn't logged in - response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureRequiringAppLaunch userActivity:nil]; + response = [[INStartAudioCallIntentResponse alloc] initWithCode:INStartAudioCallIntentResponseCodeFailureAppConfigurationRequired userActivity:nil]; } completion(response); @@ -292,6 +292,10 @@ } failure:nil]; } failure:nil]; } + else + { + completion(@[[INPersonResolutionResult notRequired]]); + } } } From 4948efddb4990d3b16a7ac28a94286194bf4412b Mon Sep 17 00:00:00 2001 From: manuroe Date: Mon, 4 Sep 2017 16:47:43 +0200 Subject: [PATCH 47/58] Siri intents are available since 10.0 --- Riot.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index a53b7d157..a20a1b659 100755 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -3496,7 +3496,7 @@ DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; INFOPLIST_FILE = SiriIntents/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -3517,7 +3517,7 @@ DEVELOPMENT_TEAM = 7J4U792NQT; ENABLE_BITCODE = NO; INFOPLIST_FILE = SiriIntents/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 10.3; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.vector.app.SiriIntents; PRODUCT_NAME = "$(TARGET_NAME)"; From b5fb421bd201beb11372a8f7ab21b0cfa2ceb554 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Wed, 6 Sep 2017 16:59:12 +0200 Subject: [PATCH 48/58] Pushkit support: Start a matrix session for each enabled accounts even if the app is in background. AppDelegate - `initMatrixSession`: Start a matrix session for each enabled accounts even if the app is in background. Indeed we call [accountManager prepareSessionForActiveAccounts] even in background mode, The session is automatically paused when the running state is detected if the application is still in background. - Define a notification listener block for each session. This block is used during all the session life to display the local notifications when the app is backgrounded. - The local notifications are handled by using the background sync mechanism (defined at MXKAccount level). - Multiple accounts are handled. --- Riot/AppDelegate.m | 312 ++++++++++++++++++++------------------------- 1 file changed, 135 insertions(+), 177 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index e0a2b2e14..c6ef995cf 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -155,6 +155,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN */ NSMutableDictionary *callEventsListeners; + /** + The notification listener blocks. + There is one block per MXSession. + The key is an identifier of the MXSession. The value, the listener block. + */ + NSMutableDictionary *notificationListenerBlocks; + /** Currently displayed "Call not supported" alert. */ @@ -179,13 +186,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN @property (nonatomic, strong) PKPushRegistry *pushRegistry; - -@property (nonatomic, getter=isHandlingPushNotification) BOOL handlingPushNotification; -@property (nonatomic) NSUInteger pushNotificationHandlingTaskIdentifier; - -@property (nonatomic, nullable) MXOnNotification notificationListenerBlock; -@property (nonatomic, nullable) dispatch_block_t pushNotificationHandlingCompletionBlock; -@property (nonatomic, nullable) dispatch_block_t pushNotificationHandlingTimeoutBlock; +@property (nonatomic) BOOL hasPendingLocalNotifications; @end @@ -326,6 +327,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN mxSessionArray = [NSMutableArray array]; callEventsListeners = [NSMutableDictionary dictionary]; + notificationListenerBlocks = [NSMutableDictionary dictionary]; // To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; @@ -475,6 +477,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { NSLog(@"[AppDelegate] applicationDidBecomeActive"); + _hasPendingLocalNotifications = NO; + // Check if there is crash log to send if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"]) { @@ -1045,168 +1049,43 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type { - // If it isn't a first push - if (self.isHandlingPushNotification) - { - // If we have processed push notification and we're waiting to complete after a timeout - if (self.pushNotificationHandlingCompletionBlock) - { - // Cancel completion of previous push notification. - // The new completion block will be created when this push notification will be processed if timeout block wouldn't be called - dispatch_block_cancel(self.pushNotificationHandlingCompletionBlock); - self.pushNotificationHandlingCompletionBlock = nil; - } - - // On every new push cancel timeout block if any. - // This situation is possible when we sequentially receive a series of push notifications in a short amount of time. - if (self.pushNotificationHandlingTimeoutBlock) - { - dispatch_block_cancel(self.pushNotificationHandlingTimeoutBlock); - self.pushNotificationHandlingTimeoutBlock = nil; - } - - // Create and run timeout block since we don't know how much time will take a new sync request - // There is also a case when we receive push event earlier than push and we need to stop execution somehow - // so timeoutBlock will help us in this situation - dispatch_block_t timeoutBlock = [self createPushNotificationHandlingStateCleaningBlock]; - self.pushNotificationHandlingTimeoutBlock = timeoutBlock; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(120 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - timeoutBlock(); - }); - - return; - } - - UIApplication *application = [UIApplication sharedApplication]; - - if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateInactive) - return; - - MXSession *session = mxSessionArray.firstObject; - - if (session.state == MXSessionStateHomeserverNotReachable) - return; - - if (session.state == MXSessionStatePaused) - [session resume:^{}]; - - self.handlingPushNotification = YES; - - id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; - self.pushNotificationHandlingTaskIdentifier = [handler startBackgroundTaskWithName:nil completion:^{ - // Maybe do smth here... - }]; - - // Listen events from MXNotificationCenter - __block MXOnNotification notificationsListenerBlock = nil; - - // This variable will be point to notificationsListenerBlock but won't retain it. - // It's very important since notificationsListenerBlock is required in two another blocks which also - // are being referenced inside notificationsListenerBlock's body. - // So this weak variable allows us to avoid retain cycle. - __weak __block MXOnNotification weakNotificationsListenerBlock = nil; - - // The block which is called when a sync with server takes a lot of time - dispatch_block_t timeoutBlock = [self createPushNotificationHandlingStateCleaningBlock]; - self.pushNotificationHandlingTimeoutBlock = timeoutBlock; - - __weak typeof(self) weakSelf = self; - - notificationsListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) { - if (weakSelf.pushNotificationHandlingTimeoutBlock) - { - dispatch_block_cancel(weakSelf.pushNotificationHandlingTimeoutBlock); - weakSelf.pushNotificationHandlingTimeoutBlock = nil; - } - - if (weakSelf.pushNotificationHandlingCompletionBlock) - { - dispatch_block_cancel(weakSelf.pushNotificationHandlingCompletionBlock); - weakSelf.pushNotificationHandlingCompletionBlock = nil; - } - - // For all type of event show local notifications besides the situation - // when the type of event is call invite and we have CallKit support - BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled; - if (!(event.eventType == MXEventTypeCallInvite && isCallKitActive)) - { - BOOL isEventRoomDirect = [session roomWithRoomId:event.roomId].isDirect; - NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; - if (notificationBody) - { - UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; - eventNotification.fireDate = [NSDate date]; - eventNotification.alertBody = notificationBody; - eventNotification.userInfo = @{ @"room_id" : event.roomId }; - - // Set sound name based on the value provided in action of MXPushRule - for (MXPushRuleAction *action in rule.actions) - { - if (action.actionType == MXPushRuleActionTypeSetTweak) - { - if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"]) - { - NSString *soundName = action.parameters[@"value"]; - if ([soundName isEqualToString:@"default"]) - soundName = UILocalNotificationDefaultSoundName; - - eventNotification.soundName = soundName; - } - } - } - - [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; - } - } - - dispatch_block_t completionBlock = [weakSelf createPushNotificationHandlingStateCleaningBlock]; - weakSelf.pushNotificationHandlingCompletionBlock = completionBlock; - - // This delay will help us to process push events which we receive earlier than push notifications associated with them - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - completionBlock(); - }); - }; - - weakNotificationsListenerBlock = notificationsListenerBlock; - self.notificationListenerBlock = notificationsListenerBlock; - - [session.notificationCenter listenToNotifications:notificationsListenerBlock]; - - // Run timeout block - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(120.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - timeoutBlock(); - }); + // Handle the local notifications by triggering a background sync. + [self handleLocalNotifications]; } -/** - Create and return a block which clean all state associated wiht push notifications handling - */ -- (dispatch_block_t)createPushNotificationHandlingStateCleaningBlock +- (void)handleLocalNotifications { - __weak typeof(self) weakSelf = self; - MXSession *session = mxSessionArray.firstObject; + _hasPendingLocalNotifications = NO; - return dispatch_block_create(0, ^{ - [session.notificationCenter removeListener:weakSelf.notificationListenerBlock]; + // Check whether the application is running in background. + if ([UIApplication sharedApplication].applicationState != UIApplicationStateBackground) + return; + + // Launch a background sync for all existing matrix sessions + NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; + for (MXKAccount *account in mxAccounts) + { + // Check the current session state + if (account.mxSession.state != MXSessionStatePaused) + { + NSLog(@"[AppDelegate] handleLocalNotifications: delay the background sync"); + // Turn on the flag used to trigger a new background sync when a session is paused. + _hasPendingLocalNotifications = YES; + } - // Update icon badge number - [UIApplication sharedApplication].applicationIconBadgeNumber = [session riot_missedDiscussionsCount]; - - id handler = [MXSDKOptions sharedInstance].backgroundModeHandler; - - NSUInteger identifier = weakSelf.pushNotificationHandlingTaskIdentifier; - - weakSelf.handlingPushNotification = NO; - weakSelf.pushNotificationHandlingTaskIdentifier = [handler invalidIdentifier]; - - weakSelf.notificationListenerBlock = nil; - weakSelf.pushNotificationHandlingTimeoutBlock = nil; - weakSelf.pushNotificationHandlingCompletionBlock = nil; - - [handler endBackgrounTaskWithIdentifier:identifier]; - }); + [account backgroundSync:20000 success:^{ + + NSLog(@"[AppDelegate] handleLocalNotifications: the background sync succeeds"); + + // Update icon badge number + [UIApplication sharedApplication].applicationIconBadgeNumber = [account.mxSession riot_missedDiscussionsCount]; + + } failure:^(NSError *error) { + + NSLog(@"[AppDelegate] handleLocalNotifications: the background sync fails"); + + }]; + } } - (nullable NSString *)notificationBodyForEvent:(MXEvent *)event inDirectRoom:(BOOL)isDirect withRoomState:(MXRoomState *)roomState @@ -1775,6 +1654,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } else if (mxSession.state == MXSessionStateStoreDataReady) { + // Enable local notifications + [self enableLocalNotificationsFromMatrixSession:mxSession]; + // Check whether the app user wants inApp notifications on new events for this session NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; for (MXKAccount *account in mxAccounts) @@ -1790,6 +1672,31 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { [self removeMatrixSession:mxSession]; } + // Consider here the case where the app is running in background. + else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground) + { + if (mxSession.state == MXSessionStateRunning) + { + // Pause the session in background task + NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; + for (MXKAccount *account in mxAccounts) + { + if (account.mxSession == mxSession) + { + [account pauseInBackgroundTask]; + break; + } + } + } + else if (mxSession.state == MXSessionStatePaused) + { + // Check whether some local notifications must be handled by triggering a background sync. + if (_hasPendingLocalNotifications) + { + [self handleLocalNotifications]; + } + } + } // Restore call observer only if all session are running NSArray *mxSessions = self.mxSessions; @@ -1895,19 +1802,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN accountManager.storeClass = [MXFileStore class]; // Observers have been defined, we can start a matrix session for each enabled accounts. - // except if the app is still in background. - if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) - { - NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts"); - [accountManager prepareSessionForActiveAccounts]; - } - else - { - // The app is launched in background as a result of a remote notification. - // Presently we are not able to initialize the matrix session(s) in background. (FIXME: initialize matrix session(s) in case of a background launch). - // Patch: the account session(s) will be opened when the app will enter foreground. - NSLog(@"[AppDelegate] initMatrixSessions: The application has been launched in background"); - } + NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts (app state: %tu)", [[UIApplication sharedApplication] applicationState]); + [accountManager prepareSessionForActiveAccounts]; // Check whether we're already logged in NSArray *mxAccounts = accountManager.accounts; @@ -1977,6 +1873,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // If any, disable the no VoIP support workaround [self disableNoVoIPOnMatrixSession:mxSession]; + // Disable local notifications from this session + [self disableLocalNotificationsFromMatrixSession:mxSession]; + [mxSessionArray removeObject:mxSession]; } @@ -2372,6 +2271,65 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } +- (void)enableLocalNotificationsFromMatrixSession:(MXSession*)mxSession +{ + __weak typeof(self) weakSelf = self; + + MXOnNotification notificationListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) { + + if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) + { + // Do not display local notification if the app is not running in background. + return; + } + + // For all type of event show local notifications besides the situation + // when the type of event is call invite and we have CallKit support + BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled; + if (!(event.eventType == MXEventTypeCallInvite && isCallKitActive)) + { + BOOL isEventRoomDirect = [mxSession roomWithRoomId:event.roomId].isDirect; + NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; + if (notificationBody) + { + UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; + eventNotification.fireDate = [NSDate date]; + eventNotification.alertBody = notificationBody; + eventNotification.userInfo = @{ @"room_id" : event.roomId }; + + // Set sound name based on the value provided in action of MXPushRule + for (MXPushRuleAction *action in rule.actions) + { + if (action.actionType == MXPushRuleActionTypeSetTweak) + { + if ([action.parameters[@"set_tweak"] isEqualToString:@"sound"]) + { + NSString *soundName = action.parameters[@"value"]; + if ([soundName isEqualToString:@"default"]) + soundName = UILocalNotificationDefaultSoundName; + + eventNotification.soundName = soundName; + } + } + } + + [[UIApplication sharedApplication] scheduleLocalNotification:eventNotification]; + } + } + }; + + [mxSession.notificationCenter listenToNotifications:notificationListenerBlock]; + callEventsListeners[@(mxSession.hash)] = notificationListenerBlock; +} + +- (void)disableLocalNotificationsFromMatrixSession:(MXSession*)mxSession +{ + // Stop listening to notification of this session + [mxSession.notificationCenter removeListener:notificationListenerBlocks[@(mxSession.hash)]]; + [notificationListenerBlocks removeObjectForKey:@(mxSession.hash)]; +} + + #pragma mark - /** From 67ffc560e273abcf708155e8167130ce8c3114f3 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Thu, 7 Sep 2017 19:28:38 +0200 Subject: [PATCH 49/58] Pushkit Support - Bug Fix - Regression: incoming video call is ignored when the app is backgrounded. Do not remove the call observer at each session state change. A call observer is created as soon as a session is `StoreDataReady`, it is used until all the sessions are closed. We let the MXCallManager delay the call invite handling when the concerned session is syncing (see https://github.com/matrix-org/matrix-ios-sdk/pull/366). - Bug Fix - Regression: app crashes on logout (see wrong use of `callEventsListeners`). --- Riot/AppDelegate.m | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index c6ef995cf..2f06a8b94 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1596,13 +1596,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN matrixSessionStateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXSessionStateDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { MXSession *mxSession = (MXSession*)notif.object; - // Remove by default potential call observer on matrix session state change - if (matrixCallObserver) - { - [[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver]; - matrixCallObserver = nil; - } - // Check whether the concerned session is a new one if (mxSession.state == MXSessionStateInitialised) { @@ -1654,6 +1647,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } else if (mxSession.state == MXSessionStateStoreDataReady) { + // A new call observer may be added here + [self addMatrixCallObserver]; + // Enable local notifications [self enableLocalNotificationsFromMatrixSession:mxSession]; @@ -1698,24 +1694,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } - // Restore call observer only if all session are running - NSArray *mxSessions = self.mxSessions; - BOOL shouldAddMatrixCallObserver = (mxSessions.count); - for (mxSession in mxSessions) - { - if (mxSession.state != MXSessionStateRunning) - { - shouldAddMatrixCallObserver = NO; - break; - } - } - - if (shouldAddMatrixCallObserver) - { - // A new call observer may be added here - [self addMatrixCallObserver]; - } - [self handleLaunchAnimation]; }]; @@ -1877,6 +1855,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [self disableLocalNotificationsFromMatrixSession:mxSession]; [mxSessionArray removeObject:mxSession]; + + if (!mxSessionArray.count && matrixCallObserver) + { + [[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver]; + matrixCallObserver = nil; + } } - (void)markAllMessagesAsRead @@ -1965,10 +1949,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { if (matrixCallObserver) { - [[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver]; + return; } - // Register call observer in order to handle new opened session + // Register call observer in order to handle incoming calls matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall object:nil queue:[NSOperationQueue mainQueue] @@ -2319,7 +2303,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN }; [mxSession.notificationCenter listenToNotifications:notificationListenerBlock]; - callEventsListeners[@(mxSession.hash)] = notificationListenerBlock; + notificationListenerBlocks[@(mxSession.hash)] = notificationListenerBlock; } - (void)disableLocalNotificationsFromMatrixSession:(MXSession*)mxSession From 23a04810f54bd92a6de4c0c85cca47a73d2de0e4 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Fri, 8 Sep 2017 15:32:55 +0200 Subject: [PATCH 50/58] PushKit: local notifications handling Support the account settings: `showDecryptedContentInNotifications` value. --- Riot/AppDelegate.m | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index e1c33c510..bd8e9698f 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1088,7 +1088,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } -- (nullable NSString *)notificationBodyForEvent:(MXEvent *)event inDirectRoom:(BOOL)isDirect withRoomState:(MXRoomState *)roomState +- (nullable NSString *)notificationBodyForEvent:(MXEvent *)event withRoomState:(MXRoomState *)roomState inAccount:(MXKAccount*)account { if (!event.content || !event.content.count) return nil; @@ -1098,9 +1098,17 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN if (event.eventType == MXEventTypeRoomMessage || event.eventType == MXEventTypeRoomEncrypted) { + BOOL isDirect = [account.mxSession roomWithRoomId:event.roomId].isDirect; + NSString *msgType = event.content[@"msgtype"]; NSString *content = event.content[@"body"]; + if (event.isEncrypted && !account.showDecryptedContentInNotifications) + { + // Hide the content + msgType = nil; + } + if (!isDirect) { NSString *roomDisplayName = roomState.displayname; @@ -1112,7 +1120,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN else if ([msgType isEqualToString:@"m.image"]) notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER_IN_ROOM", nil), eventSenderName, content, roomDisplayName]; else - // Unencrypted messages falls here + // Encrypted messages falls here notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER_IN_ROOM", nil), eventSenderName, roomDisplayName]; } else @@ -1124,7 +1132,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN else if ([msgType isEqualToString:@"m.image"]) notificationBody = [NSString stringWithFormat:NSLocalizedString(@"IMAGE_FROM_USER", nil), eventSenderName, content]; else - // Unencrypted messages falls here + // Encrypted messages falls here notificationBody = [NSString stringWithFormat:NSLocalizedString(@"MSG_FROM_USER", nil), eventSenderName]; } } @@ -1653,12 +1661,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Enable local notifications [self enableLocalNotificationsFromMatrixSession:mxSession]; - // Check whether the app user wants inApp notifications on new events for this session + // Look for the account related to this session. NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; for (MXKAccount *account in mxAccounts) { if (account.mxSession == mxSession) { + // Enable inApp notifications (if they are allowed for this account). [self enableInAppNotificationsForAccount:account]; break; } @@ -2205,6 +2214,18 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { __weak typeof(self) weakSelf = self; + // Look for the account related to this session. + NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts; + MXKAccount *account; + for (account in mxAccounts) + { + if (account.mxSession == mxSession) + { + break; + } + account = nil; + } + MXOnNotification notificationListenerBlock = ^(MXEvent *event, MXRoomState *roomState, MXPushRule *rule) { if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateBackground) @@ -2218,8 +2239,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN BOOL isCallKitActive = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled; if (!(event.eventType == MXEventTypeCallInvite && isCallKitActive)) { - BOOL isEventRoomDirect = [mxSession roomWithRoomId:event.roomId].isDirect; - NSString *notificationBody = [weakSelf notificationBodyForEvent:event inDirectRoom:isEventRoomDirect withRoomState:roomState]; + NSString *notificationBody = [weakSelf notificationBodyForEvent:event withRoomState:roomState inAccount:account]; if (notificationBody) { UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; From 71e18cf903886cf4cf1f2f8b631367efeac732c8 Mon Sep 17 00:00:00 2001 From: Denis Morozov Date: Sun, 10 Sep 2017 16:41:50 +0300 Subject: [PATCH 51/58] Fix push registration process --- Riot/AppDelegate.m | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index bd8e9698f..52efa8f96 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -972,19 +972,27 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)registerForRemoteNotificationsWithCompletion:(nullable void (^)(NSError *))completion { self.registrationForRemoteNotificationsCompletion = completion; - [[UIApplication sharedApplication] registerForRemoteNotifications]; -} - -- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings -{ - if (notificationSettings.types == UIUserNotificationTypeNone) - return; self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil]; self.pushRegistry.delegate = self; self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; } +- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings +{ + // Register for remote notifications only if user provide access to notification feature + if (notificationSettings.types != UIUserNotificationTypeNone) + { + [self registerForRemoteNotificationsWithCompletion:nil]; + } + else + { + // Clear existing token + MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; + [accountManager setApnsDeviceToken:nil]; + } +} + - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { NSString* roomId = notification.userInfo[@"room_id"]; @@ -1039,6 +1047,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN [accountManager setApnsDeviceToken:token]; isAPNSRegistered = YES; + + if (self.registrationForRemoteNotificationsCompletion) + { + self.registrationForRemoteNotificationsCompletion(nil); + self.registrationForRemoteNotificationsCompletion = nil; + } } - (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type From 46d0e7b69699c32bc2869db503c5a03ab8bb2a41 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Wed, 13 Sep 2017 15:15:57 +0200 Subject: [PATCH 52/58] Pushkit: unregister for all remote notifications received via Apple Push Notification service. --- Riot/AppDelegate.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 52efa8f96..736fe8871 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -358,6 +358,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _isAppForeground = NO; + // We use now Pushkit, unregister for all remote notifications received via Apple Push Notification service. + [[UIApplication sharedApplication] unregisterForRemoteNotifications]; + // Retrieve custom configuration NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; From d1dcee40929da1cf4d4e379c6fa85d6afddf29f0 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Tue, 19 Sep 2017 16:06:44 +0200 Subject: [PATCH 53/58] Pushkit: Remove APNS use. Use new MXKAccount API to handle push token and settings. - add format: 'event_id_only' to the data dict when you add the pusher - use the following app ID: im.vector.app.ios.voip.prod --- Riot/AppDelegate.h | 4 +-- Riot/AppDelegate.m | 31 ++++++++++++-------- Riot/Riot-Defaults.plist | 4 +-- Riot/ViewController/SettingsViewController.m | 22 +++++++------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/Riot/AppDelegate.h b/Riot/AppDelegate.h index dd33b3579..55b3cd54e 100644 --- a/Riot/AppDelegate.h +++ b/Riot/AppDelegate.h @@ -43,7 +43,7 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification; @interface AppDelegate : UIResponder { - BOOL isAPNSRegistered; + BOOL isPushRegistered; // background sync management void (^_completionHandler)(UIBackgroundFetchResult); @@ -112,7 +112,7 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification; - (void)startGoogleAnalytics; - (void)stopGoogleAnalytics; -#pragma mark - APNS methods +#pragma mark - Push notifications - (void)registerUserNotificationSettings; diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index cb193e5bd..13509940a 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -357,9 +357,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN _isAppForeground = NO; - // We use now Pushkit, unregister for all remote notifications received via Apple Push Notification service. - [[UIApplication sharedApplication] unregisterForRemoteNotifications]; - // Retrieve custom configuration NSString* userDefaults = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UserDefaults"]; NSString *defaultsPathFromApp = [[NSBundle mainBundle] pathForResource:userDefaults ofType:@"plist"]; @@ -959,11 +956,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } -#pragma mark - APNS methods +#pragma mark - Push notifications - (void)registerUserNotificationSettings { - if (!isAPNSRegistered) + if (!isPushRegistered) { // Registration on iOS 8 and later UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound |UIUserNotificationTypeAlert) categories:nil]; @@ -991,7 +988,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { // Clear existing token MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; - [accountManager setApnsDeviceToken:nil]; + [accountManager setPushDeviceToken:nil withPushOptions:nil]; } } @@ -1043,12 +1040,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSData *token = credentials.token; NSUInteger len = ((token.length > 8) ? 8 : token.length / 2); - NSLog(@"[AppDelegate] Got APNS token! (%@ ...)", [token subdataWithRange:NSMakeRange(0, len)]); + NSLog(@"[AppDelegate] Got Push token! (%@ ...)", [token subdataWithRange:NSMakeRange(0, len)]); MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; - [accountManager setApnsDeviceToken:token]; + [accountManager setPushDeviceToken:token withPushOptions:@{@"format": @"event_id_only"}]; - isAPNSRegistered = YES; + isPushRegistered = YES; if (self.registrationForRemoteNotificationsCompletion) { @@ -1060,7 +1057,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type { MXKAccountManager* accountManager = [MXKAccountManager sharedManager]; - [accountManager setApnsDeviceToken:nil]; + [accountManager setPushDeviceToken:nil withPushOptions:nil]; } - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type @@ -1737,10 +1734,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Set the push gateway URL. account.pushGatewayURL = [[NSUserDefaults standardUserDefaults] objectForKey:@"pushGatewayURL"]; - if (isAPNSRegistered) + if (isPushRegistered) { // Enable push notifications by default on new added account - account.enablePushNotifications = YES; + account.enablePushKitNotifications = YES; } else { @@ -1807,6 +1804,14 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Use MXFileStore as MXStore to permanently store events. accountManager.storeClass = [MXFileStore class]; + // Disable APNS use. + if (accountManager.apnsDeviceToken) + { + // We use now Pushkit, unregister for all remote notifications received via Apple Push Notification service. + [[UIApplication sharedApplication] unregisterForRemoteNotifications]; + [accountManager setApnsDeviceToken:nil]; + } + // Observers have been defined, we can start a matrix session for each enabled accounts. NSLog(@"[AppDelegate] initMatrixSessions: prepareSessionForActiveAccounts (app state: %tu)", [[UIApplication sharedApplication] applicationState]); [accountManager prepareSessionForActiveAccounts]; @@ -1926,7 +1931,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN - (void)logout { self.pushRegistry = nil; - isAPNSRegistered = NO; + isPushRegistered = NO; // Clear cache [MXMediaManager clearCache]; diff --git a/Riot/Riot-Defaults.plist b/Riot/Riot-Defaults.plist index da87bc19d..a8f218ea1 100644 --- a/Riot/Riot-Defaults.plist +++ b/Riot/Riot-Defaults.plist @@ -12,6 +12,8 @@ im.vector.app.ios.dev pusherAppIdProd im.vector.app.ios.prod + pushKitAppIdProd + im.vector.app.ios.voip.prod identityserverurl https://vector.im homeserverurl @@ -28,8 +30,6 @@ https://scalar-staging.riot.im/scalar-web/ integrationsRestUrl https://scalar-staging.riot.im/scalar/api - apnsDeviceToken - showAllEventsInRoomHistory showRedactionsInRoomHistory diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index 8c5166cd6..d9344fb67 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -133,7 +133,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); // listener id removedAccountObserver; id accountUserInfoObserver; - id apnsInfoUpdateObserver; + id pushInfoUpdateObserver; id notificationCenterWillUpdateObserver; id notificationCenterDidUpdateObserver; @@ -283,8 +283,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); }]; - // Add observer to apns - apnsInfoUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountAPNSActivityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { + // Add observer to push settings + pushInfoUpdateObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXKAccountPushKitActivityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { [self stopActivityIndicator]; @@ -533,10 +533,10 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); accountUserInfoObserver = nil; } - if (apnsInfoUpdateObserver) + if (pushInfoUpdateObserver) { - [[NSNotificationCenter defaultCenter] removeObserver:apnsInfoUpdateObserver]; - apnsInfoUpdateObserver = nil; + [[NSNotificationCenter defaultCenter] removeObserver:pushInfoUpdateObserver]; + pushInfoUpdateObserver = nil; } [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -1633,7 +1633,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_enable_push_notif", @"Vector", nil); - labelAndSwitchCell.mxkSwitch.on = account.pushNotificationServiceIsActive; + labelAndSwitchCell.mxkSwitch.on = account.isPushKitNotificationActive; labelAndSwitchCell.mxkSwitch.enabled = YES; [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(togglePushNotifications:) forControlEvents:UIControlEventTouchUpInside]; @@ -1646,7 +1646,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_show_decrypted_content", @"Vector", nil); labelAndSwitchCell.mxkSwitch.on = account.showDecryptedContentInNotifications; - labelAndSwitchCell.mxkSwitch.enabled = account.pushNotificationServiceIsActive; + labelAndSwitchCell.mxkSwitch.enabled = account.isPushKitNotificationActive; [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventTouchUpInside]; @@ -2713,9 +2713,9 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); MXKAccountManager *accountManager = [MXKAccountManager sharedManager]; MXKAccount* account = accountManager.activeAccounts.firstObject; - if (accountManager.apnsDeviceToken) + if (accountManager.pushDeviceToken) { - [account setEnablePushNotifications:!account.pushNotificationServiceIsActive]; + [account setEnablePushKitNotifications:!account.isPushKitNotificationActive]; } else { @@ -2728,7 +2728,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } else { - [account setEnablePushNotifications:YES]; + [account setEnablePushKitNotifications:YES]; } }]; } From f01fbe921419253f84c520253374c4469e64d548 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Wed, 20 Sep 2017 17:37:55 +0200 Subject: [PATCH 54/58] Update Podfile to build callkit version --- Podfile | 12 ++++++------ use-dev-pods.sh | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Podfile b/Podfile index 8c8b975d8..1d4d055cc 100644 --- a/Podfile +++ b/Podfile @@ -13,8 +13,8 @@ pod 'MatrixKit', '0.6.2' #pod 'MatrixKit' # The develop branch version -#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop' -#pod 'MatrixKit', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'develop' +#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'callkit' +#pod 'MatrixKit', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'callkit' # The one used for developing both MatrixSDK and MatrixKit # Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder @@ -58,8 +58,8 @@ pod 'MatrixKit/AppExtension', '0.6.2' #pod 'MatrixKit/AppExtension' # The develop branch version -#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop' -#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'develop' +#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'callkit' +#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'callkit' # The one used for developing both MatrixSDK and MatrixKit # Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder @@ -90,8 +90,8 @@ pod 'MatrixKit/AppExtension', '0.6.2' #pod 'MatrixKit/AppExtension' # The develop branch version -#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'develop' -#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'develop' +#pod 'MatrixSDK', :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => 'callkit' +#pod 'MatrixKit/AppExtension', :git => 'https://github.com/matrix-org/matrix-ios-kit.git', :branch => 'callkit' # The one used for developing both MatrixSDK and MatrixKit # Note that MatrixSDK must be cloned into a folder called matrix-ios-sdk next to the MatrixKit folder diff --git a/use-dev-pods.sh b/use-dev-pods.sh index dd3d75323..7262b294c 100755 --- a/use-dev-pods.sh +++ b/use-dev-pods.sh @@ -12,5 +12,5 @@ rm -f Podfile.lock sed -i '' -E "s!^(pod)(.*MatrixSDK)!#\1\2!g" Podfile sed -i '' -E "s!^(pod)(.*MatrixKit)!#\1\2!g" Podfile # And enable the develop ones -sed -i '' -E "s!^(#pod)(.*MatrixSDK)(.*develop)!pod\2\3!g" Podfile -sed -i '' -E "s!^(#pod)(.*MatrixKit)(.*develop)!pod\2\3!g" Podfile +sed -i '' -E "s!^(#pod)(.*MatrixSDK)(.*callkit)!pod\2\3!g" Podfile +sed -i '' -E "s!^(#pod)(.*MatrixKit)(.*callkit)!pod\2\3!g" Podfile From 89e4de5722a61a55b475fabb47611bfc7c92104b Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Thu, 21 Sep 2017 10:07:51 +0200 Subject: [PATCH 55/58] Entitlement: Add com.apple.developer.siri --- SiriIntents/SiriIntents.entitlements | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index e540aaaec..47630e3a7 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -6,5 +6,7 @@ group.im.vector + com.apple.developer.siri + From 13ddc0bf75a0a71ee35e2e164d167416bbdd43d9 Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Thu, 21 Sep 2017 12:57:42 +0200 Subject: [PATCH 56/58] Entitlements: Remove com.apple.developer.siri key (This seems useless) --- SiriIntents/SiriIntents.entitlements | 2 -- 1 file changed, 2 deletions(-) diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index 47630e3a7..e540aaaec 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -6,7 +6,5 @@ group.im.vector - com.apple.developer.siri - From f89b71257f4c3801a58142fcf4cbfd2012a3c3fc Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Thu, 21 Sep 2017 13:34:44 +0200 Subject: [PATCH 57/58] Revert "Entitlements: Remove com.apple.developer.siri key" This reverts commit 43629a1787c1a66dc1adbd4b1018f10bc80d33f1. --- SiriIntents/SiriIntents.entitlements | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index e540aaaec..47630e3a7 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -6,5 +6,7 @@ group.im.vector + com.apple.developer.siri + From 84215a0a94dd559e17df8772f7309bef9556076d Mon Sep 17 00:00:00 2001 From: Giom Foret Date: Thu, 21 Sep 2017 14:11:11 +0200 Subject: [PATCH 58/58] Entitlements: Re-remove com.apple.developer.siri key --- SiriIntents/SiriIntents.entitlements | 2 -- 1 file changed, 2 deletions(-) diff --git a/SiriIntents/SiriIntents.entitlements b/SiriIntents/SiriIntents.entitlements index 47630e3a7..e540aaaec 100644 --- a/SiriIntents/SiriIntents.entitlements +++ b/SiriIntents/SiriIntents.entitlements @@ -6,7 +6,5 @@ group.im.vector - com.apple.developer.siri -