From 336c694b522caa8a4ca739d36366be3a4c1589ea Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Thu, 11 Nov 2021 12:12:12 +1100 Subject: [PATCH] refactoring on showing call ip exposure --- .../SessionCallManager+CXProvider.swift | 13 ++++--- .../Call Management/SessionCallManager.swift | 24 +------------ Session/Calls/CallVC.swift | 25 +++---------- .../Views & Modals/IncomingCallBanner.swift | 17 +-------- .../ConversationVC+Interaction.swift | 10 +++--- Session/Conversations/ConversationVC.swift | 6 ++-- .../Views & Modals/CallModal.swift | 5 +++ Session/Meta/AppDelegate.swift | 4 +-- .../Translations/en.lproj/Localizable.strings | 6 ++++ .../PrivacySettingsTableViewController.m | 35 +++++++++++++++++++ .../Database/SSKPreferences.swift | 13 +++++++ .../MessageReceiver+Handling.swift | 12 ++++--- .../NotificationServiceExtension.swift | 3 ++ 13 files changed, 94 insertions(+), 79 deletions(-) diff --git a/Session/Calls/Call Management/SessionCallManager+CXProvider.swift b/Session/Calls/Call Management/SessionCallManager+CXProvider.swift index 84b0d2bb8..ebfae6cd5 100644 --- a/Session/Calls/Call Management/SessionCallManager+CXProvider.swift +++ b/Session/Calls/Call Management/SessionCallManager+CXProvider.swift @@ -21,12 +21,15 @@ extension SessionCallManager: CXProviderDelegate { if let _ = CurrentAppContext().frontmostViewController() as? CallVC { call.answerSessionCall() } else { - let userDefaults = UserDefaults.standard - if userDefaults[.hasSeenCallIPExposureWarning] { - showCallVC() - } else { - showCallModal() + guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // TODO: Handle more gracefully + let callVC = CallVC(for: self.currentCall!) + callVC.shouldAnswer = true + if let conversationVC = presentingVC as? ConversationVC { + callVC.conversationVC = conversationVC + conversationVC.inputAccessoryView?.isHidden = true + conversationVC.inputAccessoryView?.alpha = 0 } + presentingVC.present(callVC, animated: true, completion: nil) } action.fulfill() } else { diff --git a/Session/Calls/Call Management/SessionCallManager.swift b/Session/Calls/Call Management/SessionCallManager.swift index 4120311f8..0d561748f 100644 --- a/Session/Calls/Call Management/SessionCallManager.swift +++ b/Session/Calls/Call Management/SessionCallManager.swift @@ -123,7 +123,7 @@ public final class SessionCallManager: NSObject { callUpdate.supportsDTMF = false } - public func handleIncomingCallOfferInBusyState(offerMessage: CallMessage, using transaction: YapDatabaseReadWriteTransaction) { + public func handleIncomingCallOfferInBusyOrUnenabledState(offerMessage: CallMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let caller = offerMessage.sender, let thread = TSContactThread.fetch(for: caller, using: transaction) else { return } let message = CallMessage() message.uuid = offerMessage.uuid @@ -134,27 +134,5 @@ public final class SessionCallManager: NSObject { tsMessage.updateCall(withNewBody: NSLocalizedString("call_missing", comment: ""), transaction: transaction) } } - - internal func showCallModal() { - let callModal = CallModal() { [weak self] in - self?.showCallVC() - } - callModal.modalPresentationStyle = .overFullScreen - callModal.modalTransitionStyle = .crossDissolve - guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // TODO: Handle more gracefully - presentingVC.present(callModal, animated: true, completion: nil) - } - - internal func showCallVC() { - guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // TODO: Handle more gracefully - let callVC = CallVC(for: self.currentCall!) - callVC.shouldAnswer = true - if let conversationVC = presentingVC as? ConversationVC { - callVC.conversationVC = conversationVC - conversationVC.inputAccessoryView?.isHidden = true - conversationVC.inputAccessoryView?.alpha = 0 - } - presentingVC.present(callVC, animated: true, completion: nil) - } } diff --git a/Session/Calls/CallVC.swift b/Session/Calls/CallVC.swift index 27f665cec..af8b80e00 100644 --- a/Session/Calls/CallVC.swift +++ b/Session/Calls/CallVC.swift @@ -314,29 +314,14 @@ final class CallVC : UIViewController, VideoPreviewDelegate { } } - internal func showCallModal() { - let callModal = CallModal() { [weak self] in - self?.answerCall() - } - callModal.modalPresentationStyle = .overFullScreen - callModal.modalTransitionStyle = .crossDissolve - present(callModal, animated: true, completion: nil) - } - @objc private func answerCall() { - let userDefaults = UserDefaults.standard - if userDefaults[.hasSeenCallIPExposureWarning] { - AppEnvironment.shared.callManager.answerCall(call) { error in - DispatchQueue.main.async { - if let _ = error { - self.callInfoLabel.text = "Can't answer the call." - self.endCall() - } + AppEnvironment.shared.callManager.answerCall(call) { error in + DispatchQueue.main.async { + if let _ = error { + self.callInfoLabel.text = "Can't answer the call." + self.endCall() } } - } else { - userDefaults[.hasSeenCallIPExposureWarning] = true - showCallModal() } } diff --git a/Session/Calls/Views & Modals/IncomingCallBanner.swift b/Session/Calls/Views & Modals/IncomingCallBanner.swift index 569ffdb1f..2a2cd3cbe 100644 --- a/Session/Calls/Views & Modals/IncomingCallBanner.swift +++ b/Session/Calls/Views & Modals/IncomingCallBanner.swift @@ -136,22 +136,7 @@ final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate { } @objc private func answerCall() { - let userDefaults = UserDefaults.standard - if userDefaults[.hasSeenCallIPExposureWarning] { - showCallVC(answer: true) - } else { - showCallModal() - } - } - - internal func showCallModal() { - let callModal = CallModal() { [weak self] in - self?.showCallVC(answer: true) - } - callModal.modalPresentationStyle = .overFullScreen - callModal.modalTransitionStyle = .crossDissolve - guard let presentingVC = CurrentAppContext().frontmostViewController() else { preconditionFailure() } // TODO: Handle more gracefully - presentingVC.present(callModal, animated: true, completion: nil) + showCallVC(answer: true) } @objc private func endCall() { diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 7bf6de1c4..0aa3c5985 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -29,7 +29,10 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc // MARK: Call @objc func startCall(_ sender: Any?) { let userDefaults = UserDefaults.standard - if userDefaults[.hasSeenCallIPExposureWarning] { + if !SSKPreferences.areCallsEnabled && !userDefaults[.hasSeenCallIPExposureWarning] { + userDefaults[.hasSeenCallIPExposureWarning] = true + showCallModal() + } else if SSKPreferences.areCallsEnabled { guard let contactSessionID = (thread as? TSContactThread)?.contactSessionID() else { return } guard AppEnvironment.shared.callManager.currentCall == nil else { return } let call = SessionCall(for: contactSessionID, uuid: UUID().uuidString, mode: .offer, outgoing: true) @@ -38,9 +41,6 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc self.inputAccessoryView?.isHidden = true self.inputAccessoryView?.alpha = 0 present(callVC, animated: true, completion: nil) - } else { - userDefaults[.hasSeenCallIPExposureWarning] = true - showCallModal() } } @@ -48,8 +48,6 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc let callModal = CallModal() { [weak self] in self?.startCall(nil) } - callModal.modalPresentationStyle = .overFullScreen - callModal.modalTransitionStyle = .crossDissolve present(callModal, animated: true, completion: nil) } diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index a3eb195c5..641c8a9ea 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -309,8 +309,10 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat settingsButton.accessibilityLabel = "Settings button" settingsButton.isAccessibilityElement = true rightBarButtonItems.append(settingsButton) - let callButton = UIBarButtonItem(image: UIImage(named: "Phone")!, style: .plain, target: self, action: #selector(startCall)) - rightBarButtonItems.append(callButton) + if SSKPreferences.areCallsEnabled || !UserDefaults.standard[.hasSeenCallIPExposureWarning] { + let callButton = UIBarButtonItem(image: UIImage(named: "Phone")!, style: .plain, target: self, action: #selector(startCall)) + rightBarButtonItems.append(callButton) + } } else { let settingsButton = UIBarButtonItem(image: UIImage(named: "Gear"), style: .plain, target: self, action: #selector(openSettings)) settingsButton.accessibilityLabel = "Settings button" diff --git a/Session/Conversations/Views & Modals/CallModal.swift b/Session/Conversations/Views & Modals/CallModal.swift index 0620646e7..d6e512027 100644 --- a/Session/Conversations/Views & Modals/CallModal.swift +++ b/Session/Conversations/Views & Modals/CallModal.swift @@ -1,11 +1,15 @@ +@objc final class CallModal : Modal { private let onCallEnabled: () -> Void // MARK: Lifecycle + @objc init(onCallEnabled: @escaping () -> Void) { self.onCallEnabled = onCallEnabled super.init(nibName: nil, bundle: nil) + self.modalPresentationStyle = .overFullScreen + self.modalTransitionStyle = .crossDissolve } required init?(coder: NSCoder) { @@ -59,6 +63,7 @@ final class CallModal : Modal { // MARK: Interaction @objc private func enable() { + SSKPreferences.areCallsEnabled = true presentingViewController?.dismiss(animated: true, completion: nil) onCallEnabled() } diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 0033e2cc4..038a7d977 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -25,8 +25,8 @@ extension AppDelegate { MessageReceiver.handlePreOfferCallMessage = { (message, transaction) in guard CurrentAppContext().isMainApp else { return } let callManager = AppEnvironment.shared.callManager - guard callManager.currentCall == nil else { - callManager.handleIncomingCallOfferInBusyState(offerMessage: message, using: transaction) + guard callManager.currentCall == nil || !SSKPreferences.areCallsEnabled else { + callManager.handleIncomingCallOfferInBusyOrUnenabledState(offerMessage: message, using: transaction) return } DispatchQueue.main.async { diff --git a/Session/Meta/Translations/en.lproj/Localizable.strings b/Session/Meta/Translations/en.lproj/Localizable.strings index 31673a38b..4bbda8679 100644 --- a/Session/Meta/Translations/en.lproj/Localizable.strings +++ b/Session/Meta/Translations/en.lproj/Localizable.strings @@ -350,6 +350,12 @@ "SETTINGS_LINK_PREVIEWS_FOOTER" = "Previews are supported for most urls."; /* Header for setting for enabling & disabling link previews. */ "SETTINGS_LINK_PREVIEWS_HEADER" = "Link Previews"; +/* Setting for enabling & disabling voice & video calls. */ +"SETTINGS_CALLS" = "Voice and video calls"; +/* Footer for setting for enabling & disabling voice & video calls. */ +"SETTINGS_CALLS_FOOTER" = "Allow access to accept voice and video calls from other users."; +/* Header for setting for enabling & disabling voice & video calls. */ +"SETTINGS_CALLS_HEADER" = "Calls"; /* table section header */ "SETTINGS_NOTIFICATION_CONTENT_TITLE" = "Notification Content"; /* Label for the 'read receipts' setting. */ diff --git a/Session/Settings/PrivacySettingsTableViewController.m b/Session/Settings/PrivacySettingsTableViewController.m index 81f2f18a4..9c6217d6b 100644 --- a/Session/Settings/PrivacySettingsTableViewController.m +++ b/Session/Settings/PrivacySettingsTableViewController.m @@ -197,6 +197,25 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s linkPreviewsSection.footerTitle = NSLocalizedString( @"SETTINGS_LINK_PREVIEWS_FOOTER", @"Footer for setting for enabling & disabling link previews."); [contents addSection:linkPreviewsSection]; + + OWSTableSection *callsSection = [OWSTableSection new]; + [callsSection + addItem:[OWSTableItem switchItemWithText:NSLocalizedString(@"SETTINGS_CALLS", + @"Setting for enabling & disabling voice & video calls.") + accessibilityIdentifier:[NSString stringWithFormat:@"settings.privacy.%@", @"calls"] + isOnBlock:^{ + return [SSKPreferences areCallsEnabled]; + } + isEnabledBlock:^{ + return YES; + } + target:weakSelf + selector:@selector(didToggleCallsEnabled:)]]; + callsSection.headerTitle = NSLocalizedString( + @"SETTINGS_CALLS_HEADER", @"Header for setting for enabling & disabling voice & video calls."); + callsSection.footerTitle = NSLocalizedString( + @"SETTINGS_CALLS_FOOTER", @"Footer for setting for enabling & disabling voice & video calls."); + [contents addSection:callsSection]; self.contents = contents; } @@ -260,6 +279,22 @@ static NSString *const kSealedSenderInfoURL = @"https://signal.org/blog/sealed-s SSKPreferences.areLinkPreviewsEnabled = enabled; } +- (void)didToggleCallsEnabled:(UISwitch *)sender +{ + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + BOOL enabled = sender.isOn; + if (enabled && ![userDefaults boolForKey:@"hasSeenCallIPExposureWarning"]) { + [userDefaults setBool:YES forKey:@"hasSeenCallIPExposureWarning"]; + CallModal *modal = [[CallModal alloc] initOnCallEnabled:^{ + OWSLogInfo(@"toggled to: %@", (enabled ? @"ON" : @"OFF")); + }]; + [self presentViewController:modal animated:YES completion:nil]; + } else { + OWSLogInfo(@"toggled to: %@", (enabled ? @"ON" : @"OFF")); + SSKPreferences.areCallsEnabled = enabled; + } +} + - (void)isScreenLockEnabledDidChange:(UISwitch *)sender { BOOL shouldBeEnabled = sender.isOn; diff --git a/SessionMessagingKit/Database/SSKPreferences.swift b/SessionMessagingKit/Database/SSKPreferences.swift index 9d4c34f5d..ea6114f42 100644 --- a/SessionMessagingKit/Database/SSKPreferences.swift +++ b/SessionMessagingKit/Database/SSKPreferences.swift @@ -24,6 +24,19 @@ public class SSKPreferences: NSObject { setBool(newValue, key: areLinkPreviewsEnabledKey) } } + + // MARK: - + private static let areCallsEnabledKey = "areCallsEnabled" + + @objc + public static var areCallsEnabled: Bool { + get { + return getBool(key: areCallsEnabledKey, defaultValue: false) + } + set { + setBool(newValue, key: areCallsEnabledKey) + } + } // MARK: - diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 38eef7c00..0caa30142 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -267,12 +267,14 @@ extension MessageReceiver { switch message.kind! { case .preOffer: print("[Calls] Received pre-offer message.") - let storage = SNMessagingKitConfiguration.shared.storage let transaction = transaction as! YapDatabaseReadWriteTransaction - if let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, openGroupID: nil, using: transaction), - let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { - let tsMessage = TSIncomingMessage.from(message, associatedWith: thread) - tsMessage.save(with: transaction) + if SSKPreferences.areCallsEnabled { + let storage = SNMessagingKitConfiguration.shared.storage + if let threadID = storage.getOrCreateThread(for: message.sender!, groupPublicKey: message.groupPublicKey, openGroupID: nil, using: transaction), + let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) { + let tsMessage = TSIncomingMessage.from(message, associatedWith: thread) + tsMessage.save(with: transaction) + } } handlePreOfferCallMessage?(message, transaction) case .offer: diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 8a7f643c1..744193529 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -92,6 +92,9 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension } case let callMessage as CallMessage: MessageReceiver.handleCallMessage(callMessage, using: transaction) + if !SSKPreferences.areCallsEnabled { + return self.completeSilenty() + } notificationContent.userInfo = userInfo notificationContent.badge = 1 notificationContent.title = "Session"