Rip out a bunch of NonCallKitCallUIAdaptee

This commit is contained in:
Max Radermacher 2024-05-16 18:24:04 -05:00 committed by GitHub
parent cab7fb76f4
commit 503d5c635e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 197 additions and 734 deletions

View File

@ -1394,7 +1394,6 @@
886BB3D325BA0CA400079781 /* SetWallpaperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88ABAB8C25B8BE1E0008C78A /* SetWallpaperViewController.swift */; };
886BB3D425BA0CA900079781 /* ColorAndWallpaperSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88ABAB8A25B8B3CC0008C78A /* ColorAndWallpaperSettingsViewController.swift */; };
886CB07824E77E5B00753909 /* silence.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 886CB07724E77E5B00753909 /* silence.aiff */; };
886CB07C24E78F2200753909 /* Reflection.m4r in Resources */ = {isa = PBXBuildFile; fileRef = 886CB07B24E78F2200753909 /* Reflection.m4r */; };
8871B16F25F007DE00D4E070 /* ProfileSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8871B16E25F007DE00D4E070 /* ProfileSettingsViewController.swift */; };
8871B17125F0139D00D4E070 /* ProfileNameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8871B17025F0139D00D4E070 /* ProfileNameViewController.swift */; };
8876CE4A26A914B8002217ED /* SentMediaQualitySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8876CE4926A914B7002217ED /* SentMediaQualitySettingsViewController.swift */; };
@ -1490,7 +1489,7 @@
88D1D40422EF8A9700F472C5 /* ThreadDetailsInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D1D40322EF8A9700F472C5 /* ThreadDetailsInteraction.swift */; };
88D23D1223CEBFB200B0E74B /* NotificationActionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1123CEBFB200B0E74B /* NotificationActionHandler.swift */; };
88D23D2023CEC0C700B0E74B /* IndividualCallService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1423CEC0C700B0E74B /* IndividualCallService.swift */; };
88D23D2323CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1823CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift */; };
88D23D2323CEC0C700B0E74B /* SimulatorCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1823CEC0C700B0E74B /* SimulatorCallUIAdaptee.swift */; };
88D23D2423CEC0C700B0E74B /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1A23CEC0C700B0E74B /* CallKitCallManager.swift */; };
88D23D2523CEC0C700B0E74B /* CallKitCallUIAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1B23CEC0C700B0E74B /* CallKitCallUIAdaptee.swift */; };
88D23D2623CEC0C700B0E74B /* CallUIAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D23D1C23CEC0C700B0E74B /* CallUIAdapter.swift */; };
@ -4215,7 +4214,6 @@
886A58C8276A760600A1099B /* SubscriptionManagerImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionManagerImpl.swift; sourceTree = "<group>"; };
886A58C9276A760600A1099B /* ReceiptCredentialRedemptionJobQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiptCredentialRedemptionJobQueue.swift; sourceTree = "<group>"; };
886CB07724E77E5B00753909 /* silence.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = silence.aiff; sourceTree = "<group>"; };
886CB07B24E78F2200753909 /* Reflection.m4r */ = {isa = PBXFileReference; lastKnownFileType = file; path = Reflection.m4r; sourceTree = "<group>"; };
8871B16E25F007DE00D4E070 /* ProfileSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSettingsViewController.swift; sourceTree = "<group>"; };
8871B17025F0139D00D4E070 /* ProfileNameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileNameViewController.swift; sourceTree = "<group>"; };
8876CE4926A914B7002217ED /* SentMediaQualitySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentMediaQualitySettingsViewController.swift; sourceTree = "<group>"; };
@ -4352,7 +4350,7 @@
88D23D0D23CEBF6000B0E74B /* IndividualCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndividualCall.swift; sourceTree = "<group>"; };
88D23D1123CEBFB200B0E74B /* NotificationActionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationActionHandler.swift; sourceTree = "<group>"; };
88D23D1423CEC0C700B0E74B /* IndividualCallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndividualCallService.swift; sourceTree = "<group>"; };
88D23D1823CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonCallKitCallUIAdaptee.swift; sourceTree = "<group>"; };
88D23D1823CEC0C700B0E74B /* SimulatorCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimulatorCallUIAdaptee.swift; sourceTree = "<group>"; };
88D23D1A23CEC0C700B0E74B /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = "<group>"; };
88D23D1B23CEC0C700B0E74B /* CallKitCallUIAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallUIAdaptee.swift; sourceTree = "<group>"; };
88D23D1C23CEC0C700B0E74B /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallUIAdapter.swift; sourceTree = "<group>"; };
@ -5798,7 +5796,6 @@
isa = PBXGroup;
children = (
34074FC5203E5435004596AE /* messageReceivedSounds */,
34C3C78B20409F320000134C /* ringtoneSounds */,
34CF0783203E6B77005C4D61 /* busy_tone_ansi.caf */,
34CF0786203E6B78005C4D61 /* end_call_tone_cept.caf */,
88D6E93E254CF712003142D9 /* group_call_join.aiff */,
@ -6590,15 +6587,6 @@
path = views;
sourceTree = "<group>";
};
34C3C78B20409F320000134C /* ringtoneSounds */ = {
isa = PBXGroup;
children = (
886CB07B24E78F2200753909 /* Reflection.m4r */,
);
name = ringtoneSounds;
path = Signal/AudioFiles/ringtoneSounds;
sourceTree = SOURCE_ROOT;
};
34C6B0A41FA0E46F00D35993 /* Assets */ = {
isa = PBXGroup;
children = (
@ -8894,11 +8882,11 @@
34B3F83B1E8DF1700035BE1A /* IndividualCallViewController.swift */,
88238EA124E9DDB700F28079 /* LocalVideoView.swift */,
B935268F2B0E63C300421E6A /* NewCallViewController.swift */,
88D23D1823CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift */,
E1D827D42BD9B6E50022C1AF /* ReactionsBurstView.swift */,
E1D827D62BD9DA4D0022C1AF /* ReactionsSink.swift */,
766CE0D52A323DFE00AD609D /* RemoteVideoView.swift */,
342FFE7D271EF5B1000AC89F /* ReturnToCallViewController.swift */,
88D23D1823CEC0C700B0E74B /* SimulatorCallUIAdaptee.swift */,
);
path = UserInterface;
sourceTree = "<group>";
@ -11939,7 +11927,6 @@
501052672BDB22940097DDC5 /* PrivacyInfo.xcprivacy in Resources */,
45B74A802044AAB600CD42F8 /* pulse-quiet.aifc in Resources */,
45B74A822044AAB600CD42F8 /* pulse.aifc in Resources */,
886CB07C24E78F2200753909 /* Reflection.m4r in Resources */,
346EFC3C25FFDC6A00F493C7 /* restore-dark.json in Resources */,
346EFC3B25FFDC6A00F493C7 /* restore.json in Resources */,
34CF0788203E6B78005C4D61 /* ringback_tone_ansi.caf in Resources */,
@ -13123,7 +13110,6 @@
34995F1B2411838D00C70546 /* NewGroupMembersViewController.swift in Sources */,
346594802434D49F00E5C510 /* NewGroupState.swift in Sources */,
B9D65E532BAE1DA70067322A /* NicknameEditorViewController.swift in Sources */,
88D23D2323CEC0C700B0E74B /* NonCallKitCallUIAdaptee.swift in Sources */,
88D23D1223CEBFB200B0E74B /* NotificationActionHandler.swift in Sources */,
8806EF19248DBD7200E764C7 /* NotificationPermissionReminderMegaphone.swift in Sources */,
887B380D25F042BE00685845 /* NotificationSettingsContentViewController.swift in Sources */,
@ -13266,6 +13252,7 @@
880D90302481E617003D2B14 /* SignalApp.swift in Sources */,
8841584C252F9F1C0078903D /* SignalCall.swift in Sources */,
8822558D26B9D1D7001A33C4 /* SignalDotMePhoneNumberLink.swift in Sources */,
88D23D2323CEC0C700B0E74B /* SimulatorCallUIAdaptee.swift in Sources */,
88BE44A626153E7B00AE8E33 /* SoundAndNotificationsSettingsViewController.swift in Sources */,
F94D12FF28BD0DD900B2C478 /* SpeechManager.swift in Sources */,
34B3F87B1E8DF1700035BE1A /* SplashViewController.swift in Sources */,

View File

@ -16,9 +16,6 @@ protocol CallAudioServiceDelegate: AnyObject {
class CallAudioService: CallObserver {
private var vibrateTimer: Timer?
var handleRinging = false
weak var delegate: CallAudioServiceDelegate? {
willSet {
assert(newValue == nil || delegate == nil)
@ -28,13 +25,6 @@ class CallAudioService: CallObserver {
// Track whether the speaker should be enabled or not.
private(set) var isSpeakerEnabled = false
// MARK: Vibration config
private let vibrateRepeatDuration = 1.6
// Our ring buzz is a pair of vibrations.
// `pulseDuration` is the small pause between the two vibrations in the pair.
private let pulseDuration = 0.2
private var observers = [NSObjectProtocol]()
private var avAudioSession: AVAudioSession {
@ -278,8 +268,6 @@ class CallAudioService: CallObserver {
private func handleLocalRinging(call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("")
startRinging(call: call)
}
private func handleConnected(call: SignalCall) {
@ -358,11 +346,10 @@ class CallAudioService: CallObserver {
// MARK: Playing Sounds
var currentPlayer: AudioPlayer?
private var currentPlayer: AudioPlayer?
private func stopPlayingAnySounds() {
currentPlayer?.stop()
stopRinging()
}
private func prepareToPlay(sound: StandardSound) -> AudioPlayer? {
@ -386,63 +373,6 @@ class CallAudioService: CallObserver {
newPlayer.play()
}
// MARK: - Ringing
private var ringerSwitchObserver: CallRingerSwitchObserver?
func startRinging(call: SignalCall) {
guard handleRinging else {
Logger.debug("ignoring \(#function) since CallKit handles it's own ringing state")
return
}
// Only CallKit calls should be in the transitory ringing states
switch call.mode {
case .individual(let individualCall):
owsAssertDebug(individualCall.state == .localRinging_ReadyToAnswer)
case .groupThread:
break
}
vibrateTimer?.invalidate()
vibrateTimer = .scheduledTimer(withTimeInterval: vibrateRepeatDuration, repeats: true) { [weak self] _ in
self?.ringVibration()
}
guard let player = prepareToPlay(sound: .defaultiOSIncomingRingtone) else {
return owsFailDebug("Failed to prepare player for ringing")
}
// Start observing (observes on init)
ringerSwitchObserver = CallRingerSwitchObserver(callService: self, player: player, call: call)
}
func stopRinging() {
guard handleRinging else {
Logger.debug("ignoring \(#function) since CallKit handles it's own ringing state")
return
}
Logger.debug("")
// Stop vibrating
vibrateTimer?.invalidate()
vibrateTimer = nil
// Stops observing on deinit.
ringerSwitchObserver = nil
currentPlayer?.stop()
}
private func ringVibration() {
// Since a call notification is more urgent than a message notification, we
// vibrate twice, like a pulse, to differentiate from a normal notification vibration.
vibrate()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + pulseDuration) {
self.vibrate()
}
}
func vibrate() {
// TODO implement HapticAdapter for iPhone7 and up
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
@ -559,38 +489,3 @@ extension CallAudioService: CallServiceStateObserver {
newValue?.addObserverAndSyncState(observer: self)
}
}
private class CallRingerSwitchObserver: RingerSwitchObserver {
private let player: AudioPlayer
private let call: SignalCall
private weak var callService: CallAudioService?
init(callService: CallAudioService, player: AudioPlayer, call: SignalCall) {
self.callService = callService
self.player = player
self.call = call
// Immediately callback to maintain old behavior.
didToggleRingerSwitch(RingerSwitch.shared.addObserver(observer: self))
}
deinit {
RingerSwitch.shared.removeObserver(self)
}
func didToggleRingerSwitch(_ isSilenced: Bool) {
AssertIsOnMainThread()
// We must ensure the proper audio session before
// each time we play / pause, otherwise the category
// may have changed and no playback would occur.
callService?.ensureProperAudioSession(call: call)
if isSilenced {
player.pause()
} else {
player.play()
}
}
}

View File

@ -187,10 +187,6 @@ final class CallService: CallServiceStateObserver, CallServiceStateDelegate {
break
}
if let newValue {
self.audioService.handleRinging = callUIAdapter.adaptee(for: newValue).hasManualRinger
}
// To be safe, we reset the early ring on any call change so it's not left set from an unexpected state change.
earlyRingNextIncomingCall = false
}

View File

@ -33,10 +33,6 @@ public enum CallState: String {
case busyElsewhere // terminal
}
public enum CallAdapterType {
case `default`, nonCallKit
}
public enum CallDirection {
case outgoing, incoming
}
@ -87,8 +83,6 @@ public class IndividualCall: CustomDebugStringConvertible {
}
}
let callAdapterType: CallAdapterType
weak var remoteVideoTrack: RTCVideoTrack? {
didSet {
AssertIsOnMainThread()
@ -238,12 +232,11 @@ public class IndividualCall: CustomDebugStringConvertible {
// MARK: Initializers and Factory Methods
init(direction: CallDirection, state: CallState, thread: TSContactThread, sentAtTimestamp: UInt64, callAdapterType: CallAdapterType) {
init(direction: CallDirection, state: CallState, thread: TSContactThread, sentAtTimestamp: UInt64) {
self.direction = direction
self.state = state
self.thread = thread
self.sentAtTimestamp = sentAtTimestamp
self.callAdapterType = callAdapterType
}
deinit {

View File

@ -489,7 +489,6 @@ final class IndividualCallService: CallServiceStateObserver {
if !isOutgoing {
// If we are using the NSE, we need to kick off a ring ASAP in case this incoming call
// has resulted in the NSE waking up the main app.
owsAssertDebug(callUIAdapter.adaptee(for: call) === callUIAdapter.callKitAdaptee)
Logger.info("Performing early ring")
handleRinging(call: call, isAnticipatory: true)
} else {

View File

@ -313,8 +313,7 @@ class SignalCall: CallManagerCallReference {
direction: .outgoing,
state: .dialing,
thread: thread,
sentAtTimestamp: Date.ows_millisecondTimestamp(),
callAdapterType: .default
sentAtTimestamp: Date.ows_millisecondTimestamp()
)
}
@ -323,13 +322,11 @@ class SignalCall: CallManagerCallReference {
sentAtTimestamp: UInt64,
offerMediaType: TSRecentCallOfferType
) -> SignalCall {
let callAdapterType: CallAdapterType = .default
let individualCall = IndividualCall(
direction: .incoming,
state: .answering,
thread: thread,
sentAtTimestamp: sentAtTimestamp,
callAdapterType: callAdapterType
sentAtTimestamp: sentAtTimestamp
)
individualCall.offerMediaType = offerMediaType
return SignalCall(individualCall: individualCall)

View File

@ -22,9 +22,6 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
private let provider: CXProvider
private let audioActivity: AudioActivity
// CallKit handles incoming ringer stop/start for us. Yay!
let hasManualRinger = false
// Instantiating more than one CXProvider can cause us to miss call transactions, so
// we maintain the provider across Adaptees using a singleton pattern
static private let providerReadyFlag: ReadyFlag = ReadyFlag(name: "CallKitCXProviderReady")
@ -129,9 +126,6 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
AssertIsOnMainThread()
Logger.info("")
// make sure we don't terminate audio session during call
_ = self.audioSession.startAudioActivity(call.audioActivity)
// Add the new outgoing call to the app's list of calls.
// So we can find it in the provider delegate callbacks.
Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync {
@ -219,19 +213,11 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
completion(nil)
self.showCall(call)
self.callManager.addCall(call)
}
}
}
func answerCall(localId: UUID) {
AssertIsOnMainThread()
Logger.info("")
owsFailDebug("CallKit should answer calls via system call screen, not via notifications.")
}
func answerCall(_ call: SignalCall) {
AssertIsOnMainThread()
Logger.info("")
@ -265,12 +251,6 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
}
}
func localHangupCall(localId: UUID) {
AssertIsOnMainThread()
owsFailDebug("CallKit should decline calls via system call screen, not via notifications.")
}
func localHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
Logger.info("")

View File

@ -12,15 +12,13 @@ import UIKit
protocol CallUIAdaptee: AnyObject {
var notificationPresenterImpl: NotificationPresenterImpl { get }
var callService: CallService { get }
var hasManualRinger: Bool { get }
init(showNamesOnCallScreen: Bool, useSystemCallLog: Bool)
func startOutgoingCall(call: SignalCall)
func reportIncomingCall(_ call: SignalCall, completion: @escaping (Error?) -> Void)
func reportMissedCall(_ call: SignalCall, individualCall: IndividualCall)
func answerCall(localId: UUID)
func answerCall(_ call: SignalCall)
func recipientAcceptedCall(_ call: SignalCall)
func localHangupCall(localId: UUID)
func localHangupCall(_ call: SignalCall)
func remoteDidHangupCall(_ call: SignalCall)
func remoteBusy(_ call: SignalCall)
@ -30,65 +28,6 @@ protocol CallUIAdaptee: AnyObject {
func failCall(_ call: SignalCall, error: SignalCall.CallError)
func setIsMuted(call: SignalCall, isMuted: Bool)
func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool)
func startAndShowOutgoingCall(thread: TSContactThread, hasLocalVideo: Bool)
}
// Shared default implementations
extension CallUIAdaptee {
internal func showCall(_ call: SignalCall) {
AssertIsOnMainThread()
guard !call.hasTerminated else {
Logger.info("Not showing window for terminated call \(call)")
return
}
Logger.info("\(call)")
let callViewController: UIViewController & CallViewControllerWindowReference
switch call.mode {
case .individual(let individualCall):
callViewController = IndividualCallViewController(call: call, individualCall: individualCall)
case .groupThread(let groupThreadCall):
callViewController = GroupCallViewController(call: call, groupCall: groupThreadCall.ringRtcCall)
}
callViewController.modalTransitionStyle = .crossDissolve
WindowManager.shared.startCall(viewController: callViewController)
}
internal func reportMissedCall(_ call: SignalCall, individualCall: IndividualCall) {
AssertIsOnMainThread()
let sentAtTimestamp = Date(millisecondsSince1970: individualCall.sentAtTimestamp)
notificationPresenterImpl.presentMissedCall(
call,
caller: individualCall.remoteAddress,
sentAt: sentAtTimestamp
)
}
internal func startAndShowOutgoingCall(thread: TSContactThread, hasLocalVideo: Bool) {
AssertIsOnMainThread()
guard let (call, individualCall) = self.callService.buildOutgoingIndividualCallIfPossible(
thread: thread,
hasVideo: hasLocalVideo
) else {
// @integration This is not unexpected, it could happen if Bob tries
// to start an outgoing call at the same moment Alice has already
// sent him an Offer that is being processed.
Logger.info("found an existing call when trying to start outgoing call: \(thread.contactAddress)")
return
}
Logger.debug("")
startOutgoingCall(call: call)
individualCall.hasLocalVideo = hasLocalVideo
self.showCall(call)
}
}
/**
@ -99,42 +38,25 @@ public class CallUIAdapter: NSObject {
private var callService: CallService { AppEnvironment.shared.callService }
lazy var nonCallKitAdaptee = NonCallKitCallUIAdaptee()
lazy var callKitAdaptee: CallKitCallUIAdaptee? = { () -> CallKitCallUIAdaptee? in
if Platform.isSimulator {
// CallKit doesn't seem entirely supported in simulator.
// e.g. you can't receive calls in the call screen.
// So we use the non-CallKit call UI.
Logger.info("not using callkit adaptee for simulator.")
return nil
} else {
Logger.info("using callkit adaptee for iOS11+")
let (showNames, useSystemCallLog) = databaseStorage.read { tx in
return (
preferences.notificationPreviewType(tx: tx) != .noNameNoPreview,
preferences.isSystemCallLogEnabled(tx: tx)
)
}
return CallKitCallUIAdaptee(
showNamesOnCallScreen: showNames,
useSystemCallLog: useSystemCallLog
private lazy var adaptee: any CallUIAdaptee = { () -> any CallUIAdaptee in
let callUIAdapteeType: CallUIAdaptee.Type
#if targetEnvironment(simulator)
callUIAdapteeType = SimulatorCallUIAdaptee.self
#else
callUIAdapteeType = CallKitCallUIAdaptee.self
#endif
let (showNames, useSystemCallLog) = databaseStorage.read { tx in
return (
preferences.notificationPreviewType(tx: tx) != .noNameNoPreview,
preferences.isSystemCallLogEnabled(tx: tx)
)
}
return callUIAdapteeType.init(
showNamesOnCallScreen: showNames,
useSystemCallLog: useSystemCallLog
)
}()
var defaultAdaptee: CallUIAdaptee { callKitAdaptee ?? nonCallKitAdaptee }
func adaptee(for call: SignalCall) -> CallUIAdaptee {
switch call.mode {
case .individual(let individualCall) where individualCall.callAdapterType == .nonCallKit:
return nonCallKitAdaptee
case .individual, .groupThread:
return defaultAdaptee
}
}
public override init() {
AssertIsOnMainThread()
@ -156,24 +78,11 @@ public class CallUIAdapter: NSObject {
// make sure we don't terminate audio session during call
_ = audioSession.startAudioActivity(call.audioActivity)
adaptee(for: call).reportIncomingCall(call) { error in
adaptee.reportIncomingCall(call) { error in
AssertIsOnMainThread()
guard var error = error else {
switch call.mode {
case .individual:
// Individual calls ring on their state transitions, but group calls ring immediately.
break
case .groupThread:
// Wait to start ringing until all observers have recognized this as the current call.
DispatchQueue.main.async {
guard call === self.callService.callServiceState.currentCall else {
// Assume that the call failed before we got a chance to start ringing.
return
}
self.callService.audioService.startRinging(call: call)
}
}
self.showCall(call)
return
}
@ -205,118 +114,125 @@ public class CallUIAdapter: NSObject {
internal func reportMissedCall(_ call: SignalCall, individualCall: IndividualCall) {
AssertIsOnMainThread()
adaptee(for: call).reportMissedCall(call, individualCall: individualCall)
let sentAtTimestamp = Date(millisecondsSince1970: individualCall.sentAtTimestamp)
notificationPresenterImpl.presentMissedCall(
call,
caller: individualCall.remoteAddress,
sentAt: sentAtTimestamp
)
}
internal func startOutgoingCall(call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).startOutgoingCall(call: call)
}
// make sure we don't terminate audio session during call
_ = audioSession.startAudioActivity(call.audioActivity)
public func answerCall(localId: UUID) {
AssertIsOnMainThread()
guard let call = self.callService.callServiceState.currentCall else {
owsFailDebug("No current call.")
return
}
guard call.localId == localId else {
owsFailDebug("localId does not match current call")
return
}
adaptee(for: call).answerCall(localId: localId)
adaptee.startOutgoingCall(call: call)
}
internal func answerCall(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).answerCall(call)
adaptee.answerCall(call)
}
public func startAndShowOutgoingCall(thread: TSContactThread, hasLocalVideo: Bool) {
AssertIsOnMainThread()
defaultAdaptee.startAndShowOutgoingCall(thread: thread, hasLocalVideo: hasLocalVideo)
guard let (call, individualCall) = self.callService.buildOutgoingIndividualCallIfPossible(
thread: thread,
hasVideo: hasLocalVideo
) else {
// @integration This is not unexpected, it could happen if Bob tries
// to start an outgoing call at the same moment Alice has already
// sent him an Offer that is being processed.
Logger.info("found an existing call when trying to start outgoing call: \(thread.contactAddress)")
return
}
Logger.debug("")
startOutgoingCall(call: call)
individualCall.hasLocalVideo = hasLocalVideo
self.showCall(call)
}
internal func recipientAcceptedCall(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).recipientAcceptedCall(call)
adaptee.recipientAcceptedCall(call)
}
internal func remoteDidHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).remoteDidHangupCall(call)
adaptee.remoteDidHangupCall(call)
}
internal func remoteBusy(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).remoteBusy(call)
adaptee.remoteBusy(call)
}
internal func didAnswerElsewhere(call: SignalCall) {
adaptee(for: call).didAnswerElsewhere(call: call)
adaptee.didAnswerElsewhere(call: call)
}
internal func didDeclineElsewhere(call: SignalCall) {
adaptee(for: call).didDeclineElsewhere(call: call)
adaptee.didDeclineElsewhere(call: call)
}
internal func wasBusyElsewhere(call: SignalCall) {
adaptee(for: call).wasBusyElsewhere(call: call)
}
internal func localHangupCall(localId: UUID) {
AssertIsOnMainThread()
guard let call = self.callService.callServiceState.currentCall else {
owsFailDebug("No current call.")
return
}
guard call.localId == localId else {
owsFailDebug("localId does not match current call")
return
}
adaptee(for: call).localHangupCall(localId: localId)
adaptee.wasBusyElsewhere(call: call)
}
internal func localHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).localHangupCall(call)
adaptee.localHangupCall(call)
}
internal func failCall(_ call: SignalCall, error: SignalCall.CallError) {
AssertIsOnMainThread()
adaptee(for: call).failCall(call, error: error)
adaptee.failCall(call, error: error)
}
private func showCall(_ call: SignalCall) {
AssertIsOnMainThread()
adaptee(for: call).showCall(call)
guard !call.hasTerminated else {
Logger.info("Not showing window for terminated call \(call)")
return
}
Logger.info("\(call)")
let callViewController: UIViewController & CallViewControllerWindowReference
switch call.mode {
case .individual(let individualCall):
callViewController = IndividualCallViewController(call: call, individualCall: individualCall)
case .groupThread(let groupThreadCall):
callViewController = GroupCallViewController(call: call, groupCall: groupThreadCall.ringRtcCall)
}
callViewController.modalTransitionStyle = .crossDissolve
WindowManager.shared.startCall(viewController: callViewController)
}
internal func setIsMuted(call: SignalCall, isMuted: Bool) {
AssertIsOnMainThread()
// With CallKit, muting is handled by a CXAction, so it must go through the adaptee
adaptee(for: call).setIsMuted(call: call, isMuted: isMuted)
adaptee.setIsMuted(call: call, isMuted: isMuted)
}
internal func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) {
AssertIsOnMainThread()
adaptee(for: call).setHasLocalVideo(call: call, hasLocalVideo: hasLocalVideo)
adaptee.setHasLocalVideo(call: call, hasLocalVideo: hasLocalVideo)
}
internal func setCameraSource(call: SignalCall, isUsingFrontCamera: Bool) {

View File

@ -1,239 +0,0 @@
//
// Copyright 2016 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import SignalServiceKit
/**
* Manage call related UI in a pre-CallKit world.
*/
class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee {
var callService: CallService { AppEnvironment.shared.callService }
// Starting/Stopping incoming call ringing is our apps responsibility for the non CallKit interface.
let hasManualRinger = true
override init() {
AssertIsOnMainThread()
super.init()
}
// MARK:
func startOutgoingCall(call: SignalCall) {
AssertIsOnMainThread()
// make sure we don't terminate audio session during call
let success = self.audioSession.startAudioActivity(call.audioActivity)
assert(success)
switch call.mode {
case .individual:
self.callService.individualCallService.handleOutgoingCall(call)
case .groupThread:
switch call.groupCallRingState {
case .shouldRing where call.ringRestrictions.isEmpty, .ringing:
// Let CallService call recipientAcceptedCall when someone joins.
break
case .ringingEnded:
owsFailDebug("ringing ended while we were starting the call")
fallthrough
case .doNotRing, .shouldRing:
// Immediately consider ourselves connected.
recipientAcceptedCall(call)
case .incomingRing, .incomingRingCancelled:
owsFailDebug("should not happen for an outgoing call")
// Recover by considering ourselves connected
recipientAcceptedCall(call)
}
}
}
func reportIncomingCall(_ call: SignalCall, completion: @escaping (Error?) -> Void) {
AssertIsOnMainThread()
Logger.debug("")
self.showCall(call)
startNotifiyingForIncomingCall(call)
completion(nil)
}
private var incomingCallNotificationTimer: Timer?
private func startNotifiyingForIncomingCall(_ call: SignalCall) {
// Pull this out up front. Group calls don't necessarily keep the information around.
guard let caller = call.caller else {
return
}
incomingCallNotificationTimer?.invalidate()
// present lock screen notification if we're in the background.
// we re-present the notifiation every 3 seconds to make sure
// the user sees that their phone is ringing
incomingCallNotificationTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
let shouldContinue = { () -> Bool in
guard self.callService.callServiceState.currentCall === call else {
return false
}
switch call.mode {
case .individual(let individualCall):
return individualCall.state == .localRinging_ReadyToAnswer
case .groupThread(let groupThreadCall):
return groupThreadCall.ringRtcCall.localDeviceState.joinState == .notJoined
}
}()
guard shouldContinue else {
self.incomingCallNotificationTimer?.invalidate()
self.incomingCallNotificationTimer = nil
return
}
if UIApplication.shared.applicationState == .active {
Logger.debug("skipping notification since app is already active.")
} else {
self.notificationPresenterImpl.presentIncomingCall(call, caller: caller)
}
}
}
func answerCall(localId: UUID) {
AssertIsOnMainThread()
guard let call = self.callService.callServiceState.currentCall else {
owsFailDebug("No current call.")
return
}
guard call.localId == localId else {
owsFailDebug("localId does not match current call")
return
}
self.answerCall(call)
}
func answerCall(_ call: SignalCall) {
AssertIsOnMainThread()
guard call.localId == self.callService.callServiceState.currentCall?.localId else {
owsFailDebug("localId does not match current call")
return
}
switch call.mode {
case .individual:
self.callService.individualCallService.handleAcceptCall(call)
case .groupThread(let groupThreadCall):
// Explicitly unmute to request permissions.
self.callService.updateIsLocalAudioMuted(isLocalAudioMuted: false)
self.callService.joinGroupCallIfNecessary(call, groupCall: groupThreadCall.ringRtcCall)
}
// Enable audio for locally accepted calls after the session is configured.
self.audioSession.isRTCAudioEnabled = true
}
func recipientAcceptedCall(_ call: SignalCall) {
AssertIsOnMainThread()
// Enable audio for remotely accepted calls after the session is configured.
self.audioSession.isRTCAudioEnabled = true
}
func localHangupCall(localId: UUID) {
AssertIsOnMainThread()
guard let call = self.callService.callServiceState.currentCall else {
owsFailDebug("No current call.")
return
}
guard call.localId == localId else {
owsFailDebug("localId does not match current call")
return
}
self.localHangupCall(call)
}
func localHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
// If both parties hang up at the same moment,
// call might already be nil.
guard self.callService.callServiceState.currentCall == nil || call.localId == self.callService.callServiceState.currentCall?.localId else {
owsFailDebug("localId does not match current call")
return
}
callService.handleLocalHangupCall(call)
}
internal func remoteDidHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
internal func remoteBusy(_ call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
internal func didAnswerElsewhere(call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
internal func didDeclineElsewhere(call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
internal func wasBusyElsewhere(call: SignalCall) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
internal func failCall(_ call: SignalCall, error: SignalCall.CallError) {
AssertIsOnMainThread()
Logger.debug("is no-op")
}
func setIsMuted(call: SignalCall, isMuted: Bool) {
AssertIsOnMainThread()
guard call.localId == self.callService.callServiceState.currentCall?.localId else {
owsFailDebug("localId does not match current call")
return
}
self.callService.updateIsLocalAudioMuted(isLocalAudioMuted: isMuted)
}
func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) {
AssertIsOnMainThread()
guard call.localId == self.callService.callServiceState.currentCall?.localId else {
owsFailDebug("localId does not match current call")
return
}
self.callService.updateIsLocalVideoMuted(isLocalVideoMuted: !hasLocalVideo)
}
}

View File

@ -0,0 +1,115 @@
//
// Copyright 2016 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import SignalServiceKit
#if targetEnvironment(simulator)
class SimulatorCallUIAdaptee: NSObject, CallUIAdaptee {
var callService: CallService { AppEnvironment.shared.callService }
required init(showNamesOnCallScreen: Bool, useSystemCallLog: Bool) {
}
// MARK:
func startOutgoingCall(call: SignalCall) {
AssertIsOnMainThread()
switch call.mode {
case .individual:
self.callService.individualCallService.handleOutgoingCall(call)
case .groupThread:
switch call.groupCallRingState {
case .shouldRing where call.ringRestrictions.isEmpty, .ringing:
// Let CallService call recipientAcceptedCall when someone joins.
break
case .ringingEnded:
owsFailDebug("ringing ended while we were starting the call")
fallthrough
case .doNotRing, .shouldRing:
// Immediately consider ourselves connected.
recipientAcceptedCall(call)
case .incomingRing, .incomingRingCancelled:
owsFailDebug("should not happen for an outgoing call")
// Recover by considering ourselves connected
recipientAcceptedCall(call)
}
}
}
func reportIncomingCall(_ call: SignalCall, completion: @escaping (Error?) -> Void) {
AssertIsOnMainThread()
completion(nil)
}
func answerCall(_ call: SignalCall) {
AssertIsOnMainThread()
guard call.localId == self.callService.callServiceState.currentCall?.localId else {
owsFailDebug("localId does not match current call")
return
}
switch call.mode {
case .individual:
self.callService.individualCallService.handleAcceptCall(call)
case .groupThread(let groupThreadCall):
// Explicitly unmute to request permissions.
self.callService.updateIsLocalAudioMuted(isLocalAudioMuted: false)
self.callService.joinGroupCallIfNecessary(call, groupCall: groupThreadCall.ringRtcCall)
}
// Enable audio for locally accepted calls after the session is configured.
self.audioSession.isRTCAudioEnabled = true
}
func recipientAcceptedCall(_ call: SignalCall) {
AssertIsOnMainThread()
// Enable audio for remotely accepted calls after the session is configured.
self.audioSession.isRTCAudioEnabled = true
}
func localHangupCall(_ call: SignalCall) {
AssertIsOnMainThread()
// If both parties hang up at the same moment, call might already be nil.
owsAssert(self.callService.callServiceState.currentCall == nil || call.localId == self.callService.callServiceState.currentCall?.localId)
callService.handleLocalHangupCall(call)
}
func remoteDidHangupCall(_ call: SignalCall) {
}
func remoteBusy(_ call: SignalCall) {
}
func didAnswerElsewhere(call: SignalCall) {
}
func didDeclineElsewhere(call: SignalCall) {
}
func wasBusyElsewhere(call: SignalCall) {
}
func failCall(_ call: SignalCall, error: SignalCall.CallError) {
}
func setIsMuted(call: SignalCall, isMuted: Bool) {
AssertIsOnMainThread()
owsAssert(call.localId == self.callService.callServiceState.currentCall?.localId)
self.callService.updateIsLocalAudioMuted(isLocalAudioMuted: isMuted)
}
func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) {
AssertIsOnMainThread()
owsAssert(call.localId == self.callService.callServiceState.currentCall?.localId)
self.callService.updateIsLocalVideoMuted(isLocalVideoMuted: !hasLocalVideo)
}
}
#endif

View File

@ -53,12 +53,8 @@ public class NotificationActionHandler: Dependencies {
}
switch action {
case .answerCall:
return try answerCall(userInfo: userInfo)
case .callBack:
return try callBack(userInfo: userInfo)
case .declineCall:
return try declineCall(userInfo: userInfo)
case .markAsRead:
return try markAsRead(userInfo: userInfo)
case .reply:
@ -87,19 +83,6 @@ public class NotificationActionHandler: Dependencies {
// MARK: -
private class func answerCall(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {
guard let localCallIdString = userInfo[AppNotificationUserInfoKey.localCallId] as? String else {
throw OWSAssertionError("localCallIdString was unexpectedly nil")
}
guard let localCallId = UUID(uuidString: localCallIdString) else {
throw OWSAssertionError("unable to build localCallId. localCallIdString: \(localCallIdString)")
}
callService.callUIAdapter.answerCall(localId: localCallId)
return Promise.value(())
}
private class func callBack(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {
let aciString = userInfo[AppNotificationUserInfoKey.callBackAciString] as? String
let phoneNumber = userInfo[AppNotificationUserInfoKey.callBackPhoneNumber] as? String
@ -113,19 +96,6 @@ public class NotificationActionHandler: Dependencies {
return Promise.value(())
}
private class func declineCall(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {
guard let localCallIdString = userInfo[AppNotificationUserInfoKey.localCallId] as? String else {
throw OWSAssertionError("localCallIdString was unexpectedly nil")
}
guard let localCallId = UUID(uuidString: localCallIdString) else {
throw OWSAssertionError("unable to build localCallId. localCallIdString: \(localCallIdString)")
}
callService.callUIAdapter.localHangupCall(localId: localCallId)
return Promise.value(())
}
private class func markAsRead(userInfo: [AnyHashable: Any]) throws -> Promise<Void> {
return firstly {
self.notificationMessage(forUserInfo: userInfo)

View File

@ -25,9 +25,6 @@ class DebugUINotifications: DebugUIPage, Dependencies {
OWSTableItem(title: "All Notifications in Sequence") { [weak self] in
self?.notifyForEverythingInSequence(contactThread: contactThread)
},
OWSTableItem(title: "Incoming Call") { [weak self] in
self?.notifyForIncomingCall(thread: contactThread)
},
OWSTableItem(title: "Call Rejected: New Safety Number") { [weak self] in
self?.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread)
},
@ -88,9 +85,7 @@ class DebugUINotifications: DebugUIPage, Dependencies {
func notifyForEverythingInSequence(contactThread: TSContactThread) -> Guarantee<Void> {
let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
return self.notifyForIncomingCall(thread: contactThread).then {
self.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread)
}.then {
return self.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread).then {
self.notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: contactThread)
}.then {
self.notifyForIncomingMessage(thread: contactThread)
@ -99,13 +94,6 @@ class DebugUINotifications: DebugUIPage, Dependencies {
}
}
@discardableResult
func notifyForIncomingCall(thread: TSContactThread) -> Guarantee<Void> {
return delayedNotificationDispatchWithFakeCall(thread: thread) { call in
self.notificationPresenterImpl.presentIncomingCall(call, caller: thread.contactAddress)
}
}
@discardableResult
func notifyForMissedCallBecauseOfNewIdentity(thread: TSContactThread) -> Guarantee<Void> {
return delayedNotificationDispatchWithFakeCall(thread: thread) { call in

View File

@ -187,9 +187,6 @@
/* Title for the view of all your signal connections */
"ALL_SIGNAL_CONNECTIONS_TITLE" = "All Connections";
/* notification action */
"ANSWER_CALL_BUTTON_TITLE" = "Answer";
/* notification body */
"APN_Message" = "You may have new messages";
@ -682,9 +679,6 @@
/* Label for button that lets users call a contact again. */
"CALL_AGAIN_BUTTON_TITLE" = "Call Again";
/* notification body */
"CALL_AUDIO_INCOMING_NOTIFICATION_BODY" = "📞 Incoming voice call…";
/* notification body for a missed call in the last 24 hours. Embeds {{time}}, e.g. '3:30 PM'. */
"CALL_AUDIO_MISSED_24_HOURS_NOTIFICATION_BODY_FORMAT" = "📞 Missed voice call at %@";
@ -712,12 +706,6 @@
/* label for button shown when an incoming call rings */
"CALL_CONTROLS_INCOMING_DECLINE" = "decline";
/* Body for the repeating notification shown while an incoming group call is ringing, if the user has chosen not to include contact names in notifications */
"CALL_GROUP_INCOMING_NOTIFICATION_BODY_ANONYMOUS" = "📹 Incoming group call…";
/* Body for the repeating notification shown while an incoming group call is ringing. Embeds {{caller name}} */
"CALL_GROUP_INCOMING_NOTIFICATION_BODY_FORMAT" = "📹 %@ is ringing the group…";
/* notification body */
"CALL_MISSED_BECAUSE_OF_IDENTITY_CHANGE_NOTIFICATION_BODY" = "☎️ Missed call because the caller's safety number changed.";
@ -742,9 +730,6 @@
/* Title for alert offering to call a user. */
"CALL_USER_ALERT_TITLE" = "Call?";
/* notification body */
"CALL_VIDEO_INCOMING_NOTIFICATION_BODY" = "📹 Incoming video call…";
/* notification body for a missed call in the last 24 hours. Embeds {{time}}, e.g. '3:30 PM'. */
"CALL_VIDEO_MISSED_24_HOURS_NOTIFICATION_BODY_FORMAT" = "📹 Missed video call at %@";
@ -5839,9 +5824,6 @@
/* Error message when sending a verification code via voice call failed, but resending via sms might succeed. */
"REGISTRATION_VOICE_CODE_FAILED_TRY_SMS_ERROR" = "We couldn't send you a verification code via voice call. Try receiving your code via sms instead.";
/* notification action */
"REJECT_CALL_BUTTON_TITLE" = "Reject";
/* No comment provided by engineer. */
"RELAY_REGISTERED_ERROR_RECOVERY" = "The phone number you are trying to register has already been registered on another server, please unregister from there and try again.";

View File

@ -86,9 +86,6 @@ public enum StandardSound: UInt {
case synth = 12
case signalClassic = 13
// Ringtone Sounds
case reflection = 14
// Calls
case callConnecting = 15
case callOutboundRinging = 16
@ -107,8 +104,6 @@ public enum StandardSound: UInt {
// Audio Playback
case beginNextTrack = 24
case endLastTrack = 25
public static let defaultiOSIncomingRingtone: StandardSound = .reflection
}
public extension StandardSound {
@ -135,9 +130,6 @@ public extension StandardSound {
case .synth: return "Synth"
case .signalClassic: return "Signal Classic"
// Ringtone Sounds
case .reflection: return "Opening"
// Calls
case .callConnecting: return "Call Connecting"
case .callOutboundRinging: return "Call Outboung Ringing"
@ -198,9 +190,6 @@ public extension StandardSound {
case .signalClassic:
return quiet ? "classic-quiet.aifc" : "classic.aifc"
// Ringtone Sounds
case .reflection: return "Reflection.m4r"
// Calls
case .callConnecting: return "ringback_tone_ansi.caf"
case .callOutboundRinging: return "ringback_tone_ansi.caf"

View File

@ -26,7 +26,6 @@ public enum AppNotificationCategory: CaseIterable {
case incomingReactionWithActions_CanReply
case incomingReactionWithActions_CannotReply
case infoOrErrorMessage
case incomingCall
case missedCallWithActions
case missedCallWithoutActions
case missedCallFromNoLongerVerifiedIdentity
@ -39,9 +38,7 @@ public enum AppNotificationCategory: CaseIterable {
}
public enum AppNotificationAction: String, CaseIterable {
case answerCall
case callBack
case declineCall
case markAsRead
case reply
case showThread
@ -61,7 +58,6 @@ public struct AppNotificationUserInfoKey {
public static let storyTimestamp = "Signal.AppNotificationsUserInfoKey.storyTimestamp"
public static let callBackAciString = "Signal.AppNotificationsUserInfoKey.callBackUuid"
public static let callBackPhoneNumber = "Signal.AppNotificationsUserInfoKey.callBackPhoneNumber"
public static let localCallId = "Signal.AppNotificationsUserInfoKey.localCallId"
public static let isMissedCall = "Signal.AppNotificationsUserInfoKey.isMissedCall"
public static let defaultAction = "Signal.AppNotificationsUserInfoKey.defaultAction"
}
@ -83,8 +79,6 @@ extension AppNotificationCategory {
return "Signal.AppNotificationCategory.incomingReactionWithActionsNoReply"
case .infoOrErrorMessage:
return "Signal.AppNotificationCategory.infoOrErrorMessage"
case .incomingCall:
return "Signal.AppNotificationCategory.incomingCall"
case .missedCallWithActions:
return "Signal.AppNotificationCategory.missedCallWithActions"
case .missedCallWithoutActions:
@ -121,8 +115,6 @@ extension AppNotificationCategory {
return []
case .infoOrErrorMessage:
return []
case .incomingCall:
return [.answerCall, .declineCall]
case .missedCallWithActions:
return [.callBack, .showThread]
case .missedCallWithoutActions:
@ -148,12 +140,8 @@ extension AppNotificationCategory {
extension AppNotificationAction {
var identifier: String {
switch self {
case .answerCall:
return "Signal.AppNotifications.Action.answerCall"
case .callBack:
return "Signal.AppNotifications.Action.callBack"
case .declineCall:
return "Signal.AppNotifications.Action.declineCall"
case .markAsRead:
return "Signal.AppNotifications.Action.markAsRead"
case .reply:
@ -230,60 +218,6 @@ public class NotificationPresenterImpl: NotificationPresenter {
}
}
public func presentIncomingCall(_ call: CallNotificationInfo, caller: SignalServiceAddress) {
let thread = call.thread
let callPreview: CallPreview?
let callerNameForGroupCall: String?
(callPreview, callerNameForGroupCall) = databaseStorage.read { tx in
guard let callPreview = self.fetchCallPreview(thread: thread, tx: tx) else {
return (nil, nil)
}
return (
callPreview,
thread.isGroupThread ? contactManager.displayName(for: caller, tx: tx).resolvedValue() : nil
)
}
let notificationBody: String
if let callerNameForGroupCall = callerNameForGroupCall {
notificationBody = String(format: NotificationStrings.incomingGroupCallBodyFormat, callerNameForGroupCall)
} else if thread.isGroupThread {
notificationBody = NotificationStrings.incomingGroupCallBodyAnonymous
} else {
switch call.offerMediaType {
case .audio: notificationBody = NotificationStrings.incomingAudioCallBody
case .video: notificationBody = NotificationStrings.incomingVideoCallBody
}
}
let userInfo = [
AppNotificationUserInfoKey.threadId: thread.uniqueId,
AppNotificationUserInfoKey.localCallId: call.localId.uuidString
]
var interaction: INInteraction?
if callPreview != nil, let intent = thread.generateIncomingCallIntent(callerAddress: caller) {
let wrapper = INInteraction(intent: intent, response: nil)
wrapper.direction = .incoming
interaction = wrapper
}
performNotificationActionAsync { completion in
self.presenter.notify(
category: .incomingCall,
title: callPreview?.notificationTitle,
body: notificationBody,
threadIdentifier: callPreview?.threadIdentifier,
userInfo: userInfo,
interaction: interaction,
sound: nil,
replacingIdentifier: call.localId.uuidString,
completion: completion
)
}
}
/// Classifies a timestamp based on how it should be included in a notification.
///
/// In particular, a notification already comes with its own timestamp, so any information we put in has to be

View File

@ -30,13 +30,6 @@ public class UserNotificationConfig {
class func notificationAction(_ action: AppNotificationAction) -> UNNotificationAction? {
switch action {
case .answerCall:
return notificationActionWithIdentifier(
action.identifier,
title: CallStrings.answerCallButtonTitle,
options: [.foreground],
systemImage: "phone"
)
case .callBack:
return notificationActionWithIdentifier(
action.identifier,
@ -44,13 +37,6 @@ public class UserNotificationConfig {
options: [.foreground],
systemImage: "phone"
)
case .declineCall:
return notificationActionWithIdentifier(
action.identifier,
title: CallStrings.declineCallButtonTitle,
options: [],
systemImage: "phone.down"
)
case .markAsRead:
return notificationActionWithIdentifier(
action.identifier,
@ -312,7 +298,6 @@ class UserNotificationPresenter: Dependencies {
private func shouldPresentNotification(category: AppNotificationCategory, userInfo: [AnyHashable: Any]) -> Bool {
switch category {
case .incomingMessageFromNoLongerVerifiedIdentity,
.incomingCall,
.missedCallWithActions,
.missedCallWithoutActions,
.missedCallFromNoLongerVerifiedIdentity,

View File

@ -339,22 +339,6 @@ public class MessageStrings: NSObject {
public class NotificationStrings: NSObject {
static public var incomingAudioCallBody: String {
OWSLocalizedString("CALL_AUDIO_INCOMING_NOTIFICATION_BODY", comment: "notification body")
}
static public var incomingVideoCallBody: String {
OWSLocalizedString("CALL_VIDEO_INCOMING_NOTIFICATION_BODY", comment: "notification body")
}
static public var incomingGroupCallBodyFormat: String {
OWSLocalizedString("CALL_GROUP_INCOMING_NOTIFICATION_BODY_FORMAT", comment: "Body for the repeating notification shown while an incoming group call is ringing. Embeds {{caller name}}")
}
static public var incomingGroupCallBodyAnonymous: String {
OWSLocalizedString("CALL_GROUP_INCOMING_NOTIFICATION_BODY_ANONYMOUS", comment: "Body for the repeating notification shown while an incoming group call is ringing, if the user has chosen not to include contact names in notifications")
}
static public var missedCallBecauseOfIdentityChangeBody: String {
OWSLocalizedString("CALL_MISSED_BECAUSE_OF_IDENTITY_CHANGE_NOTIFICATION_BODY",
comment: "notification body")
@ -503,14 +487,6 @@ public class CallStrings: NSObject {
static public var showThreadButtonTitle: String {
OWSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action")
}
static public var answerCallButtonTitle: String {
OWSLocalizedString("ANSWER_CALL_BUTTON_TITLE", comment: "notification action")
}
static public var declineCallButtonTitle: String {
OWSLocalizedString("REJECT_CALL_BUTTON_TITLE", comment: "notification action")
}
}
// MARK: -

View File

@ -10,7 +10,7 @@ extension Sounds {
private static func shouldAudioPlayerLoop(forSound sound: Sound) -> Bool {
guard case .standard(let standardSound) = sound else { return false }
switch standardSound {
case .callConnecting, .callOutboundRinging, .defaultiOSIncomingRingtone:
case .callConnecting, .callOutboundRinging:
return true
default:
return false