Merge branch 'mkirk/callKitPrivacyVsiOS11'

pull/1/head
Michael Kirk 7 years ago
commit 75e3516ebc

@ -1026,9 +1026,19 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
updateRemoteVideoLayout() updateRemoteVideoLayout()
} }
internal func dismissIfPossible(shouldDelay: Bool, ignoreNag: Bool = false, completion: (() -> Swift.Void)? = nil) { internal func dismissIfPossible(shouldDelay: Bool, ignoreNag ignoreNagParam: Bool = false, completion: (() -> Swift.Void)? = nil) {
callUIAdapter.audioService.delegate = nil callUIAdapter.audioService.delegate = nil
let ignoreNag: Bool = {
// Nothing to nag about on iOS11
if #available(iOS 11, *) {
return true
} else {
// otherwise on iOS10, nag as specified
return ignoreNagParam
}
}()
if hasDismissed { if hasDismissed {
// Don't dismiss twice. // Don't dismiss twice.
return return

@ -1,8 +1,10 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "NotificationSettingsOptionsViewController.h" #import "NotificationSettingsOptionsViewController.h"
#import "Signal-Swift.h"
#import "SignalApp.h"
#import <SignalMessaging/Environment.h> #import <SignalMessaging/Environment.h>
@implementation NotificationSettingsOptionsViewController @implementation NotificationSettingsOptionsViewController
@ -48,6 +50,10 @@
- (void)setNotificationType:(NotificationType)notificationType - (void)setNotificationType:(NotificationType)notificationType
{ {
[Environment.preferences setNotificationPreviewType:notificationType]; [Environment.preferences setNotificationPreviewType:notificationType];
// rebuild callUIAdapter since notification configuration changed.
[SignalApp.sharedApp.callService createCallUIAdapter];
[self.navigationController popViewControllerAnimated:YES]; [self.navigationController popViewControllerAnimated:YES];
} }

@ -56,7 +56,7 @@
[contents addSection:soundsSection]; [contents addSection:soundsSection];
OWSTableSection *backgroundSection = [OWSTableSection new]; OWSTableSection *backgroundSection = [OWSTableSection new];
backgroundSection.headerTitle = NSLocalizedString(@"NOTIFICATIONS_SECTION_BACKGROUND", nil); backgroundSection.headerTitle = NSLocalizedString(@"SETTINGS_NOTIFICATION_CONTENT_TITLE", @"table section header");
[backgroundSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ [backgroundSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:@"UITableViewCellStyleValue1"]; reuseIdentifier:@"UITableViewCellStyleValue1"];
@ -74,6 +74,8 @@
[NotificationSettingsOptionsViewController new]; [NotificationSettingsOptionsViewController new];
[weakSelf.navigationController pushViewController:vc animated:YES]; [weakSelf.navigationController pushViewController:vc animated:YES];
}]]; }]];
backgroundSection.footerTitle
= NSLocalizedString(@"SETTINGS_NOTIFICATION_CONTENT_DESCRIPTION", @"table section footer");
[contents addSection:backgroundSection]; [contents addSection:backgroundSection];
OWSTableSection *inAppSection = [OWSTableSection new]; OWSTableSection *inAppSection = [OWSTableSection new];

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "PrivacySettingsTableViewController.h" #import "PrivacySettingsTableViewController.h"
@ -80,7 +80,19 @@ NS_ASSUME_NONNULL_BEGIN
selector:@selector(didToggleCallsHideIPAddressSwitch:)]]; selector:@selector(didToggleCallsHideIPAddressSwitch:)]];
[contents addSection:callingSection]; [contents addSection:callingSection];
if ([UIDevice currentDevice].supportsCallKit) { if (@available(iOS 11, *)) {
OWSTableSection *callKitSection = [OWSTableSection new];
[callKitSection
addItem:[OWSTableItem switchItemWithText:NSLocalizedString(
@"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_TITLE",
@"Short table cell label")
isOn:[Environment.preferences isSystemCallLogEnabled]
target:weakSelf
selector:@selector(didToggleEnableSystemCallLogSwitch:)]];
callKitSection.footerTitle = NSLocalizedString(
@"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_DESCRIPTION", @"Settings table section footer.");
[contents addSection:callKitSection];
} else if (@available(iOS 10, *)) {
OWSTableSection *callKitSection = [OWSTableSection new]; OWSTableSection *callKitSection = [OWSTableSection new];
callKitSection.footerTitle callKitSection.footerTitle
= NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer."); = NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer.");
@ -173,17 +185,32 @@ NS_ASSUME_NONNULL_BEGIN
[Environment.preferences setDoCallsHideIPAddress:enabled]; [Environment.preferences setDoCallsHideIPAddress:enabled];
} }
- (void)didToggleEnableSystemCallLogSwitch:(UISwitch *)sender
{
DDLogInfo(@"%@ user toggled call kit preference: %@", self.logTag, (sender.isOn ? @"ON" : @"OFF"));
[[Environment current].preferences setIsSystemCallLogEnabled:sender.isOn];
// rebuild callUIAdapter since CallKit configuration changed.
[SignalApp.sharedApp.callService createCallUIAdapter];
}
- (void)didToggleEnableCallKitSwitch:(UISwitch *)sender { - (void)didToggleEnableCallKitSwitch:(UISwitch *)sender {
DDLogInfo(@"%@ user toggled call kit preference: %@", self.logTag, (sender.isOn ? @"ON" : @"OFF")); DDLogInfo(@"%@ user toggled call kit preference: %@", self.logTag, (sender.isOn ? @"ON" : @"OFF"));
[[Environment current].preferences setIsCallKitEnabled:sender.isOn]; [[Environment current].preferences setIsCallKitEnabled:sender.isOn];
// rebuild callUIAdapter since CallKit vs not changed. // rebuild callUIAdapter since CallKit vs not changed.
[SignalApp.sharedApp.callService createCallUIAdapter]; [SignalApp.sharedApp.callService createCallUIAdapter];
// Show/Hide dependent switch: CallKit privacy
[self updateTableContents]; [self updateTableContents];
} }
- (void)didToggleEnableCallKitPrivacySwitch:(UISwitch *)sender { - (void)didToggleEnableCallKitPrivacySwitch:(UISwitch *)sender {
DDLogInfo(@"%@ user toggled call kit privacy preference: %@", self.logTag, (sender.isOn ? @"ON" : @"OFF")); DDLogInfo(@"%@ user toggled call kit privacy preference: %@", self.logTag, (sender.isOn ? @"ON" : @"OFF"));
[[Environment current].preferences setIsCallKitPrivacyEnabled:!sender.isOn]; [[Environment current].preferences setIsCallKitPrivacyEnabled:!sender.isOn];
// rebuild callUIAdapter since CallKit configuration changed.
[SignalApp.sharedApp.callService createCallUIAdapter];
} }
#pragma mark - Log util #pragma mark - Log util

