diff --git a/Linphone/GeneratedGit.swift b/Linphone/GeneratedGit.swift index 240baa0e4..fc44876ff 100644 --- a/Linphone/GeneratedGit.swift +++ b/Linphone/GeneratedGit.swift @@ -2,6 +2,6 @@ import Foundation public enum AppGitInfo { public static let branch = "master" - public static let commit = "1dbbe6a53" + public static let commit = "61931138b" public static let tag = "6.1.0-alpha" } diff --git a/Linphone/LinphoneApp.swift b/Linphone/LinphoneApp.swift index 2b36bf4a3..9827e0693 100644 --- a/Linphone/LinphoneApp.swift +++ b/Linphone/LinphoneApp.swift @@ -20,6 +20,7 @@ import SwiftUI import linphonesw import UserNotifications +import Intents let accountTokenNotification = Notification.Name("AccountCreationTokenReceived") var displayedChatroomPeerAddr: String? @@ -108,7 +109,28 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele } } } - + } + + func application(_ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + + guard let interaction = userActivity.interaction, + let intent = interaction.intent as? INStartCallIntent, + let person = intent.contacts?.first, + let number = person.personHandle?.value else { return false } + + let isVideo = intent.callCapability == .videoCall + + Log.info("[AppDelegate][INStartCallIntent] Generic call intent received for number: \(number) isVideo: \(isVideo)") + + CoreContext.shared.performActionOnCoreQueueWhenCoreIsStarted { core in + if let address = core.interpretUrl(url: number, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) { + TelecomManager.shared.doCallOrJoinConf(address: address, isVideo: isVideo) + } + } + + return true } func applicationWillTerminate(_ application: UIApplication) { @@ -240,6 +262,22 @@ struct RootView: View { pendingURL = url } } + .onContinueUserActivity("INStartCallIntent") { activity in + guard let interaction = activity.interaction, + let intent = interaction.intent as? INStartCallIntent, + let person = intent.contacts?.first, + let number = person.personHandle?.value else { return } + + let isVideo = intent.callCapability == .videoCall + + Log.info("[INStartCallIntent] Generic call intent received for number: \(number) isVideo: \(isVideo)") + + coreContext.performActionOnCoreQueueWhenCoreIsStarted { core in + if let address = core.interpretUrl(url: number, applyInternationalPrefix: LinphoneUtils.applyInternationalPrefix(core: core)) { + telecomManager.doCallOrJoinConf(address: address, isVideo: isVideo) + } + } + } } diff --git a/LinphoneApp.xcodeproj/project.pbxproj b/LinphoneApp.xcodeproj/project.pbxproj index 2bdc50c4d..7bc528acb 100644 --- a/LinphoneApp.xcodeproj/project.pbxproj +++ b/LinphoneApp.xcodeproj/project.pbxproj @@ -149,6 +149,8 @@ D78E062C2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E062B2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift */; }; D78E062E2BEA69F400CE3783 /* AudioRouteBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E062D2BEA69F400CE3783 /* AudioRouteBottomSheet.swift */; }; D78E06302BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E062F2BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift */; }; + D792F15A2F02BCC2002E3225 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D792F1592F02BCC2002E3225 /* Intents.framework */; }; + D792F1612F02BCC2002E3225 /* intentsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D792F1582F02BCC2002E3225 /* intentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D795F57E2EC5F9500022C17D /* RecordingsListFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D795F57D2EC5F9480022C17D /* RecordingsListFragment.swift */; }; D795F5802EC5F9660022C17D /* RecordingsListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D795F57F2EC5F95B0022C17D /* RecordingsListViewModel.swift */; }; D795F5832EC6133C0022C17D /* RecordingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D795F5822EC6133A0022C17D /* RecordingModel.swift */; }; @@ -231,6 +233,13 @@ remoteGlobalIDString = D7458F2E2E0BDCF4000C957A; remoteInfo = linphoneExtension; }; + D792F15F2F02BCC2002E3225 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D719ABAB2ABC67BF00B41C10 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D792F1572F02BCC2002E3225; + remoteInfo = intentsExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -241,6 +250,7 @@ dstSubfolderSpec = 13; files = ( 660AAF7F2B839272004C0FA6 /* msgNotificationService.appex in Embed Foundation Extensions */, + D792F1612F02BCC2002E3225 /* intentsExtension.appex in Embed Foundation Extensions */, D7458F392E0BDCF4000C957A /* linphoneExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; @@ -397,6 +407,8 @@ D78E062B2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallStatisticsSheetBottomSheet.swift; sourceTree = ""; }; D78E062D2BEA69F400CE3783 /* AudioRouteBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRouteBottomSheet.swift; sourceTree = ""; }; D78E062F2BEA6A4A00CE3783 /* ChangeLayoutBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangeLayoutBottomSheet.swift; sourceTree = ""; }; + D792F1582F02BCC2002E3225 /* intentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = intentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + D792F1592F02BCC2002E3225 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; D795F57D2EC5F9480022C17D /* RecordingsListFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingsListFragment.swift; sourceTree = ""; }; D795F57F2EC5F95B0022C17D /* RecordingsListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingsListViewModel.swift; sourceTree = ""; }; D795F5822EC6133A0022C17D /* RecordingModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingModel.swift; sourceTree = ""; }; @@ -469,10 +481,18 @@ ); target = D7458F2E2E0BDCF4000C957A /* linphoneExtension */; }; + D792F1642F02BCC2002E3225 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = D792F1572F02BCC2002E3225 /* intentsExtension */; + }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ D7458F302E0BDCF4000C957A /* linphoneExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D7458F3C2E0BDCF4000C957A /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = linphoneExtension; sourceTree = ""; }; + D792F15B2F02BCC2002E3225 /* intentsExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (D792F1642F02BCC2002E3225 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = intentsExtension; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -505,6 +525,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D792F1552F02BCC2002E3225 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D792F15A2F02BCC2002E3225 /* Intents.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -652,6 +680,7 @@ D719ABB52ABC67BF00B41C10 /* Linphone */, 660AAF7C2B839272004C0FA6 /* msgNotificationService */, D7458F302E0BDCF4000C957A /* linphoneExtension */, + D792F15B2F02BCC2002E3225 /* intentsExtension */, D7DF8BE52E2104DC003A3BC7 /* Frameworks */, D719ABB42ABC67BF00B41C10 /* Products */, ); @@ -663,6 +692,7 @@ D719ABB32ABC67BF00B41C10 /* LinphoneApp.app */, 660AAF7B2B839271004C0FA6 /* msgNotificationService.appex */, D7458F2F2E0BDCF4000C957A /* linphoneExtension.appex */, + D792F1582F02BCC2002E3225 /* intentsExtension.appex */, ); name = Products; sourceTree = ""; @@ -1137,6 +1167,7 @@ D7DF8BE52E2104DC003A3BC7 /* Frameworks */ = { isa = PBXGroup; children = ( + D792F1592F02BCC2002E3225 /* Intents.framework */, ); name = Frameworks; sourceTree = ""; @@ -1177,6 +1208,7 @@ dependencies = ( 660AAF7E2B839272004C0FA6 /* PBXTargetDependency */, D7458F382E0BDCF4000C957A /* PBXTargetDependency */, + D792F1602F02BCC2002E3225 /* PBXTargetDependency */, ); name = LinphoneApp; productName = Linphone; @@ -1205,6 +1237,28 @@ productReference = D7458F2F2E0BDCF4000C957A /* linphoneExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + D792F1572F02BCC2002E3225 /* intentsExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = D792F1652F02BCC2002E3225 /* Build configuration list for PBXNativeTarget "intentsExtension" */; + buildPhases = ( + D792F1542F02BCC2002E3225 /* Sources */, + D792F1552F02BCC2002E3225 /* Frameworks */, + D792F1562F02BCC2002E3225 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + D792F15B2F02BCC2002E3225 /* intentsExtension */, + ); + name = intentsExtension; + packageProductDependencies = ( + ); + productName = intentsExtension; + productReference = D792F1582F02BCC2002E3225 /* intentsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1212,7 +1266,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1640; + LastSwiftUpdateCheck = 2620; LastUpgradeCheck = 1430; TargetAttributes = { 660AAF7A2B839271004C0FA6 = { @@ -1225,6 +1279,9 @@ D7458F2E2E0BDCF4000C957A = { CreatedOnToolsVersion = 16.4; }; + D792F1572F02BCC2002E3225 = { + CreatedOnToolsVersion = 26.2; + }; }; }; buildConfigurationList = D719ABAE2ABC67BF00B41C10 /* Build configuration list for PBXProject "LinphoneApp" */; @@ -1265,6 +1322,7 @@ D719ABB22ABC67BF00B41C10 /* LinphoneApp */, 660AAF7A2B839271004C0FA6 /* msgNotificationService */, D7458F2E2E0BDCF4000C957A /* linphoneExtension */, + D792F1572F02BCC2002E3225 /* intentsExtension */, ); }; /* End PBXProject section */ @@ -1309,6 +1367,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D792F1562F02BCC2002E3225 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1549,6 +1614,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + D792F1542F02BCC2002E3225 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1562,6 +1634,11 @@ target = D7458F2E2E0BDCF4000C957A /* linphoneExtension */; targetProxy = D7458F372E0BDCF4000C957A /* PBXContainerItemProxy */; }; + D792F1602F02BCC2002E3225 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D792F1572F02BCC2002E3225 /* intentsExtension */; + targetProxy = D792F15F2F02BCC2002E3225 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1987,6 +2064,78 @@ }; name = Release; }; + D792F1622F02BCC2002E3225 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = intentsExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = intentsExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 26.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.intentsExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D792F1632F02BCC2002E3225 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = Z2V957B3D6; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = intentsExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = intentsExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 26.2; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.intentsExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2026,6 +2175,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D792F1652F02BCC2002E3225 /* Build configuration list for PBXNativeTarget "intentsExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D792F1622F02BCC2002E3225 /* Debug */, + D792F1632F02BCC2002E3225 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ diff --git a/intentsExtension/Info.plist b/intentsExtension/Info.plist new file mode 100644 index 000000000..e329e1950 --- /dev/null +++ b/intentsExtension/Info.plist @@ -0,0 +1,22 @@ + + + + + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsSupported + + INStartCallIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).IntentHandler + + + diff --git a/intentsExtension/IntentHandler.swift b/intentsExtension/IntentHandler.swift new file mode 100644 index 000000000..4b8157edb --- /dev/null +++ b/intentsExtension/IntentHandler.swift @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-iphone + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import Intents + +class IntentHandler: INExtension { + override func handler(for intent: INIntent) -> Any { + return self + } +} + +// MARK: - Generic Call +extension IntentHandler: INStartCallIntentHandling { + func handle(intent: INStartCallIntent, + completion: @escaping (INStartCallIntentResponse) -> Void) { + + guard let number = intent.contacts?.first?.personHandle?.value else { + completion(.init(code: .failure, userActivity: nil)) + return + } + + let isVideo = intent.callCapability == .videoCall + let activity = NSUserActivity(activityType: "org.linphone.startCall") + activity.userInfo = ["number": number, "isVideo": isVideo] + + completion(.init(code: .continueInApp, userActivity: activity)) + } +}