Merge pull request #1564 from vector-im/callkit

Support Callkit and Pushkit
This commit is contained in:
giomfo
2017-10-09 18:27:44 +02:00
committed by GitHub
17 changed files with 1322 additions and 244 deletions
+33 -5
View File
@@ -5,7 +5,6 @@ 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.6.3'
@@ -14,8 +13,8 @@ pod 'MatrixKit', '0.6.3'
#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
@@ -59,8 +58,8 @@ pod 'MatrixKit/AppExtension', '0.6.3'
#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
@@ -74,5 +73,34 @@ pod 'cmark', :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.10.2'
# The tagged version on which this version of Riot share extension has been built
pod 'MatrixKit/AppExtension', '0.6.3'
# 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 => '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
#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
Regular → Executable
+190
View File
@@ -84,9 +84,14 @@
32F3AE1A1F6FF4E600F0F004 /* WidgetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32F3AE191F6FF4E600F0F004 /* WidgetViewController.m */; };
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 */; };
83711A7C1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */; };
92324BE31F4F66D3009DE194 /* IncomingCallView.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE21F4F66D3009DE194 /* IncomingCallView.m */; };
92324BE61F4F6A60009DE194 /* CircleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 92324BE51F4F6A60009DE194 /* CircleButton.m */; };
926FA53F1F4C132000F826C2 /* MXSession+Riot.m in Sources */ = {isa = PBXBuildFile; fileRef = 926FA53E1F4C132000F826C2 /* MXSession+Riot.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 */; };
@@ -555,6 +560,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 */;
@@ -572,6 +584,7 @@
dstSubfolderSpec = 13;
files = (
24CBEC591F0EAD310093EABB /* RiotShareExtension.appex in Embed App Extensions */,
92726A4B1F58737A004AD26F /* SiriIntents.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -678,6 +691,9 @@
32FD0A3A1EB0CD9B0072B066 /* BugReportViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BugReportViewController.h; sourceTree = "<group>"; };
32FD0A3B1EB0CD9B0072B066 /* BugReportViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BugReportViewController.m; sourceTree = "<group>"; };
32FD0A3C1EB0CD9B0072B066 /* BugReportViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BugReportViewController.xib; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
83711A7B1F6F8E7D008F0D4D /* KeyboardGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyboardGrowingTextView.m; sourceTree = "<group>"; };
@@ -686,6 +702,14 @@
92324BE21F4F66D3009DE194 /* IncomingCallView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IncomingCallView.m; sourceTree = "<group>"; };
92324BE41F4F6A60009DE194 /* CircleButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CircleButton.h; sourceTree = "<group>"; };
92324BE51F4F6A60009DE194 /* CircleButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CircleButton.m; sourceTree = "<group>"; };
926FA53D1F4C132000F826C2 /* MXSession+Riot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MXSession+Riot.h"; sourceTree = "<group>"; };
926FA53E1F4C132000F826C2 /* MXSession+Riot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MXSession+Riot.m"; sourceTree = "<group>"; };
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 = "<group>"; };
92726A461F58737A004AD26F /* IntentHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntentHandler.m; sourceTree = "<group>"; };
92726A481F58737A004AD26F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
92726A4F1F587393004AD26F /* SiriIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = SiriIntents.entitlements; sourceTree = "<group>"; };
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 = "<group>"; };
F0131DE31F2200D600CBF707 /* RiotSplitViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RiotSplitViewController.h; sourceTree = "<group>"; };
F0131DE41F2200D600CBF707 /* RiotSplitViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RiotSplitViewController.m; sourceTree = "<group>"; };
@@ -1280,6 +1304,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A401F58737A004AD26F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92726A511F587410004AD26F /* Intents.framework in Frameworks */,
714F6391AC0AA86C0AEB3F43 /* libPods-SiriIntents.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F094A99F1B78D8F000B1FBBF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -1470,8 +1503,10 @@
5FC42FA41F5186AFFB6A2404 /* Frameworks */ = {
isa = PBXGroup;
children = (
92726A501F587410004AD26F /* Intents.framework */,
FD9D0BDE9232898950554DD5 /* libPods-Riot.a */,
7246451C668D6782166E22EC /* libPods-RiotShareExtension.a */,
5666C1236223F54D4C635C54 /* libPods-SiriIntents.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -1483,6 +1518,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 = "<group>";
@@ -1498,6 +1535,17 @@
path = Calls;
sourceTree = "<group>";
};
92726A441F58737A004AD26F /* SiriIntents */ = {
isa = PBXGroup;
children = (
92726A4F1F587393004AD26F /* SiriIntents.entitlements */,
92726A451F58737A004AD26F /* IntentHandler.h */,
92726A461F58737A004AD26F /* IntentHandler.m */,
92726A481F58737A004AD26F /* Info.plist */,
);
path = SiriIntents;
sourceTree = "<group>";
};
F04AF25E1F83A4C000D20F4D /* zh_Hans.lproj */ = {
isa = PBXGroup;
children = (
@@ -1850,6 +1898,8 @@
F083BBEA1E7009EC00A9B29C /* UINavigationController+Riot.m */,
F083BBEB1E7009EC00A9B29C /* UIViewController+RiotSearch.h */,
F083BBEC1E7009EC00A9B29C /* UIViewController+RiotSearch.m */,
926FA53D1F4C132000F826C2 /* MXSession+Riot.h */,
926FA53E1F4C132000F826C2 /* MXSession+Riot.m */,
);
path = Categories;
sourceTree = "<group>";
@@ -2386,6 +2436,7 @@
F083BB081E7009EC00A9B29C /* Riot */,
F083BB021E7005FD00A9B29C /* RiotTests */,
24CBEC4F1F0EAD310093EABB /* RiotShareExtension */,
92726A441F58737A004AD26F /* SiriIntents */,
F094A9A31B78D8F000B1FBBF /* Products */,
7471DF3720D498384A068DA7 /* Pods */,
5FC42FA41F5186AFFB6A2404 /* Frameworks */,
@@ -2398,6 +2449,7 @@
F094A9A21B78D8F000B1FBBF /* Riot.app */,
F094A9BE1B78D8F000B1FBBF /* RiotTests.xctest */,
24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */,
92726A431F58737A004AD26F /* SiriIntents.appex */,
);
name = Products;
sourceTree = "<group>";
@@ -2434,6 +2486,25 @@
productReference = 24CBEC4E1F0EAD310093EABB /* RiotShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
92726A421F58737A004AD26F /* SiriIntents */ = {
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 = (
);
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" */;
@@ -2451,6 +2522,7 @@
);
dependencies = (
242661F61F12B1BA00D3FC08 /* PBXTargetDependency */,
92726A4A1F58737A004AD26F /* PBXTargetDependency */,
);
name = Riot;
productName = Vector;
@@ -2494,6 +2566,16 @@
};
};
};
92726A421F58737A004AD26F = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = 7J4U792NQT;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.ApplicationGroups.iOS = {
enabled = 1;
};
};
};
F094A9A11B78D8F000B1FBBF = {
CreatedOnToolsVersion = 6.2;
DevelopmentTeam = 7J4U792NQT;
@@ -2536,6 +2618,7 @@
F094A9A11B78D8F000B1FBBF /* Riot */,
F094A9BD1B78D8F000B1FBBF /* RiotTests */,
24CBEC4D1F0EAD310093EABB /* RiotShareExtension */,
92726A421F58737A004AD26F /* SiriIntents */,
);
};
/* End PBXProject section */
@@ -2565,6 +2648,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A411F58737A004AD26F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F094A9A01B78D8F000B1FBBF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3053,6 +3143,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;
@@ -3071,6 +3179,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;
@@ -3113,6 +3239,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
92726A3F1F58737A004AD26F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
92726A471F58737A004AD26F /* IntentHandler.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F094A99E1B78D8F000B1FBBF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -3238,6 +3372,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 */,
@@ -3282,6 +3417,11 @@
target = 24CBEC4D1F0EAD310093EABB /* RiotShareExtension */;
targetProxy = 242661F51F12B1BA00D3FC08 /* PBXContainerItemProxy */;
};
92726A4A1F58737A004AD26F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 92726A421F58737A004AD26F /* SiriIntents */;
targetProxy = 92726A491F58737A004AD26F /* PBXContainerItemProxy */;
};
F094A9C01B78D8F000B1FBBF /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F094A9A11B78D8F000B1FBBF /* Riot */;
@@ -3506,6 +3646,47 @@
};
name = Release;
};
92726A4C1F58737A004AD26F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 397BCA987893439918EBF330 /* 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.0;
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;
baseConfigurationReference = 4D1164C2F07EF74950DCDA7A /* 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.0;
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 = {
@@ -3686,6 +3867,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
92726A4E1F58737A004AD26F /* Build configuration list for PBXNativeTarget "SiriIntents" */ = {
isa = XCConfigurationList;
buildConfigurations = (
92726A4C1F58737A004AD26F /* Debug */,
92726A4D1F58737A004AD26F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F094A99D1B78D8F000B1FBBF /* Build configuration list for PBXProject "Riot" */ = {
isa = XCConfigurationList;
buildConfigurations = (
+2 -2
View File
@@ -43,7 +43,7 @@ extern NSString *const kAppDelegateNetworkStatusDidChangeNotification;
@interface AppDelegate : UIResponder <UIApplicationDelegate, MXKCallViewControllerDelegate, UISplitViewControllerDelegate, UINavigationControllerDelegate, JitsiViewControllerDelegate>
{
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;
+527 -192
View File
@@ -17,6 +17,9 @@
#import "AppDelegate.h"
#import <Intents/Intents.h>
#import <PushKit/PushKit.h>
#import "RecentsDataSource.h"
#import "RoomDataSource.h"
@@ -40,8 +43,16 @@
#import <AudioToolbox/AudioToolbox.h>
#include <MatrixSDK/MXUIKitBackgroundModeHandler.h>
// Calls
#import "CallViewController.h"
#import <MatrixSDK/MXCallKitAdapter.h>
#import <MatrixSDK/MXCallKitConfiguration.h>
#import "MXSession+Riot.h"
//#define MX_CALL_STACK_OPENWEBRTC
#ifdef MX_CALL_STACK_OPENWEBRTC
#import <MatrixOpenWebRTCWrapper/MatrixOpenWebRTCWrapper.h>
@@ -51,9 +62,10 @@
#import <MatrixEndpointWrapper/MatrixEndpointWrapper.h>
#endif
#include <MatrixSDK/MXJingleCallStack.h>
#include <MatrixSDK/MXUIKitBackgroundModeHandler.h>
#ifdef MX_CALL_STACK_JINGLE
#import <MatrixSDK/MXJingleCallStack.h>
#import <MatrixSDK/MXJingleCallAudioSessionConfigurator.h>
#endif
#define CALL_STATUS_BAR_HEIGHT 44
@@ -63,7 +75,7 @@
NSString *const kAppDelegateDidTapStatusBarNotification = @"kAppDelegateDidTapStatusBarNotification";
NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateNetworkStatusDidChangeNotification";
@interface AppDelegate ()
@interface AppDelegate () <PKPushRegistryDelegate>
{
/**
Reachability observer
@@ -106,11 +118,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.
@@ -147,6 +154,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 <NSNumber *, MXOnNotification> *notificationListenerBlocks;
/**
Currently displayed "Call not supported" alert.
*/
@@ -165,9 +179,14 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
@property (strong, nonatomic) UIAlertController *mxInAppNotification;
@property (strong, nonatomic) UIAlertController *incomingCallNotification;
@property (nonatomic, nullable, copy) void (^registrationForRemoteNotificationsCompletion)(NSError *);
@property (nonatomic, strong) PKPushRegistry *pushRegistry;
@property (nonatomic) BOOL hasPendingLocalNotifications;
@end
@implementation AppDelegate
@@ -307,6 +326,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;
@@ -443,13 +463,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).
[self prepareSessionForActiveAccounts];
_isAppForeground = YES;
// GA: Start a new session. The next hit from this tracker will be the first in a new session.
@@ -460,7 +473,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
NSLog(@"[AppDelegate] applicationDidBecomeActive");
remoteNotificationRoomId = nil;
_hasPendingLocalNotifications = NO;
// Check if there is crash log to send
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"enableCrashReport"])
@@ -547,6 +560,67 @@ 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];
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) {
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;
}
return continueUserActivity;
}
@@ -890,11 +964,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];
@@ -905,7 +979,10 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
- (void)registerForRemoteNotificationsWithCompletion:(nullable void (^)(NSError *))completion
{
self.registrationForRemoteNotificationsCompletion = completion;
[[UIApplication sharedApplication] registerForRemoteNotifications];
self.pushRegistry = [[PKPushRegistry alloc] initWithQueue:nil];
self.pushRegistry.delegate = self;
self.pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
@@ -919,58 +996,15 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
// Clear existing token
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setApnsDeviceToken:nil];
[accountManager setPushDeviceToken:nil withPushOptions:nil];
}
}
- (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)]);
NSLog(@"[AppDelegate] didReceiveLocalNotification: applicationState: %@", @([UIApplication sharedApplication].applicationState));
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setApnsDeviceToken:deviceToken];
isAPNSRegistered = YES;
if (self.registrationForRemoteNotificationsCompletion)
{
self.registrationForRemoteNotificationsCompletion(nil);
self.registrationForRemoteNotificationsCompletion = nil;
}
}
- (void)application:(UIApplication*)app didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
NSLog(@"[AppDelegate] Failed to register for APNS: %@", error);
if (self.registrationForRemoteNotificationsCompletion)
{
self.registrationForRemoteNotificationsCompletion(error);
self.registrationForRemoteNotificationsCompletion = nil;
}
}
- (void)cancelBackgroundSync
{
if (_completionHandler)
{
_completionHandler(UIBackgroundFetchResultNoData);
_completionHandler = nil;
}
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"[AppDelegate] didReceiveRemoteNotification: applicationState: %@", @([UIApplication sharedApplication].applicationState));
#ifdef DEBUG
// log the full userInfo only in DEBUG
NSLog(@"[AppDelegate] didReceiveRemoteNotification: %@", userInfo);
#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
@@ -1000,82 +1034,155 @@ 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.");
}
}
// Possible workaround for https://github.com/vector-im/riot-ios/issues/1522
// iOS 11 ignores us when we say that we will not display a local notification
// making the app crash in background.
// So, try to send the information a bit later with a dispatch_async :/
NSLog(@"[AppDelegate] didReceiveRemoteNotification: BEFORE completionHandler #1");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"[AppDelegate] didReceiveRemoteNotification: BEFORE completionHandler #2");
completionHandler(UIBackgroundFetchResultNoData);
NSLog(@"[AppDelegate] didReceiveRemoteNotification: AFTER completionHandler");
});
}
- (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 Push token! (%@ ...)", [token subdataWithRange:NSMakeRange(0, len)]);
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setPushDeviceToken:token withPushOptions:@{@"format": @"event_id_only"}];
isPushRegistered = YES;
if (self.registrationForRemoteNotificationsCompletion)
{
self.registrationForRemoteNotificationsCompletion(nil);
self.registrationForRemoteNotificationsCompletion = nil;
}
}
- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type
{
MXKAccountManager* accountManager = [MXKAccountManager sharedManager];
[accountManager setPushDeviceToken:nil withPushOptions:nil];
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type
{
// Handle the local notifications by triggering a background sync.
[self handleLocalNotifications];
}
- (void)handleLocalNotifications
{
_hasPendingLocalNotifications = NO;
// 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;
}
[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 withRoomState:(MXRoomState *)roomState inAccount:(MXKAccount*)account
{
if (!event.content || !event.content.count)
return nil;
NSString *notificationBody;
NSString *eventSenderName = [roomState memberName:event.sender];
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;
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, content, roomDisplayName];
else
// Encrypted 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, content];
else
// Encrypted 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
@@ -1507,6 +1614,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Get modular widget events in rooms histories
[[MXKAppSettings standardAppSettings] addSupportedEventTypes:@[kWidgetEventTypeString]];
// Use shared container to share data with app extensions
sdkOptions.applicationGroupIdentifier = @"group.im.vector";
// Disable long press on event in bubble cells
[MXKRoomBubbleTableViewCell disableLongPressGestureOnEvent:YES];
@@ -1517,13 +1627,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)
{
@@ -1545,6 +1648,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
{
@@ -1562,12 +1678,19 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
else if (mxSession.state == MXSessionStateStoreDataReady)
{
// Check whether the app user wants inApp notifications on new events for this session
// A new call observer may be added here
[self addMatrixCallObserver];
// Enable local notifications
[self enableLocalNotificationsFromMatrixSession:mxSession];
// 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;
}
@@ -1577,23 +1700,30 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
{
[self removeMatrixSession:mxSession];
}
// Restore call observer only if all session are running
NSArray *mxSessions = self.mxSessions;
BOOL shouldAddMatrixCallObserver = (mxSessions.count);
for (mxSession in mxSessions)
// Consider here the case where the app is running in background.
else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground)
{
if (mxSession.state != MXSessionStateRunning)
if (mxSession.state == MXSessionStateRunning)
{
shouldAddMatrixCallObserver = NO;
break;
// 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];
}
}
}
if (shouldAddMatrixCallObserver)
{
// A new call observer may be added here
[self addMatrixCallObserver];
}
[self handleLaunchAnimation];
@@ -1614,10 +1744,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
{
@@ -1678,38 +1808,28 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Add observer on settings changes.
[[MXKAppSettings standardAppSettings] addObserver:self forKeyPath:@"showAllEventsInRoomHistory" options:0 context:nil];
// 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)
{
[self 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");
}
}
- (void)prepareSessionForActiveAccounts
{
// Prepare account manager
MXKAccountManager *accountManager = [MXKAccountManager sharedManager];
// Use MXFileStore as MXStore to permanently store events.
accountManager.storeClass = [MXFileStore class];
// Check the first active account to know whether we have to prepare a matrix session for each account.
NSArray *mxAccounts = [MXKAccountManager sharedManager].activeAccounts;
MXKAccount *firstActiveAccount = mxAccounts.firstObject;
if (firstActiveAccount && !firstActiveAccount.mxSession)
// 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];
// Check whether we're already logged in
NSArray *mxAccounts = accountManager.activeAccounts;
if (mxAccounts.count)
{
NSLog(@"[AppDelegate] prepareSessionForActiveAccounts");
[accountManager prepareSessionForActiveAccounts];
for (MXKAccount *account in mxAccounts)
{
// Replace default room summary updater
@@ -1774,7 +1894,16 @@ 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];
if (!mxSessionArray.count && matrixCallObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver];
matrixCallObserver = nil;
}
}
- (void)markAllMessagesAsRead
@@ -1811,8 +1940,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
- (void)logout
{
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
isAPNSRegistered = NO;
self.pushRegistry = nil;
isPushRegistered = NO;
// Clear cache
[MXMediaManager clearCache];
@@ -1851,28 +1980,141 @@ 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
{
if (matrixCallObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:matrixCallObserver];
return;
}
// Register call observer in order to handle new opened session
matrixCallObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMXCallManagerNewCall object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
// Register call observer in order to handle incoming calls
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 && !_jitsiViewController)
{
MXCall *mxCall = (MXCall*)notif.object;
// Prepare the call view controller
currentCallViewController = [CallViewController callViewController:mxCall];
currentCallViewController.delegate = self;
BOOL isCallKitAvailable = [MXCallKitAdapter callKitAvailable] && [MXKAppSettings standardAppSettings].isCallKitEnabled;
[self presentCallViewController:nil];
// Prepare the call view controller
currentCallViewController = [CallViewController callViewController:nil];
currentCallViewController.playRingtone = !isCallKitAvailable;
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<MXBackgroundModeHandler> 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
NSString *callPromptFormat = mxCall.isVideoCall ? NSLocalizedStringFromTable(@"call_incoming_video_prompt", @"Vector", nil) : NSLocalizedStringFromTable(@"call_incoming_voice_prompt", @"Vector", nil);
NSString *callerName = currentCallViewController.peer.displayname;
if (!callerName.length)
{
callerName = currentCallViewController.peer.userId;
}
NSString *callPrompt = [NSString stringWithFormat:callPromptFormat, callerName];
// Removing existing notification (if any)
[_incomingCallNotification dismissViewControllerAnimated:NO completion:nil];
_incomingCallNotification = [UIAlertController alertControllerWithTitle:callPrompt
message:nil
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[_incomingCallNotification addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"decline", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
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 addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"accept", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self.incomingCallNotification = nil;
if (self->currentCallViewController)
{
[self->currentCallViewController onButtonPressed:self->currentCallViewController.answerCallButton];
[self presentCallViewController:nil];
}
}
}]];
[_incomingCallNotification mxk_setAccessibilityIdentifier:@"AppDelegateIncomingCallAlert"];
[self showNotificationAlert:_incomingCallNotification];
}
else
{
[self presentCallViewController:nil];
}
}
}];
}
@@ -1979,6 +2221,99 @@ 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<MXCallAudioSessionConfigurator> audioSessionConfigurator;
#ifdef MX_CALL_STACK_JINGLE
audioSessionConfigurator = [[MXJingleCallAudioSessionConfigurator alloc] init];
#endif
callKitAdapter.audioSessionConfigurator = audioSessionConfigurator;
callManager.callKitAdapter = callKitAdapter;
}
else
{
callManager.callKitAdapter = nil;
}
}
- (void)enableLocalNotificationsFromMatrixSession:(MXSession*)mxSession
{
__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)
{
// 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))
{
NSString *notificationBody = [weakSelf notificationBodyForEvent:event withRoomState:roomState inAccount:account];
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];
notificationListenerBlocks[@(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 -
/**
+4
View File
@@ -297,6 +297,7 @@
"settings_user_settings" = "USER SETTINGS";
"settings_notifications_settings" = "NOTIFICATION SETTINGS";
"settings_calls_settings" = "CALLS";
"settings_user_interface" = "USER INTERFACE";
"settings_ignored_users" = "IGNORED USERS";
"settings_contacts" = "LOCAL CONTACTS";
@@ -326,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";
@@ -338,6 +340,8 @@
//"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_ui_language" = "Language";
"settings_ui_theme" = "Theme";
"settings_ui_theme_auto" = "Auto";
+28
View File
@@ -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 <Foundation/Foundation.h>
#import <MatrixSDK/MXSession.h>
@interface MXSession (Riot)
/**
The current number of rooms with missed notifications, including the invites.
*/
- (NSUInteger)riot_missedDiscussionsCount;
@end
+51
View File
@@ -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
+2
View File
@@ -49,6 +49,8 @@
<string>The microphone is used to take videos, make calls.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The photo library is used to send photos and videos.</string>
<key>NSSiriUsageDescription</key>
<string>Siri is used to perform calls even from the lock screen.</string>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
+2 -2
View File
@@ -12,6 +12,8 @@
<string>im.vector.app.ios.dev</string>
<key>pusherAppIdProd</key>
<string>im.vector.app.ios.prod</string>
<key>pushKitAppIdProd</key>
<string>im.vector.app.ios.voip.prod</string>
<key>identityserverurl</key>
<string>https://vector.im</string>
<key>homeserverurl</key>
@@ -28,8 +30,6 @@
<string>https://scalar-staging.riot.im/scalar-web/</string>
<key>integrationsRestUrl</key>
<string>https://scalar-staging.riot.im/scalar/api</string>
<key>apnsDeviceToken</key>
<string></string>
<key>showAllEventsInRoomHistory</key>
<false/>
<key>showRedactionsInRoomHistory</key>
+2
View File
@@ -11,6 +11,8 @@
<string>applinks:riot.im</string>
<string>applinks:www.riot.im</string>
</array>
<key>com.apple.developer.siri</key>
<true/>
<key>com.apple.security.application-groups</key>
<array>
<string>group.im.vector</string>
+2 -20
View File
@@ -23,6 +23,7 @@
#import "AppDelegate.h"
#import "MXRoom+Riot.h"
#import "MXSession+Riot.h"
@interface MasterTabBarController ()
{
@@ -454,26 +455,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;
+103 -21
View File
@@ -17,13 +17,14 @@
#import "SettingsViewController.h"
#import "AppDelegate.h"
#import "AvatarGenerator.h"
#import <Photos/Photos.h>
#import <MatrixSDK/MXCallKitAdapter.h>
#import <MediaPlayer/MediaPlayer.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <OLMKit/OLMKit.h>
#import <Photos/Photos.h>
#import "AppDelegate.h"
#import "AvatarGenerator.h"
#import "MXKEncryptionKeysExportView.h"
#import "BugReportViewController.h"
@@ -32,17 +33,14 @@
#import "CountryPickerViewController.h"
#import "LanguagePickerViewController.h"
#import "TableViewCellWithPhoneNumberTextField.h"
#import "NBPhoneNumberUtil.h"
#import "AvatarGenerator.h"
#import "OLMKit/OLMKit.h"
#import "RageShakeManager.h"
#import "RiotDesignValues.h"
#import "TableViewCellWithPhoneNumberTextField.h"
#import "GBDeviceInfo_iOS.h"
NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId";
enum
@@ -50,6 +48,7 @@ enum
SETTINGS_SECTION_SIGN_OUT_INDEX = 0,
SETTINGS_SECTION_USER_SETTINGS_INDEX,
SETTINGS_SECTION_NOTIFICATIONS_SETTINGS_INDEX,
SETTINGS_SECTION_CALLS_INDEX,
SETTINGS_SECTION_USER_INTERFACE_INDEX,
SETTINGS_SECTION_IGNORED_USERS_INDEX,
SETTINGS_SECTION_CONTACTS_INDEX,
@@ -64,6 +63,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,
@@ -76,6 +76,13 @@ enum
NOTIFICATION_SETTINGS_COUNT
};
enum
{
CALLS_ENABLE_CALLKIT_INDEX = 0,
CALLS_DESCRIPTION_INDEX,
CALLS_COUNT
};
enum
{
USER_INTERFACE_LANGUAGE_INDEX = 0,
@@ -127,7 +134,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
// listener
id removedAccountObserver;
id accountUserInfoObserver;
id apnsInfoUpdateObserver;
id pushInfoUpdateObserver;
id notificationCenterWillUpdateObserver;
id notificationCenterDidUpdateObserver;
@@ -273,8 +280,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];
@@ -523,10 +530,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];
@@ -1175,6 +1182,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_USER_INTERFACE_INDEX)
{
count = USER_INTERFACE_COUNT;
@@ -1616,13 +1630,25 @@ 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];
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.isPushKitNotificationActive;
[labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleShowDecodedContent:) forControlEvents:UIControlEventTouchUpInside];
cell = labelAndSwitchCell;
}
else if (row == NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX)
{
MXKTableViewCell *globalInfoCell = [self getDefaultTableViewCell:tableView];
@@ -1661,6 +1687,29 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
cell = labelAndSwitchCell;
}
}
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_USER_INTERFACE_INDEX)
{
if (row == USER_INTERFACE_LANGUAGE_INDEX)
@@ -2085,6 +2134,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_USER_INTERFACE_INDEX)
{
return NSLocalizedStringFromTable(@"settings_user_interface", @"Vector", nil);
@@ -2209,6 +2265,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
return 24;
}
@@ -2227,6 +2290,13 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
}
}
else if (section == SETTINGS_SECTION_CALLS_INDEX)
{
if (![MXCallKitAdapter callKitAvailable])
{
return SECTION_TITLE_PADDING_WHEN_HIDDEN;
}
}
return 24;
}
@@ -2656,9 +2726,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
{
@@ -2671,13 +2741,25 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
}
else
{
[account setEnablePushNotifications:YES];
[account setEnablePushKitNotifications:YES];
}
}];
}
}
}
- (void)toggleCallKit:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;
[MXKAppSettings standardAppSettings].enableCallKit = switchButton.isOn;
}
- (void)toggleShowDecodedContent:(id)sender
{
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
account.showDecryptedContentInNotifications = !account.showDecryptedContentInNotifications;
}
- (void)toggleLocalContactsSync:(id)sender
{
UISwitch *switchButton = (UISwitch*)sender;
+41
View File
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>SiriIntents</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IntentsRestrictedWhileLocked</key>
<array/>
<key>IntentsSupported</key>
<array>
<string>INStartAudioCallIntent</string>
<string>INStartVideoCallIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.intents-service</string>
<key>NSExtensionPrincipalClass</key>
<string>IntentHandler</string>
</dict>
</dict>
</plist>
+21
View File
@@ -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 <Intents/Intents.h>
@interface IntentHandler : INExtension
@end
+302
View File
@@ -0,0 +1,302 @@
/*
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 "MXKAccount.h"
#import "MXKAccountManager.h"
#import "MXFileStore.h"
#import "MXSession.h"
@interface IntentHandler () <INStartAudioCallIntentHandling, INStartVideoCallIntentHandling>
@end
@implementation IntentHandler
- (instancetype)init
{
self = [super init];
if (self)
{
[MXSDKOptions sharedInstance].applicationGroupIdentifier = @"group.im.vector";
}
return self;
}
- (id)handlerForIntent:(INIntent *)intent
{
return self;
}
#pragma mark - INStartAudioCallIntentHandling
- (void)resolveContactsForStartAudioCall:(INStartAudioCallIntent *)intent withCompletion:(void (^)(NSArray<INPersonResolutionResult *> * _Nonnull))completion
{
[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:INStartAudioCallIntentResponseCodeFailureAppConfigurationRequired 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<INPersonResolutionResult *> * _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<INPerson *> *)contacts withCompletion:(void (^)(NSArray<INPersonResolutionResult *> * _Nonnull))completion
{
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;
// 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 right room among several direct rooms from previous resolution process run
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
// 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
{
// This resolution process run after selecting appropriate user among suggested user list
selectedUserId = callee.personHandle.value;
}
MXKAccount *account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (account)
{
MXFileStore *fileStore = [[MXFileStore alloc] initWithCredentials:account.mxCredentials];
[fileStore asyncRoomsSummaries:^(NSArray<MXRoomSummary *> * _Nonnull roomsSummaries) {
// Contains userIds of all users with whom the current user has direct chats
// Use set to avoid duplicates
NSMutableSet<NSString *> *directUserIds = [NSMutableSet set];
// Contains room summaries for all direct rooms connected with particular userId
NSMutableDictionary<NSString *, NSMutableArray<MXRoomSummary *> *> *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)
{
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<MXRoomSummary *> *userRoomSummaries = roomSummaries[diretUserId];
if (userRoomSummaries)
[userRoomSummaries addObject:summary];
else
roomSummaries[diretUserId] = [NSMutableArray arrayWithObject:summary];
}
}
[fileStore asyncUsersWithUserIds:directUserIds.allObjects success:^(NSArray<MXUser *> * _Nonnull users) {
// Find users whose display name contains string presented us by Siri
NSMutableArray<MXUser *> *matchingUsers = [NSMutableArray array];
for (MXUser *user in users)
{
if (!user.displayname)
continue;
if (!NSEqualRanges([callee.displayName rangeOfString:user.displayname options:NSCaseInsensitiveSearch], (NSRange){NSNotFound,0}))
{
[matchingUsers addObject:user];
}
}
NSMutableArray<INPerson *> *persons = [NSMutableArray array];
if (matchingUsers.count == 1)
{
MXUser *user = matchingUsers.firstObject;
// Provide to the user a list of direct rooms to choose from
NSArray<MXRoomSummary *> *summaries = roomSummaries[user.userId];
for (MXRoomSummary *summary in summaries)
{
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
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 (persons.count == 0)
{
completion(@[[INPersonResolutionResult unsupported]]);
}
else if (persons.count == 1)
{
completion(@[[INPersonResolutionResult successWithResolvedPerson:persons.firstObject]]);
}
else
{
completion(@[[INPersonResolutionResult disambiguationWithPeopleToDisambiguate:persons]]);
}
} failure:nil];
} failure:nil];
}
else
{
completion(@[[INPersonResolutionResult notRequired]]);
}
}
}
@end
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.im.vector</string>
</array>
</dict>
</plist>
+2 -2
View File
@@ -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