Add and honor the “CallKit Privacy” setting.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 8104ffa129
commit 065d383c15

@ -22,7 +22,9 @@ final class CallKitCallManager: NSObject {
// MARK: Actions // MARK: Actions
func startCall(_ call: SignalCall) { func startCall(_ call: SignalCall) {
let handle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber) let handle = (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
? CXHandle(type: .generic, value: call.localId.uuidString)
: CXHandle(type: .phoneNumber, value: call.remotePhoneNumber))
let startCallAction = CXStartCallAction(call: call.localId, handle: handle) let startCallAction = CXStartCallAction(call: call.localId, handle: handle)
startCallAction.isVideo = call.hasLocalVideo startCallAction.isVideo = call.hasLocalVideo

@ -37,7 +37,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
providerConfiguration.maximumCallsPerCallGroup = 1 providerConfiguration.maximumCallsPerCallGroup = 1
providerConfiguration.supportedHandleTypes = [.phoneNumber] providerConfiguration.supportedHandleTypes = [.phoneNumber, .generic]
if let iconMaskImage = UIImage(named: "IconMask") { if let iconMaskImage = UIImage(named: "IconMask") {
providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage) providerConfiguration.iconTemplateImageData = UIImagePNGRepresentation(iconMaskImage)
@ -84,7 +84,7 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
AssertIsOnMainThread() AssertIsOnMainThread()
Logger.debug("\(self.TAG) \(#function)") Logger.debug("\(self.TAG) \(#function)")
switch (error) { switch error {
case .timeout(description: _): case .timeout(description: _):
provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.unanswered) provider.reportCall(with: call.localId, endedAt: Date(), reason: CXCallEndedReason.unanswered)
default: default:
@ -100,8 +100,12 @@ 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()
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber) update.remoteHandle = (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
? CXHandle(type: .generic, value: call.localId.uuidString)
: CXHandle(type: .phoneNumber, value: call.remotePhoneNumber))
update.hasVideo = call.hasLocalVideo update.hasVideo = call.hasLocalVideo
// Update the name used in the CallKit UI for incoming calls.
update.localizedCallerName = NSLocalizedString("CALLKIT_ANONYMOUS_CONTACT_NAME", comment: "The generic name used for calls if CallKit privacy is enabled")
disableUnsupportedFeatures(callUpdate: update) disableUnsupportedFeatures(callUpdate: update)
// Report the incoming call to the system // Report the incoming call to the system
@ -192,7 +196,6 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
Logger.debug("\(self.TAG) \(#function)") Logger.debug("\(self.TAG) \(#function)")
let update = CXCallUpdate() let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .phoneNumber, value: call.remotePhoneNumber)
update.hasVideo = hasLocalVideo update.hasVideo = hasLocalVideo
// Update the CallKit UI. // Update the CallKit UI.
@ -234,6 +237,11 @@ final class CallKitCallUIAdaptee: NSObject, CallUIAdaptee, CXProviderDelegate {
_ = self.callService.handleOutgoingCall(call) _ = self.callService.handleOutgoingCall(call)
action.fulfill() action.fulfill()
self.provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil) self.provider.reportOutgoingCall(with: call.localId, startedConnectingAt: nil)
// Update the name used in the CallKit UI for outgoing calls.
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.localId, updated: update)
} }
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {

@ -78,7 +78,7 @@ 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 10.0, *), Environment.getCurrent().preferences.isCallKitEnabled() { } else if #available(iOS 10.0, *) {
Logger.info("\(TAG) choosing callkit adaptee for iOS10+") Logger.info("\(TAG) choosing callkit adaptee for iOS10+")
adaptee = CallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter) adaptee = CallKitCallUIAdaptee(callService: callService, notificationsAdapter: notificationsAdapter)
} else { } else {

@ -68,8 +68,8 @@ extern NSString *const PropertyListPreferencesKeyEnableDebugLog;
#pragma mark Callkit #pragma mark Callkit
- (BOOL)isCallKitEnabled; - (BOOL)isCallKitPrivacyEnabled;
- (void)setIsCallKitEnabled:(BOOL)flag; - (void)setIsCallKitPrivacyEnabled:(BOOL)flag;
#pragma mark direct call connectivity (non-TURN) #pragma mark direct call connectivity (non-TURN)

@ -23,6 +23,7 @@ NSString *const PropertyListPreferencesKeyHasRegisteredVoipPush = @"VOIPPushEnab
NSString *const PropertyListPreferencesKeyLastRecordedPushToken = @"LastRecordedPushToken"; NSString *const PropertyListPreferencesKeyLastRecordedPushToken = @"LastRecordedPushToken";
NSString *const PropertyListPreferencesKeyLastRecordedVoipToken = @"LastRecordedVoipToken"; NSString *const PropertyListPreferencesKeyLastRecordedVoipToken = @"LastRecordedVoipToken";
NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled"; NSString *const PropertyListPreferencesKeyCallKitEnabled = @"CallKitEnabled";
NSString *const PropertyListPreferencesKeyCallKitPrivacyEnabled = @"CallKitPrivacyEnabled";
NSString *const PropertyListPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress"; NSString *const PropertyListPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress";
@implementation PropertyListPreferences @implementation PropertyListPreferences
@ -175,15 +176,15 @@ NSString *const PropertyListPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddr
#pragma mark CallKit #pragma mark CallKit
- (BOOL)isCallKitEnabled - (BOOL)isCallKitPrivacyEnabled
{ {
NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyCallKitEnabled]; NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyCallKitPrivacyEnabled];
return preference ? [preference boolValue] : YES; return preference ? [preference boolValue] : YES;
} }
- (void)setIsCallKitEnabled:(BOOL)flag - (void)setIsCallKitPrivacyEnabled:(BOOL)flag
{ {
[self setValueForKey:PropertyListPreferencesKeyCallKitEnabled toValue:@(flag)]; [self setValueForKey:PropertyListPreferencesKeyCallKitPrivacyEnabled toValue:@(flag)];
} }
#pragma mark direct call connectivity (non-TURN) #pragma mark direct call connectivity (non-TURN)

