Merge branch 'charlesmchen/removeRedPhoneCalls'

This commit is contained in:
Matthew Chen 2017-03-22 17:03:34 -04:00
commit b0b4771d68
6 changed files with 5 additions and 356 deletions

View file

@ -20,7 +20,6 @@
348A08441E6A1D2C0057E290 /* OWSMessagesToolbarContentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 348A08431E6A1D2C0057E290 /* OWSMessagesToolbarContentView.xib */; };
348A08511E6C73490057E290 /* AttachmentApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348A08501E6C73490057E290 /* AttachmentApprovalViewController.swift */; };
348A08531E6C75590057E290 /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348A08521E6C75590057E290 /* SignalAttachment.swift */; };
348F3A4F1E4A533900750D44 /* CallInterstitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */; };
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
450573FE1E78A06D00615BB4 /* OWS103EnableVideoCalling.m in Sources */ = {isa = PBXBuildFile; fileRef = 450573FD1E78A06D00615BB4 /* OWS103EnableVideoCalling.m */; };
4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */; };
@ -645,7 +644,6 @@
348A08431E6A1D2C0057E290 /* OWSMessagesToolbarContentView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OWSMessagesToolbarContentView.xib; sourceTree = "<group>"; };
348A08501E6C73490057E290 /* AttachmentApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttachmentApprovalViewController.swift; sourceTree = "<group>"; };
348A08521E6C75590057E290 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalAttachment.swift; sourceTree = "<group>"; };
348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallInterstitialViewController.swift; sourceTree = "<group>"; };
34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = "<group>"; };
34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = views/OWSAnyTouchGestureRecognizer.m; sourceTree = "<group>"; };
450573FC1E78A06D00615BB4 /* OWS103EnableVideoCalling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWS103EnableVideoCalling.h; path = Migrations/OWS103EnableVideoCalling.h; sourceTree = "<group>"; };
@ -2696,7 +2694,6 @@
isa = PBXGroup;
children = (
348A08501E6C73490057E290 /* AttachmentApprovalViewController.swift */,
348F3A4E1E4A533900750D44 /* CallInterstitialViewController.swift */,
4509E79B1DD6545B0025A59F /* CallViewController.swift */,
FC31962B1A06A2190094C78E /* FingerprintViewController.h */,
FC31962C1A06A2190094C78E /* FingerprintViewController.m */,
@ -3191,7 +3188,6 @@
E197B61818BBEC1A00F073E5 /* RemoteIOAudio.m in Sources */,
B67ADDC41989FF8700E1A773 /* RPServerRequestsManager.m in Sources */,
348A08511E6C73490057E290 /* AttachmentApprovalViewController.swift in Sources */,
348F3A4F1E4A533900750D44 /* CallInterstitialViewController.swift in Sources */,
EF764C351DB67CC5000D9A87 /* UIViewController+CameraPermissions.m in Sources */,
453201251E71100C00F20761 /* DisplayableTextFilter.swift in Sources */,
76EB059418170B33006006FC /* HttpManager.m in Sources */,

View file

