diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift
index f245797c7..ab3acaa92 100644
--- a/ElementX/Sources/Application/AppCoordinator.swift
+++ b/ElementX/Sources/Application/AppCoordinator.swift
@@ -17,6 +17,7 @@
import AnalyticsEvents
import BackgroundTasks
import Combine
+import Intents
import MatrixRustSDK
import SwiftUI
import Version
@@ -236,6 +237,20 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
return false
}
+ func handleUserActivity(_ userActivity: NSUserActivity) {
+ // `INStartVideoCallIntent` is to be replaced with `INStartCallIntent`
+ // but calls from Recents still send it ¯\_(ツ)_/¯
+ guard let intent = userActivity.interaction?.intent as? INStartVideoCallIntent,
+ let contact = intent.contacts?.first,
+ let roomIdentifier = contact.personHandle?.value else {
+ MXLog.error("Failed retrieving information from userActivity: \(userActivity)")
+ return
+ }
+
+ MXLog.info("Starting call in room: \(roomIdentifier)")
+ handleAppRoute(AppRoute.call(roomID: roomIdentifier))
+ }
+
// MARK: - AuthenticationFlowCoordinatorDelegate
func authenticationFlowCoordinator(didLoginWithSession userSession: UserSessionProtocol) {
diff --git a/ElementX/Sources/Application/AppCoordinatorProtocol.swift b/ElementX/Sources/Application/AppCoordinatorProtocol.swift
index 2419526da..7ac7d1d68 100644
--- a/ElementX/Sources/Application/AppCoordinatorProtocol.swift
+++ b/ElementX/Sources/Application/AppCoordinatorProtocol.swift
@@ -18,5 +18,8 @@ import Foundation
protocol AppCoordinatorProtocol: CoordinatorProtocol {
var windowManager: SecureWindowManagerProtocol { get }
+
@discardableResult func handleDeepLink(_ url: URL, isExternalURL: Bool) -> Bool
+
+ func handleUserActivity(_ userActivity: NSUserActivity)
}
diff --git a/ElementX/Sources/Application/Application.swift b/ElementX/Sources/Application/Application.swift
index 434e265bf..efef47f74 100644
--- a/ElementX/Sources/Application/Application.swift
+++ b/ElementX/Sources/Application/Application.swift
@@ -51,6 +51,11 @@ struct Application: App {
openURLInSystemBrowser($0)
}
}
+ .onContinueUserActivity("INStartVideoCallIntent", perform: { userActivity in
+ // `INStartVideoCallIntent` is to be replaced with `INStartCallIntent`
+ // but calls from Recents still send it ¯\_(ツ)_/¯
+ appCoordinator.handleUserActivity(userActivity)
+ })
.task {
appCoordinator.start()
}
diff --git a/ElementX/Sources/Services/ElementCall/ElementCallService.swift b/ElementX/Sources/Services/ElementCall/ElementCallService.swift
index 28bec8d46..5c9b90690 100644
--- a/ElementX/Sources/Services/ElementCall/ElementCallService.swift
+++ b/ElementX/Sources/Services/ElementCall/ElementCallService.swift
@@ -91,7 +91,7 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
guard let roomID = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomID.rawValue] as? String else {
- MXLog.error("Somethnig went wrong, missing room identifier for incoming voip call: \(payload)")
+ MXLog.error("Something went wrong, missing room identifier for incoming voip call: \(payload)")
return
}
@@ -102,20 +102,18 @@ class ElementCallService: NSObject, ElementCallServiceProtocol, PKPushRegistryDe
let configuration = CXProviderConfiguration()
configuration.supportsVideo = true
- configuration.includesCallsInRecents = false
+ configuration.includesCallsInRecents = true
+
+ // https://stackoverflow.com/a/46077628/730924
+ configuration.supportedHandleTypes = [.generic]
let update = CXCallUpdate()
update.hasVideo = true
update.localizedCallerName = payload.dictionaryPayload[ElementCallServiceNotificationKey.roomDisplayName.rawValue] as? String
- if let senderDisplayName = payload.dictionaryPayload[ElementCallServiceNotificationKey.senderDisplayName.rawValue] as? String {
- update.remoteHandle = .init(type: .generic, value: senderDisplayName)
- } else if let senderID = payload.dictionaryPayload[ElementCallServiceNotificationKey.senderID.rawValue] as? String {
- update.remoteHandle = .init(type: .generic, value: senderID)
- } else {
- MXLog.error("Something went wrong, both the user display name and ID are nil")
- }
+ // https://stackoverflow.com/a/41230020/730924
+ update.remoteHandle = .init(type: .generic, value: roomID)
let callProvider = CXProvider(configuration: configuration)
callProvider.setDelegate(self, queue: nil)
diff --git a/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift b/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift
index 51af47edb..c05d593f1 100644
--- a/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift
+++ b/ElementX/Sources/Services/ElementCall/ElementCallServiceProtocol.swift
@@ -24,8 +24,6 @@ enum ElementCallServiceAction {
enum ElementCallServiceNotificationKey: String {
case roomID
case roomDisplayName
- case senderID
- case senderDisplayName
}
let ElementCallServiceNotificationDiscardDelta = 10.0
diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift
index acdb99907..3dfa3e439 100644
--- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift
+++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift
@@ -70,6 +70,10 @@ class UITestsAppCoordinator: AppCoordinatorProtocol, SecureWindowManagerDelegate
fatalError("Not implemented.")
}
+ func handleUserActivity(_ activity: NSUserActivity) {
+ fatalError("Not implemented.")
+ }
+
func windowManagerDidConfigureWindows(_ windowManager: SecureWindowManagerProtocol) {
ServiceLocator.shared.userIndicatorController.window = windowManager.overlayWindow
diff --git a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift
index b866605ef..6c669d8a2 100644
--- a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift
+++ b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift
@@ -41,4 +41,8 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol {
func handleDeepLink(_ url: URL, isExternalURL: Bool) -> Bool {
fatalError("Not implemented.")
}
+
+ func handleUserActivity(_ activity: NSUserActivity) {
+ fatalError("Not implemented.")
+ }
}
diff --git a/ElementX/SupportingFiles/Info.plist b/ElementX/SupportingFiles/Info.plist
index f154a5033..fb51c555a 100644
--- a/ElementX/SupportingFiles/Info.plist
+++ b/ElementX/SupportingFiles/Info.plist
@@ -77,6 +77,7 @@
NSUserActivityTypes
INSendMessageIntent
+ INStartCallIntent
UIBackgroundModes
diff --git a/ElementX/SupportingFiles/target.yml b/ElementX/SupportingFiles/target.yml
index 98e3820f0..601e96c4d 100644
--- a/ElementX/SupportingFiles/target.yml
+++ b/ElementX/SupportingFiles/target.yml
@@ -82,7 +82,8 @@ targets:
productionAppName: $(PRODUCTION_APP_NAME)
ITSAppUsesNonExemptEncryption: false
NSUserActivityTypes: [
- INSendMessageIntent
+ INSendMessageIntent,
+ INStartCallIntent,
]
NSCameraUsageDescription: To take pictures or videos and send them as a message $(APP_DISPLAY_NAME) needs access to the camera.
NSMicrophoneUsageDescription: To record and send messages with audio, $(APP_DISPLAY_NAME) needs to access the microphone.
diff --git a/NSE/Sources/NotificationServiceExtension.swift b/NSE/Sources/NotificationServiceExtension.swift
index 802fc3200..baac46305 100644
--- a/NSE/Sources/NotificationServiceExtension.swift
+++ b/NSE/Sources/NotificationServiceExtension.swift
@@ -206,12 +206,8 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
return true
}
- var payload = [ElementCallServiceNotificationKey.roomID.rawValue: itemProxy.roomID,
- ElementCallServiceNotificationKey.roomDisplayName.rawValue: itemProxy.roomDisplayName,
- ElementCallServiceNotificationKey.senderID.rawValue: itemProxy.senderID]
- if let senderDisplayName = itemProxy.senderDisplayName {
- payload[ElementCallServiceNotificationKey.senderDisplayName.rawValue] = senderDisplayName
- }
+ let payload = [ElementCallServiceNotificationKey.roomID.rawValue: itemProxy.roomID,
+ ElementCallServiceNotificationKey.roomDisplayName.rawValue: itemProxy.roomDisplayName]
do {
try await CXProvider.reportNewIncomingVoIPPushPayload(payload)