@ -18,12 +18,12 @@ NS_ASSUME_NONNULL_BEGIN
@interface AdvancedSettingsTableViewController () @interface AdvancedSettingsTableViewController ()
@property (nonatomic) UITableViewCell *enableCallKitCell; @property (nonatomic) UITableViewCell *enableCallKitPrivacyCell;
@property (nonatomic) UITableViewCell *enableLogCell; @property (nonatomic) UITableViewCell *enableLogCell;
@property (nonatomic) UITableViewCell *submitLogCell; @property (nonatomic) UITableViewCell *submitLogCell;
@property (nonatomic) UITableViewCell *registerPushCell; @property (nonatomic) UITableViewCell *registerPushCell;
@property (nonatomic) UISwitch *enableCallKitSwitch; @property (nonatomic) UISwitch *enableCallKitPrivacySwitch;
@property (nonatomic) UISwitch *enableLogSwitch; @property (nonatomic) UISwitch *enableLogSwitch;
@property (nonatomic, readonly) BOOL supportsCallKit; @property (nonatomic, readonly) BOOL supportsCallKit;
@ -58,14 +58,14 @@ typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
[self useOWSBackButton]; [self useOWSBackButton];
// CallKit opt-out // CallKit opt-out
self.enableCallKitCell = [UITableViewCell new]; self.enableCallKitPrivacyCell = [UITableViewCell new];
self.enableCallKitCell.textLabel.text = NSLocalizedString(@"SETTINGS_ADVANCED_CALLKIT_TITLE", @"Short table cell label"); self.enableCallKitPrivacyCell.textLabel.text = NSLocalizedString(@"SETTINGS_ADVANCED_CALLKIT_PRIVACY_TITLE", @"Label for 'CallKit privacy' preference");
self.enableCallKitSwitch = [UISwitch new]; self.enableCallKitPrivacySwitch = [UISwitch new];
[self.enableCallKitSwitch setOn:[[Environment getCurrent].preferences isCallKitEnabled]]; [self.enableCallKitPrivacySwitch setOn:![[Environment getCurrent].preferences isCallKitPrivacyEnabled]];
[self.enableCallKitSwitch addTarget:self [self.enableCallKitPrivacySwitch addTarget:self
action:@selector(didToggleEnableCallKitSwitch:) action:@selector(didToggleEnableCallKitPrivacySwitch:)
forControlEvents:UIControlEventTouchUpInside]; forControlEvents:UIControlEventTouchUpInside];
self.enableCallKitCell.accessoryView = self.enableCallKitSwitch; self.enableCallKitPrivacyCell.accessoryView = self.enableCallKitPrivacySwitch;
// Enable Log // Enable Log
self.enableLogCell = [[UITableViewCell alloc] init]; self.enableLogCell = [[UITableViewCell alloc] init];
@ -99,7 +99,7 @@ typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
case AdvancedSettingsTableViewControllerSectionLogging: case AdvancedSettingsTableViewControllerSectionLogging:
return self.enableLogSwitch.isOn ? 2 : 1; return self.enableLogSwitch.isOn ? 2 : 1;
case AdvancedSettingsTableViewControllerSectionCalling: case AdvancedSettingsTableViewControllerSectionCalling:
return self.supportsCallKit ? 2 : 1; return self.supportsCallKit ? 1 : 0;
case AdvancedSettingsTableViewControllerSectionPushNotifications: case AdvancedSettingsTableViewControllerSectionPushNotifications:
return 1; return 1;
default: default:
@ -128,7 +128,7 @@ typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
switch (settingsSection) { switch (settingsSection) {
case AdvancedSettingsTableViewControllerSectionCalling: case AdvancedSettingsTableViewControllerSectionCalling:
if ([self supportsCallKit]) { if ([self supportsCallKit]) {
return NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer."); return NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION", @"Explanation of the 'CallKit Privacy` preference.");
} }
default: default:
return nil; return nil;
@ -151,7 +151,7 @@ typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
switch (indexPath.row) { switch (indexPath.row) {
case 0: case 0:
OWSAssert(self.supportsCallKit); OWSAssert(self.supportsCallKit);
return self.enableCallKitCell; return self.enableCallKitPrivacyCell;
default: default:
// Unknown cell // Unknown cell
OWSAssert(NO); OWSAssert(NO);
@ -205,9 +205,9 @@ typedef NS_ENUM(NSInteger, AdvancedSettingsTableViewControllerSection) {
[self.tableView reloadData]; [self.tableView reloadData];
} }
- (void)didToggleEnableCallKitSwitch:(UISwitch *)sender { - (void)didToggleEnableCallKitPrivacySwitch:(UISwitch *)sender {
DDLogInfo(@"%@ user toggled call kit preference: %@", self.tag, (sender.isOn ? @"ON" : @"OFF")); DDLogInfo(@"%@ user toggled call kit privacy preference: %@", self.tag, (sender.isOn ? @"ON" : @"OFF"));
[[Environment getCurrent].preferences setIsCallKitEnabled:sender.isOn]; [[Environment getCurrent].preferences setIsCallKitPrivacyEnabled:!sender.isOn];
[[Environment getCurrent].callService createCallUIAdapter]; [[Environment getCurrent].callService createCallUIAdapter];
} }

@ -85,6 +85,9 @@
/* notification action */ /* notification action */
"CALLBACK_BUTTON_TITLE" = "Call back"; "CALLBACK_BUTTON_TITLE" = "Call back";
/* The generic name used for calls if CallKit privacy is enabled */
"CALLKIT_ANONYMOUS_CONTACT_NAME" = "Signal User";
/* Activity Sheet label */ /* Activity Sheet label */
"COMPARE_SAFETY_NUMBER_ACTION" = "Compare with Clipboard"; "COMPARE_SAFETY_NUMBER_ACTION" = "Compare with Clipboard";
@ -757,8 +760,8 @@
/* Navbar title */ /* Navbar title */
"SETTINGS_ABOUT" = "About"; "SETTINGS_ABOUT" = "About";
/* Short table cell label */ /* Label for 'CallKit privacy' preference */
"SETTINGS_ADVANCED_CALLKIT_TITLE" = "Use CallKit"; "SETTINGS_ADVANCED_CALLKIT_PRIVACY_TITLE" = "Show Names & Numbers in CallKit";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_ADVANCED_DEBUGLOG" = "Enable Debug Log"; "SETTINGS_ADVANCED_DEBUGLOG" = "Enable Debug Log";
@ -832,8 +835,8 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"SETTINGS_SCREEN_SECURITY_DETAIL" = "Prevents Signal previews from appearing in the app switcher."; "SETTINGS_SCREEN_SECURITY_DETAIL" = "Prevents Signal previews from appearing in the app switcher.";
/* Settings table section footer. */ /* Explanation of the 'CallKit Privacy` preference. */
"SETTINGS_SECTION_CALL_KIT_DESCRIPTION" = "CallKit allows you to answer calls directly from your lockscreen. Be aware that when using CallKit, Apple syncs some call metadata to your iCloud account."; "SETTINGS_SECTION_CALL_KIT_PRIVACY_DESCRIPTION" = "CallKit allows you to answer calls directly from your lockscreen. If you show the names and phone numbers of incoming callers in CallKit, this information will appear in your phone's call history and will be synced to your iCloud account.";
/* settings topic header for table section */ /* settings topic header for table section */
"SETTINGS_SECTION_TITLE_CALLING" = "Calling"; "SETTINGS_SECTION_TITLE_CALLING" = "Calling";

Loading…
Cancel
Save