@ -253,18 +253,6 @@ protocol CallServiceObserver: class {
return "CallServiceActiveCallNotification"
}
class func presentCallInterstitialNotificationName() -> String {
return "CallServicePresentCallInterstitialNotification"
}
class func dismissCallInterstitialNotificationName() -> String {
return "CallServiceDismissCallInterstitialNotification"
}
class func callWasCancelledByInterstitialNotificationName() -> String {
return "CallServiceCallWasCancelledByInterstitialNotification"
}
// MARK: - Service Actions
/**
@ -396,7 +384,7 @@ protocol CallServiceObserver: class {
// Insert missed call record
if let callRecord = call.callRecord {
if (callRecord.callType == RPRecentCallTypeIncoming) {
if callRecord.callType == RPRecentCallTypeIncoming {
callRecord.updateCallType(RPRecentCallTypeMissed)
}
} else {

View file

@ -10,41 +10,14 @@ import Foundation
@objc class OutboundCallInitiator: NSObject {
let TAG = "[OutboundCallInitiator]"
let redphoneManager: PhoneManager
let contactsManager: OWSContactsManager
let contactsUpdater: ContactsUpdater
var cancelledCallTokens: [String] = []
init(redphoneManager: PhoneManager, contactsManager: OWSContactsManager, contactsUpdater: ContactsUpdater) {
self.redphoneManager = redphoneManager
init(contactsManager: OWSContactsManager, contactsUpdater: ContactsUpdater) {
self.contactsManager = contactsManager
self.contactsUpdater = contactsUpdater
super.init()
NotificationCenter.default.addObserver(self,
selector:#selector(callWasCancelledByInterstitial),
name:Notification.Name(rawValue: CallService.callWasCancelledByInterstitialNotificationName()),
object:nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func callWasCancelledByInterstitial(notification: NSNotification) {
AssertIsOnMainThread()
let callToken = notification.object as! String
cancelCallToken(callToken:callToken)
}
func cancelCallToken(callToken: String) {
AssertIsOnMainThread()
cancelledCallTokens.append(callToken)
}
/**
@ -65,76 +38,7 @@ import Foundation
* |recipientId| is a e164 formatted phone number.
*/
public func initiateCall(recipientId: String) -> Bool {
// A temporary unique id used to identify this call during the
let callToken = NSUUID().uuidString
presentCallInterstitial(callToken:callToken)
// 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
guard !self.cancelledCallTokens.contains(callToken) else {
Logger.info("\(self.TAG) OutboundCallInitiator aborting due to cancelled call.")
return
}
guard !Environment.getCurrent().phoneManager.hasOngoingRedphoneCall() else {
Logger.error("\(self.TAG) OutboundCallInitiator aborting due to ongoing RedPhone call.")
return
}
guard Environment.getCurrent().callService.call == nil else {
Logger.error("\(self.TAG) OutboundCallInitiator aborting due to ongoing WebRTC call.")
return
}
let remoteWantsWebRTC = recipient.supportsWebRTC
Logger.debug("\(self.TAG) remoteWantsWebRTC: \(remoteWantsWebRTC)")
if 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)")
self.cancelCallToken(callToken:callToken)
self.dismissCallInterstitial(callToken:callToken)
let alertTitle = NSLocalizedString("UNABLE_TO_PLACE_CALL", comment:"Alert Title")
let alertController = UIAlertController(title: alertTitle, message: error.localizedDescription, preferredStyle: .alert)
let dismissAction = UIAlertAction(title: NSLocalizedString("DISMISS_BUTTON_TEXT", comment: "Generic short text for button to dismiss a dialog"), style: .default)
alertController.addAction(dismissAction)
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
})
// 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)
assert(number != nil)
let contact: Contact? = self.contactsManager.latestContact(for: number)
redphoneManager.initiateOutgoingCall(to: contact, atRemoteNumber: number)
return true
}
private func initiateWebRTCAudioCall(recipientId: String) -> Bool {
// Rather than an init-assigned dependency property, we access `callUIAdapter` via Environment
// Rather than an init-assigned dependency property, we access `callUIAdapter` via Environment
// because it can change after app launch due to user settings
guard let callUIAdapter = Environment.getCurrent().callUIAdapter else {
assertionFailure()
@ -145,18 +49,4 @@ import Foundation
callUIAdapter.startAndShowOutgoingCall(recipientId: recipientId)
return true
}
private func presentCallInterstitial(callToken: String) {
AssertIsOnMainThread()
let notificationName = CallService.presentCallInterstitialNotificationName()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: notificationName), object: callToken)
}
private func dismissCallInterstitial(callToken: String) {
AssertIsOnMainThread()
let notificationName = CallService.dismissCallInterstitialNotificationName()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: notificationName), object: callToken)
}
}

View file

@ -184,8 +184,7 @@ static Environment *environment = nil;
OWSAssert(self.phoneManager);
OWSAssert(self.contactsManager);
OWSAssert(self.contactsUpdater);
_outboundCallInitiator = [[OutboundCallInitiator alloc] initWithRedphoneManager:self.phoneManager
contactsManager:self.contactsManager
_outboundCallInitiator = [[OutboundCallInitiator alloc] initWithContactsManager:self.contactsManager
contactsUpdater:self.contactsUpdater];
}
}

View file

