Place Signal/Redphone calls from system contacts
// FREEBIE
This commit is contained in:
parent
724a1c9b20
commit
bbfd9ba74d
|
@ -28,6 +28,8 @@
|
|||
451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */; };
|
||||
451DE9FE1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */; };
|
||||
4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4520D8D41D417D8E00123472 /* Photos.framework */; };
|
||||
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
||||
452C46901E427E200087B011 /* OutboundCallInitiator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452C468E1E427E200087B011 /* OutboundCallInitiator.swift */; };
|
||||
452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */; };
|
||||
452E3C8E1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */; };
|
||||
452E3C8F1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */; };
|
||||
|
@ -62,6 +64,7 @@
|
|||
45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
|
||||
45843D201D2236B30013E85A /* OWSContactsSearcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */; };
|
||||
45843D221D223BA10013E85A /* OWSContactsSearcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */; };
|
||||
45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
45855F371D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; };
|
||||
45855F381D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; };
|
||||
458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458967101DC117CC00E9DD21 /* AccountManagerTest.swift */; };
|
||||
|
@ -620,6 +623,7 @@
|
|||
451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SyncPushTokensJob.swift; path = Models/SyncPushTokensJob.swift; sourceTree = "<group>"; };
|
||||
4520D8D41D417D8E00123472 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; };
|
||||
4526BD481CA61C8D00166BC8 /* OWSMessageEditing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageEditing.h; sourceTree = "<group>"; };
|
||||
452C468E1E427E200087B011 /* OutboundCallInitiator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutboundCallInitiator.swift; sourceTree = "<group>"; };
|
||||
452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MesssagesBubblesSizeCalculatorTest.swift; path = Models/MesssagesBubblesSizeCalculatorTest.swift; sourceTree = "<group>"; };
|
||||
452E3C8C1D935C77002A45B0 /* OWSConversationSettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsTableViewController.h; sourceTree = "<group>"; };
|
||||
452E3C8D1D935C77002A45B0 /* OWSConversationSettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = OWSConversationSettingsTableViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
|
@ -656,6 +660,7 @@
|
|||
45843D1D1D2236B30013E85A /* OWSContactsSearcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSearcher.h; sourceTree = "<group>"; };
|
||||
45843D1E1D2236B30013E85A /* OWSContactsSearcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcher.m; sourceTree = "<group>"; };
|
||||
45843D211D223BA10013E85A /* OWSContactsSearcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSearcherTest.m; sourceTree = "<group>"; };
|
||||
45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
|
||||
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactAvatarBuilder.h; sourceTree = "<group>"; };
|
||||
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactAvatarBuilder.m; sourceTree = "<group>"; };
|
||||
4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalTests-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
|
@ -1242,6 +1247,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */,
|
||||
4509E79A1DD653700025A59F /* WebRTC.framework in Frameworks */,
|
||||
456C38961DC7B882007536A7 /* PromiseKit.framework in Frameworks */,
|
||||
4520D8D51D417D8E00123472 /* Photos.framework in Frameworks */,
|
||||
|
@ -1555,6 +1561,7 @@
|
|||
4574A5D51DD6704700C6B692 /* CallService.swift */,
|
||||
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */,
|
||||
45F170BA1E2FC5D3003FC1F2 /* CallAudioService.swift */,
|
||||
452C468E1E427E200087B011 /* OutboundCallInitiator.swift */,
|
||||
);
|
||||
path = call;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2430,6 +2437,7 @@
|
|||
D221A08C169C9E5E00537ABF /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
45847E861E4283C30080EAB3 /* Intents.framework */,
|
||||
45BD60811DE9547E00A8F436 /* Contacts.framework */,
|
||||
4509E7991DD653700025A59F /* WebRTC.framework */,
|
||||
451DE9F11DC1585F00810E42 /* PromiseKit.framework */,
|
||||
|
@ -3199,6 +3207,7 @@
|
|||
B66B9F721AEA6D1100E2E609 /* NotificationSettingsViewController.m in Sources */,
|
||||
76EB059018170B33006006FC /* IgnoredPacketFailure.m in Sources */,
|
||||
76EB05D418170B33006006FC /* ZrtpManager.m in Sources */,
|
||||
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
||||
76EB058E18170B33006006FC /* HostNameEndPoint.m in Sources */,
|
||||
E19167A418A9687800B7A468 /* DH3KKeyAgreementParticipant.m in Sources */,
|
||||
E16E5BF018AAC40200B7C403 /* EvpKeyAgreement.m in Sources */,
|
||||
|
@ -3309,6 +3318,7 @@
|
|||
B660F7131C29988E00687D6E /* SoundPlayer.m in Sources */,
|
||||
B660F7141C29988E00687D6E /* RecentCall.m in Sources */,
|
||||
B660F7151C29988E00687D6E /* RecentCallManager.m in Sources */,
|
||||
452C46901E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
|
||||
451DE9F81DC18C9500810E42 /* AccountManager.swift in Sources */,
|
||||
B660F7161C29988E00687D6E /* GroupContactsResult.m in Sources */,
|
||||
B660F7171C29988E00687D6E /* OWSContactsManager.m in Sources */,
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
|
||||
@import WebRTC;
|
||||
@import Intents;
|
||||
|
||||
NSString *const AppDelegateStoryboardMain = @"Main";
|
||||
NSString *const AppDelegateStoryboardRegistration = @"Registration";
|
||||
|
@ -333,10 +334,52 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
|
||||
{
|
||||
if ([userActivity.activityType isEqualToString:@"INStartVideoCallIntent"]) {
|
||||
DDLogInfo(@"%@ got start video call intent", self.tag);
|
||||
[[Environment getCurrent].callService handleCallKitStartVideo];
|
||||
} else if ([userActivity.activityType isEqualToString:@"INStartAudioCallIntent"]) {
|
||||
|
||||
// TODO guard if less than iOS10.
|
||||
|
||||
DDLogInfo(@"%@ got start audio call intent", self.tag);
|
||||
|
||||
// hoooooooooooly moly.
|
||||
INInteraction *interaction = [userActivity interaction];
|
||||
INIntent *intent = interaction.intent;
|
||||
|
||||
if (![intent isKindOfClass:[INStartAudioCallIntent class]]) {
|
||||
DDLogError(@"%@ unexpected class for start call audio: %@", self.tag, intent);
|
||||
return NO;
|
||||
}
|
||||
INStartAudioCallIntent *startCallIntent = (INStartAudioCallIntent *)intent;
|
||||
NSString *_Nullable handle = startCallIntent.contacts.firstObject.personHandle.value;
|
||||
if (!handle) {
|
||||
DDLogWarn(@"%@ unable to find handle in startCallIntent: %@", self.tag, startCallIntent);
|
||||
return NO;
|
||||
}
|
||||
|
||||
CallUIAdapter *callUIAdapter = [Environment getCurrent].callService.callUIAdapter;
|
||||
OWSAssert(callUIAdapter);
|
||||
|
||||
ContactsUpdater *contactsUpdater = [Environment getCurrent].contactsUpdater;
|
||||
OWSAssert(contactsUpdater);
|
||||
|
||||
OWSContactsManager *contactsManager = [Environment getCurrent].contactsManager;
|
||||
OWSAssert(contactsManager);
|
||||
|
||||
PhoneManager *phoneManager = [Environment getCurrent].phoneManager;
|
||||
OWSAssert(phoneManager);
|
||||
|
||||
OutboundCallInitiator *outboundCallInitiator =
|
||||
[[OutboundCallInitiator alloc] initWithRedphoneManager:phoneManager
|
||||
callUIAdapter:callUIAdapter
|
||||
contactsManager:contactsManager
|
||||
contactsUpdater:contactsUpdater];
|
||||
return [outboundCallInitiator initiateCallWithHandle:handle];
|
||||
} else {
|
||||
DDLogWarn(
|
||||
@"%@ called %s with userActivity: %@, but not yet supported.", self.tag, __PRETTY_FUNCTION__, userActivity);
|
||||
DDLogWarn(@"%@ called %s with userActivity: %@, but not yet supported.",
|
||||
self.tag,
|
||||
__PRETTY_FUNCTION__,
|
||||
userActivity.activityType);
|
||||
}
|
||||
|
||||
// TODO Something like...
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#import "OWSError.h"
|
||||
#import "OWSLogger.h"
|
||||
#import "OWSWebRTCDataProtos.pb.h"
|
||||
#import "PhoneNumber.h"
|
||||
#import "PhoneManager.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "PureLayout.h"
|
||||
#import "PushManager.h"
|
||||
|
@ -28,6 +28,7 @@
|
|||
#import "UIView+OWS.h"
|
||||
#import <JSQSystemSoundPlayer.h>
|
||||
#import <SignalServiceKit/Contact.h>
|
||||
#import <SignalServiceKit/ContactsUpdater.h>
|
||||
#import <SignalServiceKit/Cryptography.h>
|
||||
#import <SignalServiceKit/NSData+Base64.h>
|
||||
#import <SignalServiceKit/NSDate+millisecondTimeStamp.h>
|
||||
|
@ -45,6 +46,7 @@
|
|||
#import <SignalServiceKit/OWSOutgoingCallMessage.h>
|
||||
#import <SignalServiceKit/OWSSignalService.h>
|
||||
#import <SignalServiceKit/OWSTurnServerInfoRequest.h>
|
||||
#import <SignalServiceKit/PhoneNumber.h>
|
||||
#import <SignalServiceKit/SignalRecipient.h>
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSCall.h>
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
* Creates an outbound call via either Redphone or WebRTC depending on participant preferences.
|
||||
*/
|
||||
@objc class OutboundCallInitiator: NSObject {
|
||||
let TAG = "[OutboundCallInitiator]"
|
||||
|
||||
let callUIAdapter: CallUIAdapter
|
||||
let redphoneManager: PhoneManager
|
||||
let contactsManager: OWSContactsManager
|
||||
let contactsUpdater: ContactsUpdater
|
||||
|
||||
init(redphoneManager: PhoneManager, callUIAdapter: CallUIAdapter, contactsManager: OWSContactsManager, contactsUpdater: ContactsUpdater) {
|
||||
self.redphoneManager = redphoneManager
|
||||
self.callUIAdapter = callUIAdapter
|
||||
|
||||
self.contactsManager = contactsManager
|
||||
self.contactsUpdater = contactsUpdater
|
||||
}
|
||||
|
||||
/**
|
||||
* |handle| is a user formatted phone number, e.g. from a system contacts entry
|
||||
*/
|
||||
public func initiateCall(handle: String) -> Bool {
|
||||
Logger.info("\(TAG) in \(#function) with handle: \(handle)")
|
||||
guard let recipientId = PhoneNumber(fromUserSpecifiedText: handle).toE164() else {
|
||||
Logger.warn("\(TAG) unable to parse signalId from phone number: \(handle)")
|
||||
return false
|
||||
}
|
||||
|
||||
return initiateCall(recipientId: recipientId)
|
||||
}
|
||||
|
||||
/**
|
||||
* |recipientId| is a e164 formatted phone number.
|
||||
*/
|
||||
public func initiateCall(recipientId: String) -> Bool {
|
||||
|
||||
let localWantsWebRTC = Environment.preferences().isWebRTCEnabled()
|
||||
if !localWantsWebRTC {
|
||||
return self.initiateRedphoneCall(recipientId: recipientId)
|
||||
}
|
||||
|
||||
// Since users can toggle this setting, which is only communicated during contact sync, it's easy to imagine the
|
||||
// preference getting stale. Especially as users are toggling the feature to test calls. So here, we opt for a
|
||||
// blocking network request *every* time we place a call to make sure we've got up to date preferences.
|
||||
//
|
||||
// e.g. The following would suffice if we weren't worried about stale preferences.
|
||||
// SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:self.thread.contactIdentifier];
|
||||
self.contactsUpdater.lookupIdentifier(recipientId,
|
||||
success: { recipient in
|
||||
let remoteWantsWebRTC = recipient.supportsWebRTC
|
||||
Logger.debug("\(self.TAG) localWantsWebRTC: \(localWantsWebRTC), remoteWantsWebRTC: \(remoteWantsWebRTC)")
|
||||
|
||||
if localWantsWebRTC, remoteWantsWebRTC {
|
||||
_ = self.initiateWebRTCAudioCall(recipientId: recipientId)
|
||||
} else {
|
||||
_ = self.initiateRedphoneCall(recipientId: recipientId)
|
||||
}
|
||||
},
|
||||
failure: { error in
|
||||
Logger.warn("\(self.TAG) looking up recipientId: \(recipientId) failed with error \(error)")
|
||||
// TODO fail with alert. e.g. when someone tries to call a non signal user from their contacts we should inform them.
|
||||
})
|
||||
|
||||
// Since we've already dispatched async to make sure we have fresh webrtc preference data
|
||||
// we don't have a meaningful value to return here - but we're not using it anway. =/
|
||||
return true
|
||||
}
|
||||
|
||||
private func initiateRedphoneCall(recipientId: String) -> Bool {
|
||||
Logger.info("\(TAG) Placing redphone call to: \(recipientId)")
|
||||
|
||||
let number = PhoneNumber.tryParsePhoneNumber(fromUserSpecifiedText: recipientId)
|
||||
let contact = self.contactsManager.latestContact(for: number)
|
||||
assert(number != nil)
|
||||
assert(contact != nil)
|
||||
|
||||
redphoneManager.initiateOutgoingCall(to: contact, atRemoteNumber: number)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func initiateWebRTCAudioCall(recipientId: String) -> Bool {
|
||||
callUIAdapter.callBack(recipientId: recipientId)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Logging.h"
|
||||
#import "PacketHandler.h"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Environment.h"
|
||||
#import "Constraints.h"
|
||||
#import "DH3KKeyAgreementProtocol.h"
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
//
|
||||
// MessagesViewController.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Dylan Bourgeois on 28/10/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
|
Loading…
Reference in New Issue