@ -123,8 +123,7 @@ protocol CallAudioServiceDelegate: class {
super.init() super.init()
// This fails when someone toggles iOS Call Integration // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings
SwiftSingletons.register(self)
// Configure audio session so we don't prompt user with Record permission until call is connected. // Configure audio session so we don't prompt user with Record permission until call is connected.

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
import UIKit import UIKit
@ -18,26 +18,29 @@ import SignalServiceKit
final class CallKitCallManager: NSObject { final class CallKitCallManager: NSObject {
let callController = CXCallController() let callController = CXCallController()
let showNamesOnCallScreen: Bool
static let kAnonymousCallHandlePrefix = "Signal:" static let kAnonymousCallHandlePrefix = "Signal:"
override required init() { required init(showNamesOnCallScreen: Bool) {
AssertIsOnMainThread() AssertIsOnMainThread()
self.showNamesOnCallScreen = showNamesOnCallScreen
super.init() super.init()
SwiftSingletons.register(self) // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings
} }
// MARK: Actions // MARK: Actions
func startCall(_ call: SignalCall) { func startCall(_ call: SignalCall) {
var handle: CXHandle var handle: CXHandle
if Environment.current().preferences.isCallKitPrivacyEnabled() {
if showNamesOnCallScreen {
handle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
} else {
let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString
handle = CXHandle(type: .generic, value: callKitId) handle = CXHandle(type: .generic, value: callKitId)
TSStorageManager.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId:callKitId) TSStorageManager.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId:callKitId)
} else {
handle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
} }
let startCallAction = CXStartCallAction(call: call.localId, handle: handle) let startCallAction = CXStartCallAction(call: call.localId, handle: handle)

@ -24,14 +24,15 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
internal let callService: CallService internal let callService: CallService
internal let notificationsAdapter: CallNotificationsAdapter internal let notificationsAdapter: CallNotificationsAdapter
internal let contactsManager: OWSContactsManager internal let contactsManager: OWSContactsManager
private let showNamesOnCallScreen: Bool
private let provider: CXProvider private let provider: CXProvider
let audioActivity: AudioActivity private let audioActivity: AudioActivity
// CallKit handles incoming ringer stop/start for us. Yay! // CallKit handles incoming ringer stop/start for us. Yay!
let hasManualRinger = false let hasManualRinger = false
// The app's provider configuration, representing its CallKit capabilities // The app's provider configuration, representing its CallKit capabilities
static var providerConfiguration: CXProviderConfiguration { class func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration {
let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application") let localizedName = NSLocalizedString("APPLICATION_NAME", comment: "Name of application")
let providerConfiguration = CXProviderConfiguration(localizedName: localizedName) let providerConfiguration = CXProviderConfiguration(localizedName: localizedName)
@ -50,24 +51,35 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
// default iOS ringtone OR the custom ringtone associated with this user's // default iOS ringtone OR the custom ringtone associated with this user's
// system contact, if possible (iOS 11 or later). // system contact, if possible (iOS 11 or later).
if #available(iOS 11.0, *) {
providerConfiguration.includesCallsInRecents = useSystemCallLog
} else {
// not configurable for iOS10+
assert(useSystemCallLog)
}
return providerConfiguration return providerConfiguration
} }
init(callService: CallService, contactsManager: OWSContactsManager, notificationsAdapter: CallNotificationsAdapter) { init(callService: CallService, contactsManager: OWSContactsManager, notificationsAdapter: CallNotificationsAdapter, showNamesOnCallScreen: Bool, useSystemCallLog: Bool) {
AssertIsOnMainThread() AssertIsOnMainThread()
Logger.debug("\(self.TAG) \(#function)") Logger.debug("\(self.TAG) \(#function)")
self.callManager = CallKitCallManager() self.callManager = CallKitCallManager(showNamesOnCallScreen: showNamesOnCallScreen)
self.callService = callService self.callService = callService
self.contactsManager = contactsManager self.contactsManager = contactsManager
self.notificationsAdapter = notificationsAdapter self.notificationsAdapter = notificationsAdapter
self.provider = CXProvider(configuration: type(of: self).providerConfiguration)
let providerConfiguration = type(of: self).buildProviderConfiguration(useSystemCallLog: useSystemCallLog)
self.provider = CXProvider(configuration: providerConfiguration)
self.audioActivity = AudioActivity(audioDescription: "[CallKitCallUIAdaptee]") self.audioActivity = AudioActivity(audioDescription: "[CallKitCallUIAdaptee]")
self.showNamesOnCallScreen = showNamesOnCallScreen
super.init() super.init()
SwiftSingletons.register(self) // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings
self.provider.setDelegate(self, queue: nil) self.provider.setDelegate(self, queue: nil)
} }
@ -112,14 +124,15 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
// Construct a CXCallUpdate describing the incoming call, including the caller. // Construct a CXCallUpdate describing the incoming call, including the caller.
let update = CXCallUpdate() let update = CXCallUpdate()
if Environment.current().preferences.isCallKitPrivacyEnabled() {
if showNamesOnCallScreen {
update.localizedCallerName = self.contactsManager.stringForConversationTitle(withPhoneIdentifier: call.remotePhoneNumber)
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
} else {
let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString let callKitId = CallKitCallManager.kAnonymousCallHandlePrefix + call.localId.uuidString
update.remoteHandle = CXHandle(type: .generic, value: callKitId) update.remoteHandle = CXHandle(type: .generic, value: callKitId)
TSStorageManager.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId: callKitId) TSStorageManager.shared().setPhoneNumber(call.remotePhoneNumber, forCallKitId: callKitId)
update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled") update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled")
} else {
update.localizedCallerName = self.contactsManager.stringForConversationTitle(withPhoneIdentifier: call.remotePhoneNumber)
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
} }
update.hasVideo = call.hasLocalVideo update.hasVideo = call.hasLocalVideo
@ -254,8 +267,9 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
action.fulfill() action.fulfill()
self.provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil) self.provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil)
if Environment.current().preferences.isCallKitPrivacyEnabled() { // Update the name used in the CallKit UI for outgoing calls when the user prefers not to show names
// Update the name used in the CallKit UI for outgoing calls. // in ther notifications
if !showNamesOnCallScreen {
let update = CXCallUpdate() let update = CXCallUpdate()
update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME",
comment: "The generic name used for calls if CallKit privacy is enabled") comment: "The generic name used for calls if CallKit privacy is enabled")

