Reject incoming calls from an unseen changed identity
// FREEBIE
This commit is contained in:
parent
6b4a5398ef
commit
130aa132a0
2
Podfile
2
Podfile
|
@ -5,7 +5,7 @@ target 'Signal' do
|
|||
pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git'
|
||||
pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git'
|
||||
#pod 'AxolotlKit', path: '../SignalProtocolKit'
|
||||
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git'
|
||||
pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git', branch: 'mkirk/reject-unseen-id-calls'
|
||||
#pod 'SignalServiceKit', path: '../SignalServiceKit'
|
||||
pod 'OpenSSL'
|
||||
pod 'JSQMessagesViewController', git: 'https://github.com/WhisperSystems/JSQMessagesViewController.git', branch: 'mkirk/position-edit-menu'
|
||||
|
|
|
@ -114,7 +114,7 @@ DEPENDENCIES:
|
|||
- OpenSSL
|
||||
- PureLayout
|
||||
- Reachability
|
||||
- SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`)
|
||||
- SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`, branch `mkirk/reject-unseen-id-calls`)
|
||||
- SocketRocket (from `https://github.com/facebook/SocketRocket.git`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
|
@ -124,6 +124,7 @@ EXTERNAL SOURCES:
|
|||
:branch: mkirk/position-edit-menu
|
||||
:git: https://github.com/WhisperSystems/JSQMessagesViewController.git
|
||||
SignalServiceKit:
|
||||
:branch: mkirk/reject-unseen-id-calls
|
||||
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
||||
SocketRocket:
|
||||
:git: https://github.com/facebook/SocketRocket.git
|
||||
|
@ -136,7 +137,7 @@ CHECKOUT OPTIONS:
|
|||
:commit: 7054e4b13ee5bcd6d524adb6dc9a726e8c466308
|
||||
:git: https://github.com/WhisperSystems/JSQMessagesViewController.git
|
||||
SignalServiceKit:
|
||||
:commit: 0c46288cf96c6dadc775c2c2d089245d65490e78
|
||||
:commit: e10cc0c1803c598a7518b6c8b28195e20f0eb12e
|
||||
:git: https://github.com/WhisperSystems/SignalServiceKit.git
|
||||
SocketRocket:
|
||||
:commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf
|
||||
|
@ -164,6 +165,6 @@ SPEC CHECKSUMS:
|
|||
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
|
||||
YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266
|
||||
|
||||
PODFILE CHECKSUM: 48e80d7f1e049bbf544a689fdfdf33e8196c640a
|
||||
PODFILE CHECKSUM: 0e50a094f857d1833a01f162c8395b89604b2c35
|
||||
|
||||
COCOAPODS: 1.2.1
|
||||
|
|
|
@ -482,7 +482,7 @@
|
|||
34D8C0231ED3673300188D7C /* DebugUIMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIMessages.h; sourceTree = "<group>"; };
|
||||
34D8C0241ED3673300188D7C /* DebugUIMessages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIMessages.m; sourceTree = "<group>"; };
|
||||
34D8C0251ED3673300188D7C /* DebugUITableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUITableViewController.h; sourceTree = "<group>"; };
|
||||
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUITableViewController.m; sourceTree = "<group>"; };
|
||||
34D8C0261ED3673300188D7C /* DebugUITableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DebugUITableViewController.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
34D8C0291ED3685800188D7C /* DebugUIContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebugUIContacts.h; sourceTree = "<group>"; };
|
||||
34D8C02A1ED3685800188D7C /* DebugUIContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIContacts.m; sourceTree = "<group>"; };
|
||||
34DFCB831E8E04B400053165 /* AddToBlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToBlockListViewController.h; sourceTree = "<group>"; };
|
||||
|
@ -512,7 +512,7 @@
|
|||
4516E3FE1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWS101ExistingUsersBlockOnIdentityChange.m; path = Migrations/OWS101ExistingUsersBlockOnIdentityChange.m; sourceTree = "<group>"; };
|
||||
451764281DE939FD00EDB8B9 /* ContactCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactCell.xib; sourceTree = "<group>"; };
|
||||
451764291DE939FD00EDB8B9 /* ContactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContactCell.swift; sourceTree = "<group>"; };
|
||||
451A13B01E13DED2000A50FD /* CallNotificationsAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallNotificationsAdapter.swift; path = ../UserInterface/Notifications/CallNotificationsAdapter.swift; sourceTree = "<group>"; };
|
||||
451A13B01E13DED2000A50FD /* CallNotificationsAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = CallNotificationsAdapter.swift; path = ../UserInterface/Notifications/CallNotificationsAdapter.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
451DE9F11DC1585F00810E42 /* PromiseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PromiseKit.framework; path = Carthage/Build/iOS/PromiseKit.framework; sourceTree = "<group>"; };
|
||||
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; };
|
||||
|
@ -548,7 +548,7 @@
|
|||
45666F7C1D9C0814008FE134 /* OWSDatabaseMigrationRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSDatabaseMigrationRunner.h; path = Migrations/OWSDatabaseMigrationRunner.h; sourceTree = "<group>"; };
|
||||
45666F7D1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSDatabaseMigrationRunner.m; path = Migrations/OWSDatabaseMigrationRunner.m; sourceTree = "<group>"; };
|
||||
456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClientTest.swift; sourceTree = "<group>"; };
|
||||
4574A5D51DD6704700C6B692 /* CallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallService.swift; sourceTree = "<group>"; };
|
||||
4574A5D51DD6704700C6B692 /* CallService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CallService.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
4579431C1E7C8CE9008ED0C0 /* Pastelog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pastelog.h; sourceTree = "<group>"; };
|
||||
4579431D1E7C8CE9008ED0C0 /* Pastelog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pastelog.m; sourceTree = "<group>"; };
|
||||
45794E851E00620000066731 /* CallUIAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallUIAdapter.swift; path = UserInterface/CallUIAdapter.swift; sourceTree = "<group>"; };
|
||||
|
@ -601,8 +601,8 @@
|
|||
45DF5DF11DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompareSafetyNumbersActivity.swift; sourceTree = "<group>"; };
|
||||
45E282DE1D08E67800ADD4C8 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = translations/gl.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
45E282DF1D08E6CC00ADD4C8 /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = translations/id.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
45E2E91E1E13EE3500457AA0 /* OWSCallNotificationsAdaptee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSCallNotificationsAdaptee.h; path = UserInterface/OWSCallNotificationsAdaptee.h; sourceTree = "<group>"; };
|
||||
45E2E91F1E153B3D00457AA0 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Strings.swift; path = UserInterface/Strings.swift; sourceTree = "<group>"; };
|
||||
45E2E91E1E13EE3500457AA0 /* OWSCallNotificationsAdaptee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = OWSCallNotificationsAdaptee.h; path = UserInterface/OWSCallNotificationsAdaptee.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
45E2E91F1E153B3D00457AA0 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = Strings.swift; path = UserInterface/Strings.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
45E615151E8C590B0018AD52 /* DisplayableTextFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableTextFilter.swift; sourceTree = "<group>"; };
|
||||
45E7A6A61E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableTextFilterTest.swift; sourceTree = "<group>"; };
|
||||
45F170AB1E2F0351003FC1F2 /* CallAudioSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallAudioSession.swift; sourceTree = "<group>"; };
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Created by Michael Kirk on 12/28/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
@ -34,4 +35,9 @@ class CallNotificationsAdapter: NSObject {
|
|||
Logger.debug("\(TAG) in \(#function)")
|
||||
adaptee.presentMissedCall(call, callerName: callerName)
|
||||
}
|
||||
|
||||
func presentRejectedCallWithUnseenIdentityChange(_ call: SignalCall, callerName: String) {
|
||||
Logger.debug("\(TAG) in \(#function)")
|
||||
adaptee.presentRejectedCallWithUnseenIdentityChange(call, callerName: callerName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,17 @@ import UserNotifications
|
|||
@available(iOS 10.0, *)
|
||||
struct AppNotifications {
|
||||
enum Category {
|
||||
case missedCall
|
||||
case missedCall,
|
||||
rejectedCallFromUnseenIdentity
|
||||
|
||||
// Don't forget to update this! We use it to register categories.
|
||||
static let allValues = [ missedCall ]
|
||||
static let allValues = [ missedCall, rejectedCallFromUnseenIdentity ]
|
||||
}
|
||||
|
||||
enum Action {
|
||||
case callBack
|
||||
case callBack,
|
||||
showThread,
|
||||
confirmIdentityAndCallBack
|
||||
}
|
||||
|
||||
static var allCategories: Set<UNNotificationCategory> {
|
||||
|
@ -35,6 +38,12 @@ struct AppNotifications {
|
|||
actions: [ action(.callBack) ],
|
||||
intentIdentifiers: [],
|
||||
options: [])
|
||||
|
||||
case .rejectedCallFromUnseenIdentity:
|
||||
return UNNotificationCategory(identifier: "org.whispersystems.signal.AppNotifications.Category.rejectedCallFromUnseenIdentity",
|
||||
actions: [ action(.confirmIdentityAndCallBack), action(.showThread) ],
|
||||
intentIdentifiers: [],
|
||||
options: [])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +53,14 @@ struct AppNotifications {
|
|||
return UNNotificationAction(identifier: "org.whispersystems.signal.AppNotifications.Action.callBack",
|
||||
title: CallStrings.callBackButtonTitle,
|
||||
options: .authenticationRequired)
|
||||
case .showThread:
|
||||
return UNNotificationAction(identifier: "org.whispersystems.signal.AppNotifications.Action.showThread",
|
||||
title: CallStrings.showThreadButtonTitle,
|
||||
options: .authenticationRequired)
|
||||
case .confirmIdentityAndCallBack:
|
||||
return UNNotificationAction(identifier: "org.whispersystems.signal.AppNotifications.Action.confirmIdentityAndCallBack",
|
||||
title: CallStrings.confirmIdentityAndCallBackButtonTitle,
|
||||
options: .authenticationRequired)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +105,7 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot
|
|||
public func presentIncomingCall(_ call: SignalCall, callerName: String) {
|
||||
Logger.debug("\(TAG) \(#function) is no-op, because it's handled with callkit.")
|
||||
// TODO since CallKit doesn't currently work on the simulator,
|
||||
// we could implement UNNotifications for simulator testing.
|
||||
// we could implement UNNotifications for simulator testing, or if people have opted out of callkit.
|
||||
}
|
||||
|
||||
public func presentMissedCall(_ call: SignalCall, callerName: String) {
|
||||
|
@ -116,4 +133,30 @@ class UserNotificationsAdaptee: NSObject, OWSCallNotificationsAdaptee, UNUserNot
|
|||
|
||||
center.add(request)
|
||||
}
|
||||
|
||||
func presentRejectedCallWithUnseenIdentityChange(_ call: SignalCall, callerName: String) {
|
||||
Logger.debug("\(TAG) \(#function)")
|
||||
|
||||
let content = UNMutableNotificationContent()
|
||||
// TODO group by thread identifier
|
||||
// content.threadIdentifier = threadId
|
||||
|
||||
let notificationBody = { () -> String in
|
||||
switch previewType {
|
||||
case .noNameNoPreview:
|
||||
return CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBody
|
||||
case .nameNoPreview, .namePreview:
|
||||
return (Environment.getCurrent().preferences.isCallKitPrivacyEnabled()
|
||||
? CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName
|
||||
: String(format: CallStrings.rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName, callerName))
|
||||
}}()
|
||||
|
||||
content.body = notificationBody
|
||||
content.sound = UNNotificationSound.default()
|
||||
content.categoryIdentifier = AppNotifications.category(.rejectedCallFromUnseenIdentity).identifier
|
||||
|
||||
let request = UNNotificationRequest.init(identifier: call.localId.uuidString, content: content, trigger: nil)
|
||||
|
||||
center.add(request)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,21 @@ import Foundation
|
|||
* Strings re-used in multiple places should be added here.
|
||||
*/
|
||||
@objc class CallStrings: NSObject {
|
||||
|
||||
static let callStatusFormat = NSLocalizedString("CALL_STATUS_FORMAT", comment: "embeds {{Call Status}} in call screen label. For ongoing calls, {{Call Status}} is a seconds timer like 01:23, otherwise {{Call Status}} is a short text like 'Ringing', 'Busy', or 'Failed Call'")
|
||||
|
||||
// MARK: Notification actions
|
||||
static let callBackButtonTitle = NSLocalizedString("CALLBACK_BUTTON_TITLE", comment: "notification action")
|
||||
static let confirmIdentityAndCallBackButtonTitle = NSLocalizedString("CONFIRM_IDENTITY_AND_CALLBACK_BUTTON_TITLE", comment: "notification action, confirming that it's OK to proceed calling after a caller's Safety Number has changed")
|
||||
static let showThreadButtonTitle = NSLocalizedString("SHOW_THREAD_BUTTON_TITLE", comment: "notification action")
|
||||
|
||||
// MARK: Missed Call Notification
|
||||
static let missedCallNotificationBody = NSLocalizedString("MISSED_CALL", comment: "notification title")
|
||||
static let missedCallNotificationBodyWithCallerName = NSLocalizedString("MSGVIEW_MISSED_CALL_WITH_NAME", comment: "notification title. Embeds {{Caller's Name}}")
|
||||
static let missedCallNotificationBodyWithoutCallerName = NSLocalizedString("MSGVIEW_MISSED_CALL_WITHOUT_NAME", comment: "notification title.")
|
||||
static let callStatusFormat = NSLocalizedString("CALL_STATUS_FORMAT", comment: "embeds {{Call Status}} in call screen label. For ongoing calls, {{Call Status}} is a seconds timer like 01:23, otherwise {{Call Status}} is a short text like 'Ringing', 'Busy', or 'Failed Call'")
|
||||
|
||||
// MARK: Missed with Unseen identity Notification
|
||||
static let rejectedCallWithUnseenIdentityChangeNotificationBody = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY", comment: "notification action")
|
||||
static let rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITHOUT_CALLER_NAME", comment: "notification action")
|
||||
static let rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName = NSLocalizedString("MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITH_CALLER_NAME", comment: "notification action")
|
||||
}
|
||||
|
|
|
@ -84,6 +84,51 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
[contents addSection:[DebugUIContacts section]];
|
||||
|
||||
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so we
|
||||
// give a little delay.
|
||||
uint64_t notificationDelay = 5;
|
||||
[contents
|
||||
addSection:[OWSTableSection
|
||||
sectionWithTitle:[NSString stringWithFormat:@"Call Notifications (%llu second delay)",
|
||||
notificationDelay]
|
||||
items:@[
|
||||
[OWSTableItem itemWithTitle:@"Missed Call"
|
||||
actionBlock:^{
|
||||
SignalCall *call = [SignalCall
|
||||
incomingCallWithLocalId:[NSUUID new]
|
||||
remotePhoneNumber:thread.contactIdentifier
|
||||
signalingId:0];
|
||||
|
||||
dispatch_after(
|
||||
dispatch_time(DISPATCH_TIME_NOW,
|
||||
(int64_t)(notificationDelay * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(),
|
||||
^{
|
||||
[[Environment getCurrent]
|
||||
.callService.notificationsAdapter
|
||||
presentMissedCall:call
|
||||
callerName:thread.name];
|
||||
});
|
||||
}],
|
||||
[OWSTableItem
|
||||
itemWithTitle:@"Rejected Call with Unseen Safety Number"
|
||||
actionBlock:^{
|
||||
SignalCall *call =
|
||||
[SignalCall incomingCallWithLocalId:[NSUUID new]
|
||||
remotePhoneNumber:thread.contactIdentifier
|
||||
signalingId:0];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
|
||||
(int64_t)(notificationDelay * NSEC_PER_SEC)),
|
||||
dispatch_get_main_queue(),
|
||||
^{
|
||||
[[Environment getCurrent].callService.notificationsAdapter
|
||||
presentRejectedCallWithUnseenIdentityChange:call
|
||||
callerName:thread.name];
|
||||
});
|
||||
}],
|
||||
]]];
|
||||
|
||||
DebugUITableViewController *viewController = [DebugUITableViewController new];
|
||||
viewController.contents = contents;
|
||||
[viewController presentFromViewController:fromViewController];
|
||||
|
|
|
@ -110,9 +110,10 @@ protocol CallServiceObserver: class {
|
|||
private let accountManager: AccountManager
|
||||
private let messageSender: MessageSender
|
||||
private let contactsManager: OWSContactsManager
|
||||
private let notificationsAdapter: CallNotificationsAdapter
|
||||
private let storageManager: TSStorageManager
|
||||
|
||||
// Exposed by environment.m
|
||||
internal let notificationsAdapter: CallNotificationsAdapter
|
||||
internal var callUIAdapter: CallUIAdapter!
|
||||
|
||||
// MARK: Class
|
||||
|
@ -200,6 +201,7 @@ protocol CallServiceObserver: class {
|
|||
self.contactsManager = contactsManager
|
||||
self.messageSender = messageSender
|
||||
self.notificationsAdapter = notificationsAdapter
|
||||
self.storageManager = TSStorageManager.shared()
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -465,9 +467,16 @@ protocol CallServiceObserver: class {
|
|||
AssertIsOnMainThread()
|
||||
|
||||
Logger.info("\(TAG) receivedCallOffer for thread:\(thread)")
|
||||
|
||||
let newCall = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: callId)
|
||||
|
||||
guard call == nil else {
|
||||
guard !self.storageManager.hasUnseenIdentityChange(forRecipientId: thread.contactIdentifier()) else {
|
||||
let callerName = self.contactsManager.displayName(forPhoneIdentifier: thread.contactIdentifier())
|
||||
self.notificationsAdapter.presentRejectedCallWithUnseenIdentityChange(newCall, callerName: callerName)
|
||||
return
|
||||
}
|
||||
|
||||
guard self.call == nil else {
|
||||
// TODO on iOS10+ we can use CallKit to swap calls rather than just returning busy immediately.
|
||||
Logger.verbose("\(TAG) receivedCallOffer for thread: \(thread) but we're already in call: \(call!)")
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ import Foundation
|
|||
return false
|
||||
}
|
||||
|
||||
// TODO possible to get here when. e.g. dialing from contacts/recent calls. Should verify seen latest SN.
|
||||
|
||||
// Check for microphone permissions
|
||||
// Alternative way without prompting for permissions:
|
||||
// if AVAudioSession.sharedInstance().recordPermission() == .denied {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Created by Michael Kirk on 12/28/16.
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -11,6 +12,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (void)presentMissedCall:(SignalCall *)call callerName:(NSString *)callerName;
|
||||
|
||||
- (void)presentRejectedCallWithUnseenIdentityChange:(SignalCall *)call
|
||||
callerName:(NSString *)callerName
|
||||
NS_SWIFT_NAME(presentRejectedCallWithUnseenIdentityChange(_:callerName:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -113,6 +113,43 @@
|
|||
[self presentNotification:notification identifier:localCallId];
|
||||
}
|
||||
|
||||
- (void)presentRejectedCallWithUnseenIdentityChange:(SignalCall *)call callerName:(NSString *)callerName
|
||||
{
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:call.remotePhoneNumber];
|
||||
OWSAssert(thread != nil);
|
||||
|
||||
UILocalNotification *notification = [UILocalNotification new];
|
||||
notification.category = PushManagerCategoriesRejectedCallFromUnseenIdentityChange;
|
||||
NSString *localCallId = call.localId.UUIDString;
|
||||
notification.userInfo = @{
|
||||
PushManagerUserInfoKeysLocalCallId : localCallId,
|
||||
PushManagerUserInfoKeysCallBackSignalRecipientId : call.remotePhoneNumber,
|
||||
Signal_Thread_UserInfo_Key : thread.uniqueId
|
||||
};
|
||||
|
||||
NSString *alertMessage;
|
||||
switch (self.notificationPreviewType) {
|
||||
case NotificationNoNameNoPreview: {
|
||||
alertMessage = [CallStrings rejectedCallWithUnseenIdentityChangeNotificationBody];
|
||||
break;
|
||||
}
|
||||
case NotificationNameNoPreview:
|
||||
case NotificationNamePreview: {
|
||||
alertMessage = (([UIDevice currentDevice].supportsCallKit &&
|
||||
[[Environment getCurrent].preferences isCallKitPrivacyEnabled])
|
||||
? [CallStrings rejectedCallWithUnseenIdentityChangeNotificationBodyWithoutCallerName]
|
||||
: [NSString
|
||||
stringWithFormat:[CallStrings
|
||||
rejectedCallWithUnseenIdentityChangeNotificationBodyWithCallerName],
|
||||
callerName]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
notification.alertBody = [NSString stringWithFormat:@"☎️ %@", alertMessage];
|
||||
|
||||
[self presentNotification:notification identifier:localCallId];
|
||||
}
|
||||
|
||||
#pragma mark - Signal Messages
|
||||
|
||||
- (void)notifyUserForErrorMessage:(TSErrorMessage *)message inThread:(TSThread *)thread {
|
||||
|
|
|
@ -10,22 +10,25 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class UILocalNotification;
|
||||
|
||||
#define Signal_Thread_UserInfo_Key @"Signal_Thread_Id"
|
||||
#define Signal_Message_UserInfo_Key @"Signal_Message_Id"
|
||||
FOUNDATION_EXPORT NSString *const Signal_Thread_UserInfo_Key;
|
||||
FOUNDATION_EXPORT NSString *const Signal_Message_UserInfo_Key;
|
||||
|
||||
#define Signal_Full_New_Message_Category @"Signal_Full_New_Message"
|
||||
FOUNDATION_EXPORT NSString *const Signal_Full_New_Message_Category;
|
||||
|
||||
#define Signal_Message_Reply_Identifier @"Signal_New_Message_Reply"
|
||||
#define Signal_Message_MarkAsRead_Identifier @"Signal_Message_MarkAsRead"
|
||||
FOUNDATION_EXPORT NSString *const Signal_Message_Reply_Identifier;
|
||||
FOUNDATION_EXPORT NSString *const Signal_Message_MarkAsRead_Identifier;
|
||||
|
||||
#pragma mark Signal Calls constants
|
||||
|
||||
FOUNDATION_EXPORT NSString *const PushManagerCategoriesIncomingCall;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerCategoriesMissedCall;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerCategoriesRejectedCallFromUnseenIdentityChange;
|
||||
|
||||
FOUNDATION_EXPORT NSString *const PushManagerActionsAcceptCall;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerActionsDeclineCall;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerActionsCallBack;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerActionsConfirmIdentityAndCallBack;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerActionsShowThread;
|
||||
|
||||
FOUNDATION_EXPORT NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId;
|
||||
FOUNDATION_EXPORT NSString *const PushManagerUserInfoKeysLocalCallId;
|
||||
|
|
|
@ -16,7 +16,13 @@
|
|||
#import <SignalServiceKit/TSOutgoingMessage.h>
|
||||
#import <SignalServiceKit/TSSocketManager.h>
|
||||
|
||||
#define pushManagerDomain @"org.whispersystems.pushmanager"
|
||||
NSString *const Signal_Thread_UserInfo_Key = @"Signal_Thread_Id";
|
||||
NSString *const Signal_Message_UserInfo_Key = @"Signal_Message_Id";
|
||||
|
||||
NSString *const Signal_Full_New_Message_Category = @"Signal_Full_New_Message";
|
||||
|
||||
NSString *const Signal_Message_Reply_Identifier = @"Signal_New_Message_Reply";
|
||||
NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRead";
|
||||
|
||||
@interface PushManager ()
|
||||
|
||||
|
@ -132,10 +138,9 @@
|
|||
withResponseInfo:(NSDictionary *)responseInfo
|
||||
completionHandler:(void (^)())completionHandler
|
||||
{
|
||||
DDLogInfo(@"received: %s", __PRETTY_FUNCTION__);
|
||||
DDLogInfo(@"%@ handling action with identifier: %@", self.tag, identifier);
|
||||
|
||||
if ([identifier isEqualToString:Signal_Message_Reply_Identifier]) {
|
||||
DDLogInfo(@"%@ received reply identifier", self.tag);
|
||||
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
||||
|
||||
if (threadId) {
|
||||
|
@ -146,6 +151,7 @@
|
|||
messageBody:responseInfo[UIUserNotificationActionResponseTypedTextKey]];
|
||||
[self.messageSender sendMessage:message
|
||||
success:^{
|
||||
// TODO do we really want to mark them all as read?
|
||||
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
||||
[[[[Environment getCurrent] signalsViewController] tableView] reloadData];
|
||||
}
|
||||
|
@ -162,10 +168,9 @@
|
|||
}];
|
||||
}
|
||||
} else if ([identifier isEqualToString:Signal_Message_MarkAsRead_Identifier]) {
|
||||
// TODO mark all as read? Or just this one?
|
||||
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
||||
} else if ([identifier isEqualToString:PushManagerActionsAcceptCall]) {
|
||||
DDLogInfo(@"%@ received accept call action", self.tag);
|
||||
|
||||
NSString *localIdString = notification.userInfo[PushManagerUserInfoKeysLocalCallId];
|
||||
if (!localIdString) {
|
||||
DDLogError(@"%@ missing localIdString.", self.tag);
|
||||
|
@ -178,11 +183,9 @@
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
[self.callUIAdapter answerCallWithLocalId:localId];
|
||||
completionHandler();
|
||||
} else if ([identifier isEqualToString:PushManagerActionsDeclineCall]) {
|
||||
DDLogInfo(@"%@ received decline call action", self.tag);
|
||||
|
||||
NSString *localIdString = notification.userInfo[PushManagerUserInfoKeysLocalCallId];
|
||||
if (!localIdString) {
|
||||
DDLogError(@"%@ missing localIdString.", self.tag);
|
||||
|
@ -196,9 +199,8 @@
|
|||
}
|
||||
|
||||
[self.callUIAdapter declineCallWithLocalId:localId];
|
||||
completionHandler();
|
||||
} else if ([identifier isEqualToString:PushManagerActionsCallBack]) {
|
||||
DDLogInfo(@"%@ received call back action", self.tag);
|
||||
|
||||
NSString *recipientId = notification.userInfo[PushManagerUserInfoKeysCallBackSignalRecipientId];
|
||||
if (!recipientId) {
|
||||
DDLogError(@"%@ missing call back id", self.tag);
|
||||
|
@ -206,9 +208,26 @@
|
|||
}
|
||||
|
||||
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId];
|
||||
} else {
|
||||
DDLogDebug(@"%@ Unhandled action with identifier: %@", self.tag, identifier);
|
||||
completionHandler();
|
||||
} else if ([identifier isEqualToString:PushManagerActionsConfirmIdentityAndCallBack]) {
|
||||
NSString *recipientId = notification.userInfo[PushManagerUserInfoKeysCallBackSignalRecipientId];
|
||||
if (!recipientId) {
|
||||
DDLogError(@"%@ missing call back id", self.tag);
|
||||
return;
|
||||
}
|
||||
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId];
|
||||
[MarkIdentityAsSeenJob runWithThread:thread];
|
||||
|
||||
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId];
|
||||
completionHandler();
|
||||
} else if ([identifier isEqualToString:PushManagerActionsShowThread]) {
|
||||
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
||||
[Environment messageThreadId:threadId];
|
||||
completionHandler();
|
||||
} else {
|
||||
DDLogError(@"%@ Unhandled action with identifier: %@", self.tag, identifier);
|
||||
OWSFail(@"Unhandled action");
|
||||
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
||||
[Environment messageThreadId:threadId];
|
||||
completionHandler();
|
||||
|
@ -338,10 +357,14 @@
|
|||
|
||||
NSString *const PushManagerCategoriesIncomingCall = @"PushManagerCategoriesIncomingCall";
|
||||
NSString *const PushManagerCategoriesMissedCall = @"PushManagerCategoriesMissedCall";
|
||||
NSString *const PushManagerCategoriesRejectedCallFromUnseenIdentityChange =
|
||||
@"PushManagerCategoriesRejectedCallFromUnseenIdentityChange";
|
||||
|
||||
NSString *const PushManagerActionsAcceptCall = @"PushManagerActionsAcceptCall";
|
||||
NSString *const PushManagerActionsDeclineCall = @"PushManagerActionsDeclineCall";
|
||||
NSString *const PushManagerActionsCallBack = @"PushManagerActionsCallBack";
|
||||
NSString *const PushManagerActionsConfirmIdentityAndCallBack = @"PushManagerActionsConfirmIdentityAndCallBack";
|
||||
NSString *const PushManagerActionsShowThread = @"PushManagerActionsShowThread";
|
||||
|
||||
NSString *const PushManagerUserInfoKeysLocalCallId = @"PushManagerUserInfoKeysLocalCallId";
|
||||
NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManagerUserInfoKeysCallBackSignalRecipientId";
|
||||
|
@ -379,12 +402,38 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
|
|||
callBackAction.destructive = NO;
|
||||
callBackAction.authenticationRequired = YES;
|
||||
|
||||
UIMutableUserNotificationCategory *callCategory = [UIMutableUserNotificationCategory new];
|
||||
callCategory.identifier = PushManagerCategoriesMissedCall;
|
||||
[callCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextMinimal];
|
||||
[callCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextDefault];
|
||||
UIMutableUserNotificationCategory *missedCallCategory = [UIMutableUserNotificationCategory new];
|
||||
missedCallCategory.identifier = PushManagerCategoriesMissedCall;
|
||||
[missedCallCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextMinimal];
|
||||
[missedCallCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextDefault];
|
||||
|
||||
return callCategory;
|
||||
return missedCallCategory;
|
||||
}
|
||||
|
||||
- (UIUserNotificationCategory *)signalRejectedCallWithUnseenIdentityChangeCategory
|
||||
{
|
||||
UIMutableUserNotificationAction *confirmAndCallBackAction = [UIMutableUserNotificationAction new];
|
||||
confirmAndCallBackAction.identifier = PushManagerActionsConfirmIdentityAndCallBack;
|
||||
confirmAndCallBackAction.title = [CallStrings confirmIdentityAndCallBackButtonTitle];
|
||||
confirmAndCallBackAction.activationMode = UIUserNotificationActivationModeForeground;
|
||||
confirmAndCallBackAction.destructive = NO;
|
||||
confirmAndCallBackAction.authenticationRequired = YES;
|
||||
|
||||
UIMutableUserNotificationAction *showThreadAction = [UIMutableUserNotificationAction new];
|
||||
showThreadAction.identifier = PushManagerActionsShowThread;
|
||||
showThreadAction.title = [CallStrings showThreadButtonTitle];
|
||||
showThreadAction.activationMode = UIUserNotificationActivationModeForeground;
|
||||
showThreadAction.destructive = NO;
|
||||
showThreadAction.authenticationRequired = YES;
|
||||
|
||||
UIMutableUserNotificationCategory *rejectedCallCategory = [UIMutableUserNotificationCategory new];
|
||||
rejectedCallCategory.identifier = PushManagerCategoriesRejectedCallFromUnseenIdentityChange;
|
||||
[rejectedCallCategory setActions:@[ confirmAndCallBackAction, showThreadAction ]
|
||||
forContext:UIUserNotificationActionContextMinimal];
|
||||
[rejectedCallCategory setActions:@[ confirmAndCallBackAction, showThreadAction ]
|
||||
forContext:UIUserNotificationActionContextDefault];
|
||||
|
||||
return rejectedCallCategory;
|
||||
}
|
||||
|
||||
#pragma mark Util
|
||||
|
@ -408,6 +457,7 @@ NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManager
|
|||
categories:[NSSet setWithObjects:[self fullNewMessageNotificationCategory],
|
||||
[self signalIncomingCallCategory],
|
||||
[self signalMissedCallCategory],
|
||||
[self signalRejectedCallWithUnseenIdentityChangeCategory],
|
||||
nil]];
|
||||
|
||||
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
"CALL_VIEW_SETTINGS_NAG_SHOW_CALL_SETTINGS" = "Show Privacy Settings";
|
||||
|
||||
/* 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";
|
||||
|
@ -232,6 +232,9 @@
|
|||
/* No comment provided by engineer. */
|
||||
"CONFIRM_ACCOUNT_DESTRUCTION_TITLE" = "Are you sure you want to delete your account?";
|
||||
|
||||
/* notification action, confirming that it's OK to proceed calling after a caller's Safety Number has changed */
|
||||
"CONFIRM_IDENTITY_AND_CALLBACK_BUTTON_TITLE" = "Confirm and Call Back";
|
||||
|
||||
/* Alert body */
|
||||
"CONFIRM_LEAVE_GROUP_DESCRIPTION" = "You will no longer be able to send or receive messages in this group.";
|
||||
|
||||
|
@ -670,9 +673,6 @@
|
|||
/* table cell label in conversation settings */
|
||||
"LIST_GROUP_MEMBERS_ACTION" = "List Group Members";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"load_earlier_messages" = "load_earlier_messages";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"LOGGING_SECTION" = "Logging";
|
||||
|
||||
|
@ -736,6 +736,15 @@
|
|||
/* notification title */
|
||||
"MISSED_CALL" = "Missed call";
|
||||
|
||||
/* notification action */
|
||||
"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY" = "Missed call because the caller's Safety Number changed.";
|
||||
|
||||
/* notification action */
|
||||
"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITH_CALLER_NAME" = "Missed call from %@ because their Safety Number changed.";
|
||||
|
||||
/* notification action */
|
||||
"MISSED_CALL_WITH_UNSEEN_IDENTITY_BODY_WITHOUT_CALLER_NAME" = "Missed call because the caller's Safety Number changed.";
|
||||
|
||||
/* Alert body
|
||||
Alert body when camera is not authorized */
|
||||
"MISSING_CAMERA_PERMISSION_MESSAGE" = "Signal needs access to your camera for video calls. You can grant this permission in the Settings app >> Privacy >> Camera >> Signal";
|
||||
|
@ -950,7 +959,7 @@
|
|||
"PROCEED_BUTTON" = "Proceed";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PUSH_MANAGER_MARKREAD" = "Mark as read";
|
||||
"PUSH_MANAGER_MARKREAD" = "Mark as Read";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PUSH_MANAGER_REPLY" = "Reply";
|
||||
|
@ -1258,6 +1267,9 @@
|
|||
/* Action sheet item */
|
||||
"SHOW_SAFETY_NUMBER_ACTION" = "Show new safety number";
|
||||
|
||||
/* notification action */
|
||||
"SHOW_THREAD_BUTTON_TITLE" = "Show Thread";
|
||||
|
||||
/* {{1 day}} embedded in strings, e.g. 'Alice updated disappearing messages expiration to {{1 day}}'. See other *_TIME_AMOUNT strings */
|
||||
"SINGLE_DAY_TIME_AMOUNT" = "%u day";
|
||||
|
||||
|
|
Loading…
Reference in New Issue