@ -1,171 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc(OWSCallInterstitialViewController)
class CallInterstitialViewController: UIViewController {
let TAG = "[CallInterstitialViewController]"
var wasCallCancelled = false
let callToken: String!
// MARK: Views
var hasConstraints = false
var blurView: UIVisualEffectView!
var contentView: UIView!
// MARK: Initializers
@available(*, unavailable, message:"init is unavailable, use initWithCallToken")
required init?(coder aDecoder: NSCoder) {
assert(false)
self.callToken = ""
super.init(coder: aDecoder)
}
required init(callToken: String) {
self.callToken = callToken
super.init(nibName: nil, bundle: nil)
observeNotifications()
}
func observeNotifications() {
NotificationCenter.default.addObserver(self,
selector:#selector(willResignActive),
name:NSNotification.Name.UIApplicationWillResignActive,
object:nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func willResignActive() {
cancelCall()
}
// MARK: View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
createViews()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
blurView.layer.opacity = 0
contentView.layer.opacity = 0
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 0.3,
delay: 1.0,
options: UIViewAnimationOptions.curveLinear,
animations: {
self.blurView.layer.opacity = 1
self.contentView.layer.opacity = 1
},
completion: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
blurView.layer.removeAllAnimations()
contentView.layer.removeAllAnimations()
}
// MARK: - Create Views
func createViews() {
assert(self.view != nil)
// Dark blurred background.
let blurEffect = UIBlurEffect(style: .dark)
blurView = UIVisualEffectView(effect: blurEffect)
blurView.isUserInteractionEnabled = false
self.view.addSubview(blurView)
contentView = UIView()
self.view.addSubview(contentView)
let dialingLabel = UILabel()
dialingLabel.text = NSLocalizedString("CALL_INTERSTITIAL_CALLING_LABEL", comment: "Title for call interstitial view")
dialingLabel.textColor = UIColor.white
dialingLabel.font = UIFont.ows_lightFont(withSize:ScaleFromIPhone5To7Plus(32, 40))
dialingLabel.textAlignment = .center
contentView.addSubview(dialingLabel)
let cancelCallButton = UIButton()
cancelCallButton.setTitle(NSLocalizedString("TXT_CANCEL_TITLE", comment: "nil"),
for:.normal)
cancelCallButton.setTitleColor(UIColor.white, for:.normal)
cancelCallButton.titleLabel?.font = UIFont.ows_lightFont(withSize:ScaleFromIPhone5To7Plus(26, 32))
let buttonInset = ScaleFromIPhone5To7Plus(7, 9)
cancelCallButton.titleEdgeInsets = UIEdgeInsets(top: buttonInset,
left: buttonInset,
bottom: buttonInset,
right: buttonInset)
cancelCallButton.addTarget(self, action:#selector(cancelCallButtonPressed), for:.touchUpInside)
contentView.addSubview(cancelCallButton)
dialingLabel.autoPinWidthToSuperview()
dialingLabel.autoVCenterInSuperview()
cancelCallButton.autoSetDimension(.height, toSize:ScaleFromIPhone5To7Plus(50, 60))
cancelCallButton.autoPinWidthToSuperview()
cancelCallButton.autoPinEdge(toSuperviewEdge:.bottom, withInset:ScaleFromIPhone5To7Plus(23, 41))
}
// MARK: - Layout
override func updateViewConstraints() {
if !hasConstraints {
// We only want to create our constraints once.
//
// Note that constraints are also created elsewhere.
// This only creates the constraints for the top-level contents of the view.
hasConstraints = true
// Force creation of the view.
let view = self.view
assert(view != nil)
// Dark blurred background.
blurView.autoPinEdgesToSuperviewEdges()
contentView.autoPinEdgesToSuperviewEdges()
}
super.updateViewConstraints()
}
// MARK: - Methods
func cancelCall() {
guard !wasCallCancelled else {
return
}
wasCallCancelled = true
assert(callToken != nil)
let notificationName = CallService.callWasCancelledByInterstitialNotificationName()
NotificationCenter.default.post(name: NSNotification.Name(rawValue: notificationName), object: callToken)
self.dismiss(animated: false)
}
// MARK: - Events
func cancelCallButtonPressed(sender button: UIButton) {
cancelCall()
}
}

View file

@ -137,14 +137,6 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
selector:@selector(handleActiveCallNotification:)
name:[CallService callServiceActiveCallNotificationName]
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handlePresentCallInterstitialNotification:)
name:[CallService presentCallInterstitialNotificationName]
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleDismissCallInterstitialNotification:)
name:[CallService dismissCallInterstitialNotificationName]
object:nil];
[self updateBarButtonItems];
}
@ -203,50 +195,6 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
}
}
- (void)handlePresentCallInterstitialNotification:(NSNotification *)notification
{
AssertIsOnMainThread();
NSString *callToken = notification.object;
OWSAssert(callToken != nil);
OWSCallInterstitialViewController *viewController = [[OWSCallInterstitialViewController alloc] initWithCallToken:callToken];
void(^presentInterstitial)() = ^{
viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:viewController
animated:NO
completion:nil];
};
// Dismiss any other modals so we can present call modal.
if (self.presentedViewController) {
[self dismissViewControllerAnimated:YES completion:presentInterstitial];
} else {
presentInterstitial();
}
}
- (void)handleDismissCallInterstitialNotification:(NSNotification *)notification
{
AssertIsOnMainThread();
NSString *callToken = notification.object;
OWSAssert(callToken != nil);
if (!self.presentedViewController ||
![self.presentedViewController isKindOfClass:[OWSCallInterstitialViewController class]]) {
return;
}
OWSCallInterstitialViewController *viewController = (OWSCallInterstitialViewController *)self.presentedViewController;
if (![viewController.callToken isEqualToString:callToken]) {
return;
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleActiveCallNotification:(NSNotification *)notification
{
AssertIsOnMainThread();
@ -262,8 +210,7 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS
// Dismiss any other modals so we can present call modal.
if (self.presentedViewController) {
BOOL shouldAnimate = ![self.presentedViewController isKindOfClass:[OWSCallInterstitialViewController class]];
[self dismissViewControllerAnimated:shouldAnimate
[self dismissViewControllerAnimated:YES
completion:^{
[self performSegueWithIdentifier:SignalsViewControllerSegueShowIncomingCall sender:call];
}];