@ -91,9 +91,21 @@ extension CallUIAdaptee {
// So we use the non-CallKit call UI. // So we use the non-CallKit call UI.
Logger.info("\(TAG) choosing non-callkit adaptee for simulator.") Logger.info("\(TAG) choosing non-callkit adaptee for simulator.")
adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter) adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
} else if #available(iOS 11, *) {
Logger.info("\(TAG) choosing callkit adaptee for iOS11+")
let showNames = Environment.preferences().notificationPreviewType() != .noNameNoPreview
let useSystemCallLog = Environment.preferences().isSystemCallLogEnabled()
adaptee = CallKitCallUIAdaptee(callService: callService, contactsManager: contactsManager, notificationsAdapter: notificationsAdapter, showNamesOnCallScreen: showNames, useSystemCallLog: useSystemCallLog)
} else if #available(iOS 10.0, *), Environment.current().preferences.isCallKitEnabled() { } else if #available(iOS 10.0, *), Environment.current().preferences.isCallKitEnabled() {
Logger.info("\(TAG) choosing callkit adaptee for iOS10+") Logger.info("\(TAG) choosing callkit adaptee for iOS10")
adaptee = CallKitCallUIAdaptee(callService: callService, contactsManager: contactsManager, notificationsAdapter: notificationsAdapter) let hideNames = Environment.preferences().isCallKitPrivacyEnabled() || Environment.preferences().notificationPreviewType() == .noNameNoPreview
let showNames = !hideNames
// All CallKit calls use the system call log on iOS10
let useSystemCallLog = true
adaptee = CallKitCallUIAdaptee(callService: callService, contactsManager: contactsManager, notificationsAdapter: notificationsAdapter, showNamesOnCallScreen: showNames, useSystemCallLog: useSystemCallLog)
} else { } else {
Logger.info("\(TAG) choosing non-callkit adaptee") Logger.info("\(TAG) choosing non-callkit adaptee")
adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter) adaptee = NonCallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
@ -103,7 +115,7 @@ extension CallUIAdaptee {
super.init() super.init()
SwiftSingletons.register(self) // We cannot assert singleton here, because this class gets rebuilt when the user changes relevant call settings
callService.addObserverAndSyncState(observer: self) callService.addObserverAndSyncState(observer: self)
} }

