refactor to make CallKit disabled for China mainland

This commit is contained in:
Ryan Zhao 2022-04-21 12:07:21 +10:00
parent 9542b0e0f9
commit fba6dbcf9b
6 changed files with 137 additions and 69 deletions

View File

@ -128,6 +128,7 @@
7B0EFDF2275449AA00FFAAE7 /* TSInfoMessage+Calls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B0EFDF1275449AA00FFAAE7 /* TSInfoMessage+Calls.swift */; };
7B0EFDF4275490EA00FFAAE7 /* ringing.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 7B0EFDF3275490EA00FFAAE7 /* ringing.mp3 */; };
7B0EFDF62755CC5400FFAAE7 /* CallMissedTipsModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B0EFDF52755CC5400FFAAE7 /* CallMissedTipsModal.swift */; };
7B13E1E92810F01300BD4F64 /* SessionCallManager+Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B13E1E82810F01300BD4F64 /* SessionCallManager+Action.swift */; };
7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E1271E743B00848B49 /* OWSSounds.swift */; };
7B1581E4271FC59D00848B49 /* CallModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E3271FC59C00848B49 /* CallModal.swift */; };
7B1581E6271FD2A100848B49 /* VideoPreviewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E5271FD2A100848B49 /* VideoPreviewVC.swift */; };
@ -1115,6 +1116,7 @@
7B0EFDF1275449AA00FFAAE7 /* TSInfoMessage+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSInfoMessage+Calls.swift"; sourceTree = "<group>"; };
7B0EFDF3275490EA00FFAAE7 /* ringing.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = ringing.mp3; sourceTree = "<group>"; };
7B0EFDF52755CC5400FFAAE7 /* CallMissedTipsModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMissedTipsModal.swift; sourceTree = "<group>"; };
7B13E1E82810F01300BD4F64 /* SessionCallManager+Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionCallManager+Action.swift"; sourceTree = "<group>"; };
7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = "<group>"; };
7B1581E3271FC59C00848B49 /* CallModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallModal.swift; sourceTree = "<group>"; };
7B1581E5271FD2A100848B49 /* VideoPreviewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPreviewVC.swift; sourceTree = "<group>"; };
@ -2098,6 +2100,7 @@
7BC707F127290ACB002817AD /* SessionCallManager.swift */,
7BA6890C27325CCC00EFC32F /* SessionCallManager+CXCallController.swift */,
7BA6890E27325CE300EFC32F /* SessionCallManager+CXProvider.swift */,
7B13E1E82810F01300BD4F64 /* SessionCallManager+Action.swift */,
);
path = "Call Management";
sourceTree = "<group>";
@ -4952,6 +4955,7 @@
7B7CB190270FB2150079FF93 /* MiniCallView.swift in Sources */,
B875885A264503A6000E60D0 /* JoinOpenGroupModal.swift in Sources */,
B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */,
7B13E1E92810F01300BD4F64 /* SessionCallManager+Action.swift in Sources */,
C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */,
7B1581E827210ECC00848B49 /* RenderView.swift in Sources */,
7BC707F227290ACB002817AD /* SessionCallManager.swift in Sources */,

View File

@ -0,0 +1,47 @@
extension SessionCallManager {
@discardableResult
public func startCallAction() -> Bool {
guard let call = self.currentCall else { return false }
call.startSessionCall()
return true
}
@discardableResult
public func answerCallAction() -> Bool {
guard let call = self.currentCall else { return false }
if let _ = CurrentAppContext().frontmostViewController() as? CallVC {
call.answerSessionCall()
} else {
guard let presentingVC = CurrentAppContext().frontmostViewController() else { return false } // FIXME: Handle more gracefully
let callVC = CallVC(for: self.currentCall!)
if let conversationVC = presentingVC as? ConversationVC {
callVC.conversationVC = conversationVC
conversationVC.inputAccessoryView?.isHidden = true
conversationVC.inputAccessoryView?.alpha = 0
}
presentingVC.present(callVC, animated: true) {
call.answerSessionCall()
}
}
return true
}
@discardableResult
public func endCallAction() -> Bool {
guard let call = self.currentCall else { return false }
call.endSessionCall()
if call.didTimeout {
reportCurrentCallEnded(reason: .unanswered)
} else {
reportCurrentCallEnded(reason: nil)
}
return true
}
@discardableResult
public func setMutedCallAction(isMuted: Bool) -> Bool {
guard let call = self.currentCall else { return false }
call.isMuted = isMuted
return true
}
}

