From f6e6e6b78775eed0871a42137f095879f538a738 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 9 Jan 2017 17:19:50 +0100 Subject: [PATCH] CallViewController only accesses CallService via the CallUIAdapter This is an effort to better define boundaries and simplify relationships. This also fixes a theoretical problem where CallKit was showing the in-app call screen before the call was successfully answered, now we wait until the action is fulfilled. // FREEBIE --- Signal/src/call/CallService.swift | 2 -- Signal/src/call/NonCallKitCallUIAdaptee.swift | 4 +++- .../call/Speakerbox/CallKitCallManager.swift | 16 ++++++++++++-- .../Speakerbox/CallKitCallUIAdaptee.swift | 22 +++++++++---------- .../view controllers/CallViewController.swift | 13 +++++------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Signal/src/call/CallService.swift b/Signal/src/call/CallService.swift index 318ad4400..add7791e4 100644 --- a/Signal/src/call/CallService.swift +++ b/Signal/src/call/CallService.swift @@ -578,8 +578,6 @@ fileprivate let timeoutSeconds = 60 let callRecord = TSCall(timestamp: NSDate.ows_millisecondTimeStamp(), withCallNumber: call.remotePhoneNumber, callType: RPRecentCallTypeIncoming, in: thread) callRecord.save() - callUIAdapter.answerCall(call) - let message = DataChannelMessage.forConnected(callId: call.signalingId) if peerConnectionClient.sendDataChannelMessage(data: message.asData()) { Logger.debug("\(TAG) sendDataChannelMessage returned true") diff --git a/Signal/src/call/NonCallKitCallUIAdaptee.swift b/Signal/src/call/NonCallKitCallUIAdaptee.swift index 4c561ecfc..6c33d217f 100644 --- a/Signal/src/call/NonCallKitCallUIAdaptee.swift +++ b/Signal/src/call/NonCallKitCallUIAdaptee.swift @@ -48,7 +48,9 @@ class NonCallKitCallUIAdaptee: CallUIAdaptee { } internal func answerCall(_ call: SignalCall) { - // NO-OP + CallService.signalingQueue.async { + self.callService.handleAnswerCall(call) + } } internal func declineCall(_ call: SignalCall) { diff --git a/Signal/src/call/Speakerbox/CallKitCallManager.swift b/Signal/src/call/Speakerbox/CallKitCallManager.swift index c481bf2ff..a3efc1734 100644 --- a/Signal/src/call/Speakerbox/CallKitCallManager.swift +++ b/Signal/src/call/Speakerbox/CallKitCallManager.swift @@ -5,8 +5,12 @@ import UIKit import CallKit /** - * Based on SpeakerboxCallManager, from the Apple CallKit Example app. Though, it's responsibilities are mostly mirrored (and delegated from) CallKitCallUIAdaptee. - * TODO: Would it simplify things to merge this into CallKitCallUIAdaptee? + * Requests actions from CallKit + * + * @Discussion: + * Based on SpeakerboxCallManager, from the Apple CallKit Example app. Though, it's responsibilities are mostly + * mirrored (and delegated from) CallKitCallUIAdaptee. + * TODO: Would it simplify things to merge this into CallKitCallUIAdaptee? */ @available(iOS 10.0, *) final class CallKitCallManager: NSObject { @@ -52,6 +56,14 @@ final class CallKitCallManager: NSObject { requestTransaction(transaction) } + func answer(call: SignalCall) { + let answerCallAction = CXAnswerCallAction(call: call.localId) + let transaction = CXTransaction() + transaction.addAction(answerCallAction) + + requestTransaction(transaction) + } + private func requestTransaction(_ transaction: CXTransaction) { callController.request(transaction) { error in if let error = error { diff --git a/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift b/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift index d7a8d9113..6982eae5e 100644 --- a/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift +++ b/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift @@ -7,10 +7,10 @@ import CallKit import AVFoundation /** - * Connects user interface to the CallService usin CallKit. + * Connects user interface to the CallService using CallKit. * - * User interface is mapped to CXCall action requests, and if the CXProvider accepts them, - * their corresponding consequences are requested via the CallService + * User interface is routed to the CallManager which requests CXCallActions, and if the CXProvider accepts them, + * their corresponding consequences are implmented in the CXProviderDelegate methods, e.g. using the CallService */ @available(iOS 10.0, *) final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { @@ -84,7 +84,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { } internal func answerCall(_ call: SignalCall) { - showCall(call) + callManager.answer(call: call) } internal func declineCall(_ call: SignalCall) { @@ -144,9 +144,9 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { CallService.signalingQueue.async { self.callService.handleOutgoingCall(call).then { action.fulfill() - }.catch { error in - self.callManager.removeCall(call) - action.fail() + }.catch { error in + self.callManager.removeCall(call) + action.fail() } } @@ -182,13 +182,11 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { // // Trigger the call to be answered via the underlying network service. // call.answerSpeakerboxCall() - // Synchronous to ensure work is done before call is displayed as "answered" - CallService.signalingQueue.sync { + CallService.signalingQueue.async { self.callService.handleAnswerCall(call) + self.showCall(call) + action.fulfill() } - - // Signal to the system that the action has been successfully performed. - action.fulfill() } public func provider(_ provider: CXProvider, perform action: CXEndCallAction) { diff --git a/Signal/src/view controllers/CallViewController.swift b/Signal/src/view controllers/CallViewController.swift index 54364fcd3..2c00196bf 100644 --- a/Signal/src/view controllers/CallViewController.swift +++ b/Signal/src/view controllers/CallViewController.swift @@ -135,7 +135,7 @@ class CallViewController: UIViewController, CallDelegate { let TAG = "[CallViewController]" // Dependencies - let callService: CallService + let callUIAdapter: CallUIAdapter let contactsManager: OWSContactsManager let audioService: CallAudioService @@ -165,7 +165,7 @@ class CallViewController: UIViewController, CallDelegate { required init?(coder aDecoder: NSCoder) { contactsManager = Environment.getCurrent().contactsManager - callService = Environment.getCurrent().callService + let callService = Environment.getCurrent().callService! callUIAdapter = callService.callUIAdapter audioService = CallAudioService() super.init(coder: aDecoder) @@ -173,7 +173,7 @@ class CallViewController: UIViewController, CallDelegate { required init() { contactsManager = Environment.getCurrent().contactsManager - callService = Environment.getCurrent().callService + let callService = Environment.getCurrent().callService! callUIAdapter = callService.callUIAdapter audioService = CallAudioService() super.init(nibName: nil, bundle: nil) @@ -286,7 +286,7 @@ class CallViewController: UIViewController, CallDelegate { if let call = self.call { callUIAdapter.toggleMute(call: call, isMuted: muteButton.isSelected) } else { - Logger.warn("\(TAG) hung up, but call was unexpectedly nil") + Logger.warn("\(TAG) pressed mute, but call was unexpectedly nil") } } @@ -308,9 +308,7 @@ class CallViewController: UIViewController, CallDelegate { return } - CallService.signalingQueue.async { - self.callService.handleAnswerCall(call) - } + callUIAdapter.answerCall(call) } /** @@ -338,7 +336,6 @@ class CallViewController: UIViewController, CallDelegate { } internal func muteDidChange(call: SignalCall, isMuted: Bool) { - Logger.debug("\(TAG) in \(#function)") DispatchQueue.main.async { self.muteButton.isSelected = call.isMuted }