@ -112,10 +112,8 @@
} }
case NotificationNameNoPreview: case NotificationNameNoPreview:
case NotificationNamePreview: { case NotificationNamePreview: {
alertMessage = (([UIDevice currentDevice].supportsCallKit && alertMessage =
[[Environment current].preferences isCallKitPrivacyEnabled]) [NSString stringWithFormat:[CallStrings missedCallNotificationBodyWithCallerName], callerName];
? [CallStrings missedCallNotificationBodyWithoutCallerName]
: [NSString stringWithFormat:[CallStrings missedCallNotificationBodyWithCallerName], callerName]);
break; break;
} }
} }
@ -152,12 +150,8 @@
} }
case NotificationNameNoPreview: case NotificationNameNoPreview:
case NotificationNamePreview: { case NotificationNamePreview: {
alertMessage = (([UIDevice currentDevice].supportsCallKit && alertMessage = [NSString
[[Environment current].preferences isCallKitPrivacyEnabled]) stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName], callerName];
? [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName]
: [NSString
stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName],
callerName]);
break; break;
} }
} }
@ -193,12 +187,8 @@
} }
case NotificationNameNoPreview: case NotificationNameNoPreview:
case NotificationNamePreview: { case NotificationNamePreview: {
alertMessage = (([UIDevice currentDevice].supportsCallKit && alertMessage = [NSString
[[Environment current].preferences isCallKitPrivacyEnabled]) stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName], callerName];
? [CallStrings missedCallWithIdentityChangeNotificationBodyWithoutCallerName]
: [NSString
stringWithFormat:[CallStrings missedCallWithIdentityChangeNotificationBodyWithCallerName],
callerName]);
break; break;
} }
} }