View File

@ -5,45 +5,62 @@ extension SessionCallManager {
public func startCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
guard case .offer = call.mode else { return }
guard !call.hasConnected else { return }
let handle = CXHandle(type: .generic, value: call.sessionID)
let startCallAction = CXStartCallAction(call: call.callID, handle: handle)
startCallAction.isVideo = false
let transaction = CXTransaction()
transaction.addAction(startCallAction)
reportOutgoingCall(call)
requestTransaction(transaction, completion: completion)
if callController != nil {
let handle = CXHandle(type: .generic, value: call.sessionID)
let startCallAction = CXStartCallAction(call: call.callID, handle: handle)
startCallAction.isVideo = false
let transaction = CXTransaction()
transaction.addAction(startCallAction)
requestTransaction(transaction, completion: completion)
} else {
startCallAction()
completion?(nil)
}
}
public func answerCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
let answerCallAction = CXAnswerCallAction(call: call.callID)
let transaction = CXTransaction()
transaction.addAction(answerCallAction)
if callController != nil {
let answerCallAction = CXAnswerCallAction(call: call.callID)
let transaction = CXTransaction()
transaction.addAction(answerCallAction)
requestTransaction(transaction, completion: completion)
requestTransaction(transaction, completion: completion)
} else {
answerCallAction()
completion?(nil)
}
}
public func endCall(_ call: SessionCall, completion: ((Error?) -> Void)?) {
let endCallAction = CXEndCallAction(call: call.callID)
let transaction = CXTransaction()
transaction.addAction(endCallAction)
if callController != nil {
let endCallAction = CXEndCallAction(call: call.callID)
let transaction = CXTransaction()
transaction.addAction(endCallAction)
requestTransaction(transaction, completion: completion)
requestTransaction(transaction, completion: completion)
} else {
endCallAction()
completion?(nil)
}
}
// Not currently in use
public func setOnHoldStatus(for call: SessionCall) {
let setHeldCallAction = CXSetHeldCallAction(call: call.callID, onHold: true)
let transaction = CXTransaction()
transaction.addAction(setHeldCallAction)
if callController != nil {
let setHeldCallAction = CXSetHeldCallAction(call: call.callID, onHold: true)
let transaction = CXTransaction()
transaction.addAction(setHeldCallAction)
requestTransaction(transaction)
requestTransaction(transaction)
}
}
private func requestTransaction(_ transaction: CXTransaction, completion: ((Error?) -> Void)? = nil) {
callController.request(transaction) { error in
callController?.request(transaction) { error in
if let error = error {
SNLog("Error requesting transaction: \(error)")
} else {

View File

@ -8,9 +8,11 @@ extension SessionCallManager: CXProviderDelegate {
public func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
AssertIsOnMainThread()
guard let call = self.currentCall else { return action.fail() }
call.startSessionCall()
action.fulfill()
if startCallAction() {
action.fulfill()
} else {
action.fail()
}
}
public func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
@ -18,21 +20,11 @@ extension SessionCallManager: CXProviderDelegate {
print("[CallKit] Perform CXAnswerCallAction")
guard let call = self.currentCall else { return action.fail() }
if CurrentAppContext().isMainAppAndActive {
if let _ = CurrentAppContext().frontmostViewController() as? CallVC {
call.answerSessionCall()
if answerCallAction() {
action.fulfill()
} else {
guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // FIXME: Handle more gracefully
let callVC = CallVC(for: self.currentCall!)
if let conversationVC = presentingVC as? ConversationVC {
callVC.conversationVC = conversationVC
conversationVC.inputAccessoryView?.isHidden = true
conversationVC.inputAccessoryView?.alpha = 0
}
presentingVC.present(callVC, animated: true) {
call.answerSessionCall()
}
action.fail()
}
action.fulfill()
} else {
call.answerSessionCallInBackground(action: action)
}
@ -41,22 +33,21 @@ extension SessionCallManager: CXProviderDelegate {
public func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
print("[CallKit] Perform CXEndCallAction")
AssertIsOnMainThread()
guard let call = self.currentCall else { return action.fail() }
call.endSessionCall()
if call.didTimeout {
reportCurrentCallEnded(reason: .unanswered)
if endCallAction() {
action.fulfill()
} else {
reportCurrentCallEnded(reason: nil)
action.fail()
}
action.fulfill()
}
public func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
print("[CallKit] Perform CXSetMutedCallAction, isMuted: \(action.isMuted)")
AssertIsOnMainThread()
guard let call = self.currentCall else { return action.fail() }
call.isMuted = action.isMuted
action.fulfill()
if setMutedCallAction(isMuted: action.isMuted) {
action.fulfill()
} else {
action.fail()
}
}
public func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) {

View File

@ -2,8 +2,8 @@ import CallKit
import SessionMessagingKit
public final class SessionCallManager: NSObject {
let provider: CXProvider
let callController = CXCallController()
let provider: CXProvider?
let callController: CXCallController?
var currentCall: SessionCall? = nil {
willSet {
if (newValue != nil) {
@ -49,12 +49,16 @@ public final class SessionCallManager: NSObject {
init(useSystemCallLog: Bool = false) {
AssertIsOnMainThread()
self.provider = type(of: self).sharedProvider(useSystemCallLog: useSystemCallLog)
if SSKPreferences.isCallKitSupported {
self.provider = type(of: self).sharedProvider(useSystemCallLog: useSystemCallLog)
self.callController = CXCallController()
} else {
self.provider = nil
self.callController = nil
}
super.init()
// We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings
self.provider.setDelegate(self, queue: nil)
self.provider?.setDelegate(self, queue: nil)
}
// MARK: Report calls
@ -63,10 +67,10 @@ public final class SessionCallManager: NSObject {
UserDefaults(suiteName: "group.com.loki-project.loki-messenger")?.set(true, forKey: "isCallOngoing")
call.stateDidChange = {
if call.hasStartedConnecting {
self.provider.reportOutgoingCall(with: call.callID, startedConnectingAt: call.connectingDate)
self.provider?.reportOutgoingCall(with: call.callID, startedConnectingAt: call.connectingDate)
}
if call.hasConnected {
self.provider.reportOutgoingCall(with: call.callID, connectedAt: call.connectedDate)
self.provider?.reportOutgoingCall(with: call.callID, connectedAt: call.connectedDate)
}
}
}
@ -74,21 +78,26 @@ public final class SessionCallManager: NSObject {
public func reportIncomingCall(_ call: SessionCall, callerName: String, completion: @escaping (Error?) -> Void) {
AssertIsOnMainThread()
// Construct a CXCallUpdate describing the incoming call, including the caller.
let update = CXCallUpdate()
update.localizedCallerName = callerName
update.remoteHandle = CXHandle(type: .generic, value: call.callID.uuidString)
update.hasVideo = false
if let provider = provider {
// Construct a CXCallUpdate describing the incoming call, including the caller.
let update = CXCallUpdate()
update.localizedCallerName = callerName
update.remoteHandle = CXHandle(type: .generic, value: call.callID.uuidString)
update.hasVideo = false
disableUnsupportedFeatures(callUpdate: update)
disableUnsupportedFeatures(callUpdate: update)
// Report the incoming call to the system
self.provider.reportNewIncomingCall(with: call.callID, update: update) { error in
guard error == nil else {
self.reportCurrentCallEnded(reason: .failed)
completion(error)
return
// Report the incoming call to the system
provider.reportNewIncomingCall(with: call.callID, update: update) { error in
guard error == nil else {
self.reportCurrentCallEnded(reason: .failed)
completion(error)
return
}
UserDefaults(suiteName: "group.com.loki-project.loki-messenger")?.set(true, forKey: "isCallOngoing")
completion(nil)
}
} else {
UserDefaults(suiteName: "group.com.loki-project.loki-messenger")?.set(true, forKey: "isCallOngoing")
completion(nil)
}
@ -97,7 +106,7 @@ public final class SessionCallManager: NSObject {
public func reportCurrentCallEnded(reason: CXCallEndedReason?) {
guard let call = currentCall else { return }
if let reason = reason {
self.provider.reportCall(with: call.callID, endedAt: nil, reason: reason)
self.provider?.reportCall(with: call.callID, endedAt: nil, reason: reason)
switch (reason) {
case .answeredElsewhere: call.updateCallMessage(mode: .answeredElsewhere)
case .unanswered: call.updateCallMessage(mode: .unanswered)

View File

@ -39,7 +39,7 @@ public class SSKPreferences: NSObject {
}
@objc
public static var isCallKitSupported() -> Bool {
public static var isCallKitSupported: Bool {
let userLocale = NSLocale.current
guard let regionCode = userLocale.regionCode else { return false }