From ce3780e44a5d4e1467e08e78da9175ccbdc5bed0 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 6 Jan 2017 15:38:35 +0100 Subject: [PATCH] Wip smashign providerdelgate into UIAdaptee --- .../CallNotificationsAdapter.swift | 9 ++- .../Speakerbox/CallKitCallUIAdaptee.swift | 28 ++++---- .../Speakerbox/CallKitProviderDelegate.swift | 66 ++++++++++++++----- .../call/UserInterface/CallUIAdapter.swift | 13 +++- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift b/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift index 5f0badf3d..3cfd2ca12 100644 --- a/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift +++ b/Signal/src/UserInterface/Notifications/CallNotificationsAdapter.swift @@ -3,6 +3,9 @@ import Foundation +/** + * Present call related notifications to the user. + */ @objc(OWSCallNotificationsAdapter) class CallNotificationsAdapter: NSObject { @@ -10,9 +13,9 @@ class CallNotificationsAdapter: NSObject { let adaptee: OWSCallNotificationsAdaptee override init() { - // TODO We can't mix UINotification (NotificationManager) with the UNNotifications - // Because registering message categories in one, clobbers the notifications in the other. - // We have to first port *all* the existing UINotifications to UNNotifications + // TODO We can't mix UILocalNotification (NotificationManager) with the UNNotifications + // Because registering message categories in one, clobbers the registered categories from the other + // We have to first port *all* the existing UINotification categories to UNNotifications // which is a good thing to do, but in trying to limit the scope of changes that's been // left out for now. // if #available(iOS 10.0, *) { diff --git a/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift b/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift index 7cd78f1f2..8296b27f9 100644 --- a/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift +++ b/Signal/src/call/Speakerbox/CallKitCallUIAdaptee.swift @@ -3,6 +3,10 @@ import Foundation +/** + * CallKit backed implementation of UI Activity related to Signal Calls + * TODO: Code Cleanup: It might be more straight forward to roll this into the CallKitProviderDelegate. + */ @available(iOS 10.0, *) class CallKitCallUIAdaptee: CallUIAdaptee { @@ -13,15 +17,15 @@ class CallKitCallUIAdaptee: CallUIAdaptee { init(callService: CallService, notificationsAdapter: CallNotificationsAdapter) { self.callManager = CallKitCallManager() - self.providerDelegate = CallKitProviderDelegate(callManager: callManager, callService: callService) + self.providerDelegate = CallKitProviderDelegate(callService: callService, notificationsAdapter: notificationsAdapter) self.notificationsAdapter = notificationsAdapter } public func startOutgoingCall(_ call: SignalCall) { // Add the new outgoing call to the app's list of calls. // So we can find it in the provider delegate callbacks. - self.callManager.addCall(call) - providerDelegate.callManager.startCall(call) +// self.callManager.addCall(call) +// providerDelegate.callManager.startCall(call) } public func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) { @@ -29,15 +33,15 @@ class CallKitCallUIAdaptee: CallUIAdaptee { // Crux is, the peerconnectionclient is what controls the audio channel. // But a peerconnectionclient is per call. // While this providerDelegate is an app singleton. - providerDelegate.audioManager = audioManager - - providerDelegate.reportIncomingCall(call) { error in - if error == nil { - Logger.debug("\(self.TAG) successfully reported incoming call.") - } else { - Logger.error("\(self.TAG) providerDelegate.reportIncomingCall failed with error: \(error)") - } - } +// providerDelegate.audioManager = audioManager +// +// providerDelegate.reportIncomingCall(call) { error in +// if error == nil { +// Logger.debug("\(self.TAG) successfully reported incoming call.") +// } else { +// Logger.error("\(self.TAG) providerDelegate.reportIncomingCall failed with error: \(error)") +// } +// } } public func reportMissedCall(_ call: SignalCall, callerName: String) { diff --git a/Signal/src/call/Speakerbox/CallKitProviderDelegate.swift b/Signal/src/call/Speakerbox/CallKitProviderDelegate.swift index 78d36e90c..49763607f 100644 --- a/Signal/src/call/Speakerbox/CallKitProviderDelegate.swift +++ b/Signal/src/call/Speakerbox/CallKitProviderDelegate.swift @@ -6,12 +6,19 @@ import UIKit import CallKit import AVFoundation +/** + * Connects requests for CallKit actions (CXActions) with their corresponding consequences in CallService + * + * TODO: Code cleanup: The responsibilities largely overlap with the CallKitCallUIAdapter. Maybe they should be merged. + */ @available(iOS 10.0, *) -final class CallKitProviderDelegate: NSObject, CXProviderDelegate { +final class CallKitProviderDelegate: NSObject, CallUIAdaptee, CXProviderDelegate { let TAG = "[CallKitProviderDelegate]" - let callManager: CallKitCallManager - let callService: CallService + + private let callManager: CallKitCallManager + private let callService: CallService + internal let notificationsAdapter: CallNotificationsAdapter private let provider: CXProvider // FIXME - I might be thinking about this the wrong way. @@ -22,16 +29,6 @@ final class CallKitProviderDelegate: NSObject, CXProviderDelegate { // It seems like a mess to reconcile this difference in cardinality. But... here we are. var audioManager: SignalCallAudioManager? - init(callManager: CallKitCallManager, callService: CallService) { - self.callService = callService - self.callManager = callManager - provider = CXProvider(configuration: type(of: self).providerConfiguration) - - super.init() - - provider.setDelegate(self, queue: nil) - } - /// The app's provider configuration, representing its CallKit capabilities static var providerConfiguration: CXProviderConfiguration { let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application") @@ -52,8 +49,28 @@ final class CallKitProviderDelegate: NSObject, CXProviderDelegate { return providerConfiguration } - /// Use CXProvider to report the incoming call to the system - func reportIncomingCall(_ call: SignalCall, completion: ((NSError?) -> Void)? = nil) { + init(callService: CallService, notificationsAdapter: CallNotificationsAdapter) { + self.callManager = CallKitCallManager() + self.callService = callService + self.notificationsAdapter = notificationsAdapter + self.provider = CXProvider(configuration: type(of: self).providerConfiguration) + + super.init() + + self.provider.setDelegate(self, queue: nil) + } + + // MARK: CallUIAdaptee + + internal func startOutgoingCall(_ call: SignalCall) { + // Add the new outgoing call to the app's list of calls. + // So we can find it in the provider delegate callbacks. + callManager.addCall(call) + callManager.startCall(call) + } + + // TODO CodeCleanup: remove unused audiomanager + internal func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) { // Construct a CXCallUpdate describing the incoming call, including the caller. let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber) @@ -65,14 +82,27 @@ final class CallKitProviderDelegate: NSObject, CXProviderDelegate { Only add incoming call to the app's list of calls if the call was allowed (i.e. there was no error) since calls may be "denied" for various legitimate reasons. See CXErrorCodeIncomingCallError. */ - if error == nil { - self.callManager.addCall(call) + guard error == nil else { + Logger.error("\(self.TAG) failed to report new incoming call") + return } - completion?(error as? NSError) + self.callManager.addCall(call) } } + internal func answerCall(_ call: SignalCall) { + showCall(call) + } + + internal func declineCall(_ call: SignalCall) { + callManager.end(call: call) + } + + internal func endCall(_ call: SignalCall) { + callManager.end(call: call) + } + // MARK: CXProviderDelegate func providerDidReset(_ provider: CXProvider) { diff --git a/Signal/src/call/UserInterface/CallUIAdapter.swift b/Signal/src/call/UserInterface/CallUIAdapter.swift index 66a8b89b5..baacfc5b0 100644 --- a/Signal/src/call/UserInterface/CallUIAdapter.swift +++ b/Signal/src/call/UserInterface/CallUIAdapter.swift @@ -6,6 +6,8 @@ import PromiseKit import CallKit protocol CallUIAdaptee { + var notificationsAdapter: CallNotificationsAdapter { get } + func startOutgoingCall(_ call: SignalCall) func reportIncomingCall(_ call: SignalCall, callerName: String, audioManager: SignalCallAudioManager) func reportMissedCall(_ call: SignalCall, callerName: String) @@ -14,11 +16,16 @@ protocol CallUIAdaptee { func endCall(_ call: SignalCall) } +// Shared default implementations extension CallUIAdaptee { - public func showCall(_ call: SignalCall) { + internal func showCall(_ call: SignalCall) { let callNotificationName = CallService.callServiceActiveCallNotificationName() NotificationCenter.default.post(name: NSNotification.Name(rawValue: callNotificationName), object: call) } + + internal func reportMissedCall(_ call: SignalCall, callerName: String) { + notificationsAdapter.presentMissedCall(call, callerName: callerName) + } } /** @@ -34,14 +41,14 @@ class CallUIAdapter { required init(callService: CallService, contactsManager: OWSContactsManager, notificationsAdapter: CallNotificationsAdapter) { self.contactsManager = contactsManager if Platform.isSimulator { - // Callkit doesn't seem entirely supported in simulator. + // CallKit doesn't seem entirely supported in simulator. // e.g. you can't receive calls in the call screen. // So we use the non-call kit call UI. Logger.info("\(TAG) choosing non-callkit adaptee for simulator.") adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter) } else if #available(iOS 10.0, *) { Logger.info("\(TAG) choosing callkit adaptee for iOS10+") - adaptee = CallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter) + adaptee = CallKitProviderDelegate(callService: callService, notificationsAdapter: notificationsAdapter) } else { Logger.info("\(TAG) choosing non-callkit adaptee for older iOS") adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)