@ -1147,10 +1147,7 @@
"NOTIFICATIONS_FOOTER_WARNING" = "Due to known bugs in Apple's push framework, message previews will only be shown if the message is retrieved within 30 seconds after being sent. The application badge might be inaccurate as a result."; "NOTIFICATIONS_FOOTER_WARNING" = "Due to known bugs in Apple's push framework, message previews will only be shown if the message is retrieved within 30 seconds after being sent. The application badge might be inaccurate as a result.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NOTIFICATIONS_NONE" = "No name or message"; "NOTIFICATIONS_NONE" = "No Name or Content";
/* No comment provided by engineer. */
"NOTIFICATIONS_SECTION_BACKGROUND" = "Background Notifications";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NOTIFICATIONS_SECTION_INAPP" = "In-App Notifications"; "NOTIFICATIONS_SECTION_INAPP" = "In-App Notifications";
@ -1159,10 +1156,10 @@
"NOTIFICATIONS_SECTION_SOUNDS" = "Sounds"; "NOTIFICATIONS_SECTION_SOUNDS" = "Sounds";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NOTIFICATIONS_SENDER_AND_MESSAGE" = "Sender name & message"; "NOTIFICATIONS_SENDER_AND_MESSAGE" = "Name and Content";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NOTIFICATIONS_SENDER_ONLY" = "Sender name only"; "NOTIFICATIONS_SENDER_ONLY" = "Name Only";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NOTIFICATIONS_SHOW" = "Show"; "NOTIFICATIONS_SHOW" = "Show";
@ -1575,12 +1572,24 @@
/* Title for settings activity */ /* Title for settings activity */
"SETTINGS_NAV_BAR_TITLE" = "Settings"; "SETTINGS_NAV_BAR_TITLE" = "Settings";
/* table section footer */
"SETTINGS_NOTIFICATION_CONTENT_DESCRIPTION" = "Call and Message notifications can appear while your phone is locked. You may wish to limit what is shown in these notifications.";
/* table section header */
"SETTINGS_NOTIFICATION_CONTENT_TITLE" = "Notification Content";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_NOTIFICATIONS" = "Notifications"; "SETTINGS_NOTIFICATIONS" = "Notifications";
/* Label for 'CallKit privacy' preference */ /* Label for 'CallKit privacy' preference */
"SETTINGS_PRIVACY_CALLKIT_PRIVACY_TITLE" = "Show Caller's Name & Number"; "SETTINGS_PRIVACY_CALLKIT_PRIVACY_TITLE" = "Show Caller's Name & Number";
/* Settings table section footer. */
"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_DESCRIPTION" = "Disabling this will prevent calls from appearing in the \"Recents\" list in the iOS Phone app.";
/* Short table cell label */
"SETTINGS_PRIVACY_CALLKIT_SYSTEM_CALL_LOG_PREFERENCE_TITLE" = "System Call Logs";
/* Short table cell label */ /* Short table cell label */
"SETTINGS_PRIVACY_CALLKIT_TITLE" = "iOS Call Integration"; "SETTINGS_PRIVACY_CALLKIT_TITLE" = "iOS Call Integration";

@ -59,8 +59,14 @@ extern NSString *const OWSPreferencesKeyEnableDebugLog;
#pragma mark Callkit #pragma mark Callkit
- (BOOL)isSystemCallLogEnabled;
- (void)setIsSystemCallLogEnabled:(BOOL)flag;
#pragma mark - Legacy CallKit settings
- (BOOL)isCallKitEnabled; - (BOOL)isCallKitEnabled;
- (void)setIsCallKitEnabled:(BOOL)flag; - (void)setIsCallKitEnabled:(BOOL)flag;
// Returns YES IFF isCallKitEnabled has been set by user. // Returns YES IFF isCallKitEnabled has been set by user.
- (BOOL)isCallKitEnabledSet; - (BOOL)isCallKitEnabledSet;

