From f0ccdd978741356f859b1c6fefaeaeef23313c19 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 25 Aug 2022 18:03:43 -0700 Subject: [PATCH] Move localId up from IndividualCall to SignalCall Group calls don't normally have stable IDs, but we need an opaque ID to represent a particular ring for CallKit or notifications. The next commit will drop the localId on IndividualCall, but right now it's still needed for presenting notifications. --- Signal/src/Calls/CallService.swift | 3 +- .../src/Calls/Individual/IndividualCall.swift | 8 ++---- .../Individual/IndividualCallService.swift | 8 +++--- Signal/src/Calls/SignalCall.swift | 10 ++++--- .../CallKit/CallKitCallManager.swift | 16 +++++------ .../CallKit/CallKitCallUIAdaptee.swift | 28 +++++++++---------- .../Individual/CallUIAdapter.swift | 4 +-- .../Individual/NonCallKitCallUIAdaptee.swift | 12 ++++---- .../DebugUI/DebugUINotifications.swift | 1 - 9 files changed, 44 insertions(+), 46 deletions(-) diff --git a/Signal/src/Calls/CallService.swift b/Signal/src/Calls/CallService.swift index f9b7035101..25064eaee1 100644 --- a/Signal/src/Calls/CallService.swift +++ b/Signal/src/Calls/CallService.swift @@ -570,7 +570,7 @@ public final class CallService: LightweightCallManager { AssertIsOnMainThread() guard !hasCallInProgress else { return nil } - let call = SignalCall.outgoingIndividualCall(localId: UUID(), thread: thread) + let call = SignalCall.outgoingIndividualCall(thread: thread) call.individualCall.offerMediaType = hasVideo ? .video : .audio addCall(call) @@ -594,7 +594,6 @@ public final class CallService: LightweightCallManager { } let newCall = SignalCall.incomingIndividualCall( - localId: UUID(), thread: thread, sentAtTimestamp: sentAtTimestamp, offerMediaType: offerMediaType diff --git a/Signal/src/Calls/Individual/IndividualCall.swift b/Signal/src/Calls/Individual/IndividualCall.swift index bc7707db64..0707d2e566 100644 --- a/Signal/src/Calls/Individual/IndividualCall.swift +++ b/Signal/src/Calls/Individual/IndividualCall.swift @@ -113,7 +113,7 @@ public class IndividualCall: NSObject, IndividualCallNotificationInfo { var wasRemovedFromSystem = false @objc - public let remoteAddress: SignalServiceAddress + public var remoteAddress: SignalServiceAddress { thread.contactAddress } public var isEnded: Bool { switch state { @@ -128,7 +128,7 @@ public class IndividualCall: NSObject, IndividualCallNotificationInfo { // Distinguishes between calls locally, e.g. in CallKit @objc - public let localId: UUID + public let localId: UUID = UUID() public let thread: TSContactThread @@ -208,11 +208,9 @@ public class IndividualCall: NSObject, IndividualCallNotificationInfo { // MARK: Initializers and Factory Methods - init(direction: CallDirection, localId: UUID, state: CallState, thread: TSContactThread, sentAtTimestamp: UInt64, callAdapterType: CallAdapterType) { + init(direction: CallDirection, state: CallState, thread: TSContactThread, sentAtTimestamp: UInt64, callAdapterType: CallAdapterType) { self.direction = direction - self.localId = localId self.state = state - self.remoteAddress = thread.contactAddress self.thread = thread self.sentAtTimestamp = sentAtTimestamp self.callAdapterType = callAdapterType diff --git a/Signal/src/Calls/Individual/IndividualCallService.swift b/Signal/src/Calls/Individual/IndividualCallService.swift index bcae3608de..906575fe56 100644 --- a/Signal/src/Calls/Individual/IndividualCallService.swift +++ b/Signal/src/Calls/Individual/IndividualCallService.swift @@ -61,7 +61,7 @@ final public class IndividualCallService: NSObject { AssertIsOnMainThread() Logger.info("call: \(call)") - BenchEventStart(title: "Outgoing Call Connection", eventId: "call-\(call.individualCall.localId)") + BenchEventStart(title: "Outgoing Call Connection", eventId: "call-\(call.localId)") guard callService.currentCall == nil else { owsFailDebug("call already exists: \(String(describing: callService.currentCall))") @@ -264,7 +264,7 @@ final public class IndividualCallService: NSObject { callType: callType ) - BenchEventStart(title: "Incoming Call Connection", eventId: "call-\(newCall.individualCall.localId)") + BenchEventStart(title: "Incoming Call Connection", eventId: "call-\(newCall.localId)") guard tsAccountManager.isOnboarded(with: transaction) else { Logger.warn("user is not onboarded, skipping call.") @@ -1222,10 +1222,10 @@ final public class IndividualCallService: NSObject { switch call.individualCall.state { case .dialing: - BenchEventComplete(eventId: "call-\(call.individualCall.localId)") + BenchEventComplete(eventId: "call-\(call.localId)") call.individualCall.state = .remoteRinging case .answering: - BenchEventComplete(eventId: "call-\(call.individualCall.localId)") + BenchEventComplete(eventId: "call-\(call.localId)") call.individualCall.state = isAnticipatory ? .localRinging_Anticipatory : .localRinging_ReadyToAnswer self.callUIAdapter.reportIncomingCall(call, thread: call.individualCall.thread) case .localRinging_Anticipatory: diff --git a/Signal/src/Calls/SignalCall.swift b/Signal/src/Calls/SignalCall.swift index 66796e00f2..7cd6678972 100644 --- a/Signal/src/Calls/SignalCall.swift +++ b/Signal/src/Calls/SignalCall.swift @@ -106,6 +106,9 @@ public class SignalCall: NSObject, CallManagerCallReference { didSet { AssertIsOnMainThread() } } + // Distinguishes between calls locally, e.g. in CallKit + public let localId: UUID + @objc public let thread: TSThread @@ -174,6 +177,7 @@ public class SignalCall: NSObject, CallManagerCallReference { audioDescription: "[SignalCall] with group \(groupThread.groupModel.groupId)", behavior: .call ) + localId = UUID() thread = groupThread if !RemoteConfig.groupRings { ringRestrictions = .notApplicable @@ -213,6 +217,7 @@ public class SignalCall: NSObject, CallManagerCallReference { behavior: .call ) thread = individualCall.thread + localId = individualCall.localId ringRestrictions = .notApplicable super.init() individualCall.delegate = self @@ -240,10 +245,9 @@ public class SignalCall: NSObject, CallManagerCallReference { return call } - public class func outgoingIndividualCall(localId: UUID, thread: TSContactThread) -> SignalCall { + public class func outgoingIndividualCall(thread: TSContactThread) -> SignalCall { let individualCall = IndividualCall( direction: .outgoing, - localId: localId, state: .dialing, thread: thread, sentAtTimestamp: Date.ows_millisecondTimestamp(), @@ -253,7 +257,6 @@ public class SignalCall: NSObject, CallManagerCallReference { } public class func incomingIndividualCall( - localId: UUID, thread: TSContactThread, sentAtTimestamp: UInt64, offerMediaType: TSRecentCallOfferType @@ -273,7 +276,6 @@ public class SignalCall: NSObject, CallManagerCallReference { let individualCall = IndividualCall( direction: .incoming, - localId: localId, state: .answering, thread: thread, sentAtTimestamp: sentAtTimestamp, diff --git a/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallManager.swift b/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallManager.swift index d51c6f8312..211987bd47 100644 --- a/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallManager.swift +++ b/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallManager.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2020 Open Whisper Systems. All rights reserved. +// Copyright (c) 2022 Open Whisper Systems. All rights reserved. // import UIKit @@ -48,12 +48,12 @@ final class CallKitCallManager: NSObject { } handle = CXHandle(type: type, value: value) } else { - let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.individualCall.localId.uuidString + let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString handle = CXHandle(type: .generic, value: callKitId) CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId) } - let startCallAction = CXStartCallAction(call: call.individualCall.localId, handle: handle) + let startCallAction = CXStartCallAction(call: call.localId, handle: handle) startCallAction.isVideo = call.individualCall.hasLocalVideo @@ -64,7 +64,7 @@ final class CallKitCallManager: NSObject { } func localHangup(call: SignalCall) { - let endCallAction = CXEndCallAction(call: call.individualCall.localId) + let endCallAction = CXEndCallAction(call: call.localId) let transaction = CXTransaction() transaction.addAction(endCallAction) @@ -72,7 +72,7 @@ final class CallKitCallManager: NSObject { } func setHeld(call: SignalCall, onHold: Bool) { - let setHeldCallAction = CXSetHeldCallAction(call: call.individualCall.localId, onHold: onHold) + let setHeldCallAction = CXSetHeldCallAction(call: call.localId, onHold: onHold) let transaction = CXTransaction() transaction.addAction(setHeldCallAction) @@ -80,7 +80,7 @@ final class CallKitCallManager: NSObject { } func setIsMuted(call: SignalCall, isMuted: Bool) { - let muteCallAction = CXSetMutedCallAction(call: call.individualCall.localId, muted: isMuted) + let muteCallAction = CXSetMutedCallAction(call: call.localId, muted: isMuted) let transaction = CXTransaction() transaction.addAction(muteCallAction) @@ -88,7 +88,7 @@ final class CallKitCallManager: NSObject { } func answer(call: SignalCall) { - let answerCallAction = CXAnswerCallAction(call: call.individualCall.localId) + let answerCallAction = CXAnswerCallAction(call: call.localId) let transaction = CXTransaction() transaction.addAction(answerCallAction) @@ -110,7 +110,7 @@ final class CallKitCallManager: NSObject { private(set) var calls = [SignalCall]() func callWithLocalId(_ localId: UUID) -> SignalCall? { - guard let index = calls.firstIndex(where: { $0.individualCall.localId == localId }) else { + guard let index = calls.firstIndex(where: { $0.localId == localId }) else { return nil } return calls[index] diff --git a/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallUIAdaptee.swift b/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallUIAdaptee.swift index 06723f5418..6311f616ed 100644 --- a/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallUIAdaptee.swift +++ b/Signal/src/Calls/UserInterface/Individual/CallKit/CallKitCallUIAdaptee.swift @@ -131,9 +131,9 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { switch error { case .timeout(description: _): - self.provider.reportCall(with: call.individualCall.localId, endedAt: Date(), reason: CXCallEndedReason.unanswered) + self.provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.unanswered) default: - self.provider.reportCall(with: call.individualCall.localId, endedAt: Date(), reason: CXCallEndedReason.failed) + self.provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.failed) } self.callManager.removeCall(call) } @@ -152,7 +152,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { update.remoteHandle = CXHandle(type: .phoneNumber, value: phoneNumber) } } else { - let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.individualCall.localId.uuidString + let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString update.remoteHandle = CXHandle(type: .generic, value: callKitId) CallKitIdStore.setAddress(call.individualCall.remoteAddress, forCallKitId: callKitId) update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled") @@ -164,7 +164,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { // Report the incoming call to the system - self.provider.reportNewIncomingCall(with: call.individualCall.localId, update: update) { error in + self.provider.reportNewIncomingCall(with: call.localId, update: update) { error in /* 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. @@ -207,12 +207,12 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Logger.info("") Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { - self.provider.reportOutgoingCall(with: call.individualCall.localId, connectedAt: nil) + self.provider.reportOutgoingCall(with: call.localId, connectedAt: nil) let update = CXCallUpdate() self.disableUnsupportedFeatures(callUpdate: update) - self.provider.reportCall(with: call.individualCall.localId, updated: update) + self.provider.reportCall(with: call.localId, updated: update) // When we tell CallKit about the call, it tries // to unmute the call. We can work around this @@ -245,7 +245,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Logger.info("") Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { - self.provider.reportCall(with: call.individualCall.localId, endedAt: nil, reason: CXCallEndedReason.remoteEnded) + self.provider.reportCall(with: call.localId, endedAt: nil, reason: CXCallEndedReason.remoteEnded) self.callManager.removeCall(call) } } @@ -255,7 +255,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Logger.info("") Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { - self.provider.reportCall(with: call.individualCall.localId, endedAt: nil, reason: CXCallEndedReason.unanswered) + self.provider.reportCall(with: call.localId, endedAt: nil, reason: CXCallEndedReason.unanswered) self.callManager.removeCall(call) } } @@ -265,7 +265,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Logger.info("") Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { - self.provider.reportCall(with: call.individualCall.localId, endedAt: nil, reason: .answeredElsewhere) + self.provider.reportCall(with: call.localId, endedAt: nil, reason: .answeredElsewhere) self.callManager.removeCall(call) } } @@ -275,7 +275,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Logger.info("") Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { - self.provider.reportCall(with: call.individualCall.localId, endedAt: nil, reason: .declinedElsewhere) + self.provider.reportCall(with: call.localId, endedAt: nil, reason: .declinedElsewhere) self.callManager.removeCall(call) } } @@ -286,7 +286,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { // Callkit doesn't have a reason for "busy elsewhere", .declinedElsewhere is close enough. - self.provider.reportCall(with: call.individualCall.localId, endedAt: nil, reason: .declinedElsewhere) + self.provider.reportCall(with: call.localId, endedAt: nil, reason: .declinedElsewhere) self.callManager.removeCall(call) } } @@ -309,7 +309,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { Self.providerReadyFlag.runNowOrWhenDidBecomeReadySync { let update = CXCallUpdate() update.hasVideo = hasLocalVideo - self.provider.reportCall(with: call.individualCall.localId, updated: update) + self.provider.reportCall(with: call.localId, updated: update) } } @@ -349,7 +349,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { self.callService.individualCallService.handleOutgoingCall(call) action.fulfill() - provider.reportOutgoingCall(with: call.individualCall.localId, startedConnectingAt: nil) + provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil) // Update the name used in the CallKit UI for outgoing calls when the user prefers not to show names // in their notifications @@ -357,7 +357,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate { let update = CXCallUpdate() update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled") - provider.reportCall(with: call.individualCall.localId, updated: update) + provider.reportCall(with: call.localId, updated: update) } } diff --git a/Signal/src/Calls/UserInterface/Individual/CallUIAdapter.swift b/Signal/src/Calls/UserInterface/Individual/CallUIAdapter.swift index 8fea6d8c88..99524b2c21 100644 --- a/Signal/src/Calls/UserInterface/Individual/CallUIAdapter.swift +++ b/Signal/src/Calls/UserInterface/Individual/CallUIAdapter.swift @@ -208,7 +208,7 @@ public class CallUIAdapter: NSObject, CallServiceObserver { return } - guard call.individualCall.localId == localId else { + guard call.localId == localId else { owsFailDebug("localId does not match current call") return } @@ -267,7 +267,7 @@ public class CallUIAdapter: NSObject, CallServiceObserver { return } - guard call.individualCall.localId == localId else { + guard call.localId == localId else { owsFailDebug("localId does not match current call") return } diff --git a/Signal/src/Calls/UserInterface/Individual/NonCallKitCallUIAdaptee.swift b/Signal/src/Calls/UserInterface/Individual/NonCallKitCallUIAdaptee.swift index 2da13bbc3c..d39a8d5558 100644 --- a/Signal/src/Calls/UserInterface/Individual/NonCallKitCallUIAdaptee.swift +++ b/Signal/src/Calls/UserInterface/Individual/NonCallKitCallUIAdaptee.swift @@ -74,7 +74,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { return } - guard call.individualCall.localId == localId else { + guard call.localId == localId else { owsFailDebug("localId does not match current call") return } @@ -85,7 +85,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { func answerCall(_ call: SignalCall) { AssertIsOnMainThread() - guard call.individualCall.localId == self.callService.currentCall?.individualCall.localId else { + guard call.localId == self.callService.currentCall?.localId else { owsFailDebug("localId does not match current call") return } @@ -111,7 +111,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { return } - guard call.individualCall.localId == localId else { + guard call.localId == localId else { owsFailDebug("localId does not match current call") return } @@ -124,7 +124,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { // If both parties hang up at the same moment, // call might already be nil. - guard self.callService.currentCall == nil || call.individualCall.localId == self.callService.currentCall?.individualCall.localId else { + guard self.callService.currentCall == nil || call.localId == self.callService.currentCall?.localId else { owsFailDebug("localId does not match current call") return } @@ -171,7 +171,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { func setIsMuted(call: SignalCall, isMuted: Bool) { AssertIsOnMainThread() - guard call.individualCall.localId == self.callService.currentCall?.individualCall.localId else { + guard call.localId == self.callService.currentCall?.localId else { owsFailDebug("localId does not match current call") return } @@ -182,7 +182,7 @@ class NonCallKitCallUIAdaptee: NSObject, CallUIAdaptee { func setHasLocalVideo(call: SignalCall, hasLocalVideo: Bool) { AssertIsOnMainThread() - guard call.individualCall.localId == self.callService.currentCall?.individualCall.localId else { + guard call.localId == self.callService.currentCall?.localId else { owsFailDebug("localId does not match current call") return } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUINotifications.swift b/Signal/src/ViewControllers/DebugUI/DebugUINotifications.swift index 2db64b71ee..f9dca67aea 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUINotifications.swift +++ b/Signal/src/ViewControllers/DebugUI/DebugUINotifications.swift @@ -92,7 +92,6 @@ class DebugUINotifications: DebugUIPage { func delayedNotificationDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (IndividualCall) -> Void) -> Guarantee { let call = SignalCall.incomingIndividualCall( - localId: UUID(), thread: thread, sentAtTimestamp: Date.ows_millisecondTimestamp(), offerMediaType: .audio