@ -26,6 +26,7 @@ NSString *const OWSPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress";
NSString *const OWSPreferencesKeyHasDeclinedNoContactsView = @"hasDeclinedNoContactsView"; NSString *const OWSPreferencesKeyHasDeclinedNoContactsView = @"hasDeclinedNoContactsView";
NSString *const OWSPreferencesKeyIOSUpgradeNagDate = @"iOSUpgradeNagDate"; NSString *const OWSPreferencesKeyIOSUpgradeNagDate = @"iOSUpgradeNagDate";
NSString *const OWSPreferencesKey_IsReadyForAppExtensions = @"isReadyForAppExtensions_5"; NSString *const OWSPreferencesKey_IsReadyForAppExtensions = @"isReadyForAppExtensions_5";
NSString *const OWSPreferencesKeySystemCallLogEnabled = @"OWSPreferencesKeySystemCallLogEnabled";
@implementation OWSPreferences @implementation OWSPreferences
@ -173,36 +174,122 @@ NSString *const OWSPreferencesKey_IsReadyForAppExtensions = @"isReadyForAppExten
#pragma mark CallKit #pragma mark CallKit
- (BOOL)isSystemCallLogEnabled
{
if (@available(iOS 11, *)) {
// do nothing
} else {
OWSFail(@"%@ Call Logging can only be configured on iOS11+", self.logTag);
return NO;
}
NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeySystemCallLogEnabled];
if (preference) {
return preference.boolValue;
} else {
// For legacy users, who may have previously intentionally disabled CallKit because they
// didn't want their calls showing up in the call log, we want to disable call logging
NSNumber *callKitPreference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled];
if (callKitPreference && !callKitPreference.boolValue) {
// user explicitly opted out of callKit, so disable system call logging.
return NO;
}
}
// For everyone else, including new users, enable by default.
return YES;
}
- (void)setIsSystemCallLogEnabled:(BOOL)flag
{
if (@available(iOS 11, *)) {
// do nothing
} else {
OWSFail(@"%@ Call Logging can only be configured on iOS11+", self.logTag);
return;
}
[self setValueForKey:OWSPreferencesKeySystemCallLogEnabled toValue:@(flag)];
}
// In iOS 10.2.1, Apple fixed a bug wherein call history was backed up to iCloud.
//
// See: https://support.apple.com/en-us/HT207482
//
// In iOS 11, Apple introduced a property CXProviderConfiguration.includesCallsInRecents
// that allows us to prevent Signal calls made with CallKit from showing up in the device's
// call history.
//
// Therefore in versions of iOS after 11, we have no need of call privacy.
#pragma mark Legacy CallKit
- (BOOL)isCallKitEnabled - (BOOL)isCallKitEnabled
{ {
if (@available(iOS 11, *)) {
OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return NO;
}
NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled]; NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled];
return preference ? [preference boolValue] : YES; return preference ? [preference boolValue] : YES;
} }
- (void)setIsCallKitEnabled:(BOOL)flag - (void)setIsCallKitEnabled:(BOOL)flag
{ {
if (@available(iOS 11, *)) {
OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return;
}
[self setValueForKey:OWSPreferencesKeyCallKitEnabled toValue:@(flag)]; [self setValueForKey:OWSPreferencesKeyCallKitEnabled toValue:@(flag)];
OWSFail(@"Rev callUIAdaptee to get new setting");
} }
- (BOOL)isCallKitEnabledSet - (BOOL)isCallKitEnabledSet
{ {
if (@available(iOS 11, *)) {
OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return NO;
}
NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled]; NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitEnabled];
return preference != nil; return preference != nil;
} }
- (BOOL)isCallKitPrivacyEnabled - (BOOL)isCallKitPrivacyEnabled
{ {
NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled]; if (@available(iOS 11, *)) {
return preference ? [preference boolValue] : YES; OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return NO;
}
NSNumber *_Nullable preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled];
if (preference) {
return [preference boolValue];
} else {
// Private by default.
return YES;
}
} }
- (void)setIsCallKitPrivacyEnabled:(BOOL)flag - (void)setIsCallKitPrivacyEnabled:(BOOL)flag
{ {
if (@available(iOS 11, *)) {
OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return;
}
[self setValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled toValue:@(flag)]; [self setValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled toValue:@(flag)];
} }
- (BOOL)isCallKitPrivacySet - (BOOL)isCallKitPrivacySet
{ {
if (@available(iOS 11, *)) {
OWSFail(@"%@ CallKit privacy is irrelevant for iOS11+", self.logTag);
return NO;
}
NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled]; NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyCallKitPrivacyEnabled];
return preference != nil; return preference != nil;
} }

Loading…
Cancel
Save