2014-08-01 07:53:58 +02:00
|
|
|
|
//
|
2019-01-18 00:57:28 +01:00
|
|
|
|
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
2014-08-01 07:53:58 +02:00
|
|
|
|
//
|
2015-04-14 21:49:00 +02:00
|
|
|
|
|
2016-10-14 22:59:58 +02:00
|
|
|
|
#import "PushManager.h"
|
2015-09-01 19:22:08 +02:00
|
|
|
|
#import "AppDelegate.h"
|
2016-12-20 23:44:11 +01:00
|
|
|
|
#import "Signal-Swift.h"
|
2017-12-01 21:17:29 +01:00
|
|
|
|
#import "SignalApp.h"
|
2017-07-14 15:27:52 +02:00
|
|
|
|
#import "ThreadUtil.h"
|
2018-09-21 21:41:10 +02:00
|
|
|
|
#import <SignalCoreKit/NSDate+OWS.h>
|
2017-12-19 03:50:51 +01:00
|
|
|
|
#import <SignalMessaging/OWSContactsManager.h>
|
2018-01-26 22:23:39 +01:00
|
|
|
|
#import <SignalServiceKit/AppReadiness.h>
|
2018-12-19 22:35:43 +01:00
|
|
|
|
#import <SignalServiceKit/NSString+SSK.h>
|
2017-11-16 15:54:55 +01:00
|
|
|
|
#import <SignalServiceKit/OWSDevice.h>
|
2016-10-14 22:59:58 +02:00
|
|
|
|
#import <SignalServiceKit/OWSMessageSender.h>
|
2017-09-26 17:45:22 +02:00
|
|
|
|
#import <SignalServiceKit/OWSReadReceiptManager.h>
|
2016-12-20 23:44:11 +01:00
|
|
|
|
#import <SignalServiceKit/OWSSignalService.h>
|
2017-05-27 02:41:27 +02:00
|
|
|
|
#import <SignalServiceKit/TSAccountManager.h>
|
2017-09-21 23:09:55 +02:00
|
|
|
|
#import <SignalServiceKit/TSIncomingMessage.h>
|
2017-05-27 02:41:27 +02:00
|
|
|
|
#import <SignalServiceKit/TSOutgoingMessage.h>
|
|
|
|
|
#import <SignalServiceKit/TSSocketManager.h>
|
2014-08-01 07:53:58 +02:00
|
|
|
|
|
2017-05-31 17:49:30 +02:00
|
|
|
|
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";
|
2017-06-23 19:55:21 +02:00
|
|
|
|
NSString *const Signal_Full_New_Message_Category_No_Longer_Verified =
|
|
|
|
|
@"Signal_Full_New_Message_Category_No_Longer_Verified";
|
2017-05-31 17:49:30 +02:00
|
|
|
|
|
|
|
|
|
NSString *const Signal_Message_Reply_Identifier = @"Signal_New_Message_Reply";
|
|
|
|
|
NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRead";
|
2015-02-20 17:02:31 +01:00
|
|
|
|
|
2016-09-14 18:19:05 +02:00
|
|
|
|
@interface PushManager ()
|
2014-08-01 07:53:58 +02:00
|
|
|
|
|
2017-05-09 16:04:48 +02:00
|
|
|
|
@property (nonatomic) NSMutableArray *currentNotifications;
|
2015-04-14 21:49:00 +02:00
|
|
|
|
@property (nonatomic) UIBackgroundTaskIdentifier callBackgroundTask;
|
2015-09-01 19:22:08 +02:00
|
|
|
|
|
2014-08-01 07:53:58 +02:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation PushManager
|
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
+ (instancetype)sharedManager {
|
2018-10-16 17:47:54 +02:00
|
|
|
|
OWSAssertDebug(AppEnvironment.shared.pushManager);
|
2014-08-01 07:53:58 +02:00
|
|
|
|
|
2018-10-16 17:47:54 +02:00
|
|
|
|
return AppEnvironment.shared.pushManager;
|
2016-10-14 22:59:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-16 17:47:54 +02:00
|
|
|
|
- (instancetype)init {
|
2014-10-29 14:25:41 +01:00
|
|
|
|
self = [super init];
|
2016-09-11 22:53:12 +02:00
|
|
|
|
if (!self) {
|
|
|
|
|
return self;
|
2014-10-29 14:25:41 +01:00
|
|
|
|
}
|
2016-09-11 22:53:12 +02:00
|
|
|
|
|
|
|
|
|
_callBackgroundTask = UIBackgroundTaskInvalid;
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
// TODO: consolidate notification tracking with NotificationsManager, which also maintains a list of notifications.
|
2017-04-12 16:03:09 +02:00
|
|
|
|
_currentNotifications = [NSMutableArray array];
|
2016-09-11 22:53:12 +02:00
|
|
|
|
|
2017-04-01 00:36:30 +02:00
|
|
|
|
OWSSingletonAssert();
|
|
|
|
|
|
2017-09-14 23:06:35 +02:00
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
|
|
|
selector:@selector(handleMessageRead:)
|
2017-09-27 20:05:21 +02:00
|
|
|
|
name:kIncomingMessageMarkedAsReadNotification
|
2017-09-14 23:06:35 +02:00
|
|
|
|
object:nil];
|
|
|
|
|
|
2014-10-29 14:25:41 +01:00
|
|
|
|
return self;
|
|
|
|
|
}
|
2014-10-07 00:04:50 +02:00
|
|
|
|
|
2018-10-16 17:47:54 +02:00
|
|
|
|
#pragma mark - Dependencies
|
|
|
|
|
|
|
|
|
|
- (OWSMessageSender *)messageSender {
|
|
|
|
|
return SSKEnvironment.shared.messageSender;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (OWSMessageFetcherJob *)messageFetcherJob {
|
|
|
|
|
return AppEnvironment.shared.messageFetcherJob;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id<NotificationsProtocol>)notificationsManager {
|
|
|
|
|
return SSKEnvironment.shared.notificationsManager;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
2018-03-08 00:09:07 +01:00
|
|
|
|
- (CallUIAdapter *)callUIAdapter
|
|
|
|
|
{
|
2018-10-15 20:58:15 +02:00
|
|
|
|
return AppEnvironment.shared.callService.callUIAdapter;
|
2018-03-08 00:09:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-14 23:06:35 +02:00
|
|
|
|
- (void)handleMessageRead:(NSNotification *)notification
|
|
|
|
|
{
|
2017-12-19 17:38:25 +01:00
|
|
|
|
OWSAssertIsOnMainThread();
|
2017-09-26 17:45:22 +02:00
|
|
|
|
|
2017-09-14 23:06:35 +02:00
|
|
|
|
if ([notification.object isKindOfClass:[TSIncomingMessage class]]) {
|
|
|
|
|
TSIncomingMessage *message = (TSIncomingMessage *)notification.object;
|
|
|
|
|
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogDebug(@"canceled notification for message:%@", message);
|
2017-09-14 23:06:35 +02:00
|
|
|
|
[self cancelNotificationsWithThreadId:message.uniqueThreadId];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
#pragma mark Manage Incoming Push
|
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
|
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogInfo(@"received remote notification");
|
2016-12-20 23:44:11 +01:00
|
|
|
|
|
2018-11-02 18:51:46 +01:00
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
|
2018-01-26 22:23:39 +01:00
|
|
|
|
[self.messageFetcherJob run];
|
|
|
|
|
}];
|
2015-04-14 21:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-03 23:09:50 +01:00
|
|
|
|
- (void)applicationDidBecomeActive {
|
2018-11-02 18:51:46 +01:00
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
|
2018-01-26 22:23:39 +01:00
|
|
|
|
[self.messageFetcherJob run];
|
|
|
|
|
}];
|
2017-01-03 23:09:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
/**
|
2015-12-22 12:45:09 +01:00
|
|
|
|
* This code should in principle never be called. The only cases where it would be called are with the old-style
|
|
|
|
|
* "content-available:1" pushes if there is no "voip" token registered
|
2015-04-14 21:49:00 +02:00
|
|
|
|
*
|
|
|
|
|
*/
|
2015-12-22 12:45:09 +01:00
|
|
|
|
- (void)application:(UIApplication *)application
|
|
|
|
|
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogInfo(@"received content-available push");
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
|
|
|
|
|
// If we want to re-introduce silent pushes we can remove this assert.
|
2018-08-27 16:29:51 +02:00
|
|
|
|
OWSFailDebug(@"Unexpected content-available push.");
|
2016-12-20 23:44:11 +01:00
|
|
|
|
|
2018-11-02 18:51:46 +01:00
|
|
|
|
[AppReadiness runNowOrWhenAppDidBecomeReady:^{
|
2018-01-29 17:25:23 +01:00
|
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
|
|
|
|
completionHandler(UIBackgroundFetchResultNewData);
|
|
|
|
|
});
|
|
|
|
|
}];
|
2015-04-14 21:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-07 01:55:37 +02:00
|
|
|
|
- (void)presentOncePerActivationConversationWithThreadId:(NSString *)threadId
|
|
|
|
|
{
|
|
|
|
|
if (self.hasPresentedConversationSinceLastDeactivation) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"refusing to present conversation: %@ multiple times.", threadId);
|
2018-07-07 01:55:37 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.hasPresentedConversationSinceLastDeactivation = YES;
|
Faster conversation presentation.
There are multiple places in the codebase we present a conversation.
We used to have some very conservative machinery around how this was done, for
fear of failing to present the call view controller, which would have left a
hidden call in the background. We've since addressed that concern more
thoroughly via the separate calling UIWindow.
As such, the remaining presentation machinery is overly complex and inflexible
for what we need.
Sometimes we want to animate-push the conversation. (tap on home, tap on "send message" in contact card/group members)
Sometimes we want to dismiss a modal, to reveal the conversation behind it (contact picker, group creation)
Sometimes we want to present the conversation with no animation (becoming active from a notification)
We also want to ensure that we're never pushing more than one conversation view
controller, which was previously a problem since we were "pushing" a newly
constructed VC in response to these myriad actions. It turned out there were
certain code paths that caused multiple actions to be fired in rapid succession
which pushed multiple ConversationVC's.
The built-in method: `setViewControllers:animated` easily ensures we only have
one ConversationVC on the stack, while being composable enough to faciliate the
various more efficient animations we desire.
The only thing lost with the complex methods is that the naive
`presentViewController:` can fail, e.g. if another view is already presented.
E.g. if an alert appears *just* before the user taps compose, the contact
picker will fail to present.
Since we no longer depend on this for presenting the CallViewController, this
isn't catostrophic, and in fact, arguable preferable, since we want the user to
read and dismiss any alert explicitly.
// FREEBIE
2018-08-18 22:54:35 +02:00
|
|
|
|
|
|
|
|
|
// This will happen before the app is visible. By making this animated:NO, the conversation screen
|
|
|
|
|
// will be visible to the user immediately upon opening the app, rather than having to watch it animate
|
|
|
|
|
// in from the homescreen.
|
|
|
|
|
[SignalApp.sharedApp presentConversationForThreadId:threadId animated:NO];
|
2018-07-07 01:55:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
|
|
|
|
|
{
|
2017-12-19 17:38:25 +01:00
|
|
|
|
OWSAssertIsOnMainThread();
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogInfo(@"launched from local notification");
|
2016-12-20 23:44:11 +01:00
|
|
|
|
|
2017-09-30 23:59:19 +02:00
|
|
|
|
NSString *_Nullable threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
|
|
|
|
|
if (threadId) {
|
2018-07-07 01:55:37 +02:00
|
|
|
|
[self presentOncePerActivationConversationWithThreadId:threadId];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
} else {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"threadId was unexpectedly nil");
|
2015-04-14 21:49:00 +02:00
|
|
|
|
}
|
2017-11-06 18:37:15 +01:00
|
|
|
|
|
|
|
|
|
// We only want to receive a single local notification per launch.
|
|
|
|
|
[application cancelAllLocalNotifications];
|
|
|
|
|
[self.currentNotifications removeAllObjects];
|
|
|
|
|
[self.notificationsManager clearAllNotifications];
|
2015-04-14 21:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
- (void)application:(UIApplication *)application
|
|
|
|
|
handleActionWithIdentifier:(NSString *)identifier
|
|
|
|
|
forLocalNotification:(UILocalNotification *)notification
|
2017-11-08 20:04:51 +01:00
|
|
|
|
completionHandler:(void (^)(void))completionHandler
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogInfo(@"in %s", __FUNCTION__);
|
2016-12-20 23:44:11 +01:00
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
[self application:application
|
|
|
|
|
handleActionWithIdentifier:identifier
|
|
|
|
|
forLocalNotification:notification
|
|
|
|
|
withResponseInfo:@{}
|
|
|
|
|
completionHandler:completionHandler];
|
2015-09-01 19:22:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
- (void)application:(UIApplication *)application
|
|
|
|
|
handleActionWithIdentifier:(NSString *)identifier
|
|
|
|
|
forLocalNotification:(UILocalNotification *)notification
|
|
|
|
|
withResponseInfo:(NSDictionary *)responseInfo
|
2017-11-08 20:04:51 +01:00
|
|
|
|
completionHandler:(void (^)(void))completionHandler
|
2016-08-01 00:25:07 +02:00
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogInfo(@"handling action with identifier: %@", identifier);
|
2016-12-20 23:44:11 +01:00
|
|
|
|
|
2015-09-01 19:22:08 +02:00
|
|
|
|
if ([identifier isEqualToString:Signal_Message_Reply_Identifier]) {
|
|
|
|
|
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-09-01 19:22:08 +02:00
|
|
|
|
if (threadId) {
|
|
|
|
|
TSThread *thread = [TSThread fetchObjectWithUniqueID:threadId];
|
2017-07-14 15:27:52 +02:00
|
|
|
|
NSString *replyText = responseInfo[UIUserNotificationActionResponseTypedTextKey];
|
|
|
|
|
|
2018-04-09 15:15:48 +02:00
|
|
|
|
// In line with most apps, we send a normal outgoing messgae here - not a "quoted reply".
|
2018-10-20 19:51:48 +02:00
|
|
|
|
|
|
|
|
|
// We use a non-durable send to delay calling the completion handler until sending completes
|
|
|
|
|
// in hopes our send will complete before the app gets suspended.
|
|
|
|
|
[ThreadUtil sendMessageNonDurablyWithText:replyText
|
2017-07-14 15:27:52 +02:00
|
|
|
|
inThread:thread
|
2018-04-09 15:15:48 +02:00
|
|
|
|
quotedReplyModel:nil
|
2017-07-14 15:27:52 +02:00
|
|
|
|
messageSender:self.messageSender
|
2015-12-22 12:45:09 +01:00
|
|
|
|
success:^{
|
2017-05-31 17:49:30 +02:00
|
|
|
|
// TODO do we really want to mark them all as read?
|
2016-10-14 22:59:58 +02:00
|
|
|
|
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
}
|
2017-07-14 15:27:52 +02:00
|
|
|
|
failure:^(NSError *_Nonnull error) {
|
2016-10-14 22:59:58 +02:00
|
|
|
|
// TODO Surface the specific error in the notification?
|
2018-08-27 18:00:28 +02:00
|
|
|
|
OWSLogError(@"Message send failed with error: %@", error);
|
2016-10-14 22:59:58 +02:00
|
|
|
|
|
|
|
|
|
UILocalNotification *failedSendNotif = [[UILocalNotification alloc] init];
|
|
|
|
|
failedSendNotif.alertBody =
|
2018-02-16 02:45:28 +01:00
|
|
|
|
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]]
|
|
|
|
|
.filterStringForDisplay;
|
2016-10-14 22:59:58 +02:00
|
|
|
|
failedSendNotif.userInfo = @{ Signal_Thread_UserInfo_Key : thread.uniqueId };
|
2017-04-05 17:13:09 +02:00
|
|
|
|
[self presentNotification:failedSendNotif checkForCancel:NO];
|
2016-10-14 22:59:58 +02:00
|
|
|
|
completionHandler();
|
2015-12-22 12:45:09 +01:00
|
|
|
|
}];
|
2015-09-01 19:22:08 +02:00
|
|
|
|
}
|
2015-12-22 12:45:09 +01:00
|
|
|
|
} else if ([identifier isEqualToString:Signal_Message_MarkAsRead_Identifier]) {
|
2017-05-31 17:49:30 +02:00
|
|
|
|
// TODO mark all as read? Or just this one?
|
2015-09-01 19:22:08 +02:00
|
|
|
|
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
2016-11-12 18:22:29 +01:00
|
|
|
|
} else if ([identifier isEqualToString:PushManagerActionsAcceptCall]) {
|
|
|
|
|
NSString *localIdString = notification.userInfo[PushManagerUserInfoKeysLocalCallId];
|
|
|
|
|
if (!localIdString) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogError(@"missing localIdString.");
|
2016-11-12 18:22:29 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSUUID *localId = [[NSUUID alloc] initWithUUIDString:localIdString];
|
|
|
|
|
if (!localId) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogError(@"localIdString failed to parse as UUID.");
|
2016-11-12 18:22:29 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-18 21:17:55 +01:00
|
|
|
|
[self.callUIAdapter answerCallWithLocalId:localId];
|
2017-05-31 17:49:30 +02:00
|
|
|
|
completionHandler();
|
2016-11-12 18:22:29 +01:00
|
|
|
|
} else if ([identifier isEqualToString:PushManagerActionsDeclineCall]) {
|
|
|
|
|
NSString *localIdString = notification.userInfo[PushManagerUserInfoKeysLocalCallId];
|
|
|
|
|
if (!localIdString) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogError(@"missing localIdString.");
|
2016-11-12 18:22:29 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSUUID *localId = [[NSUUID alloc] initWithUUIDString:localIdString];
|
|
|
|
|
if (!localId) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogError(@"localIdString failed to parse as UUID.");
|
2016-11-12 18:22:29 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-18 21:17:55 +01:00
|
|
|
|
[self.callUIAdapter declineCallWithLocalId:localId];
|
2017-05-31 17:49:30 +02:00
|
|
|
|
completionHandler();
|
2016-11-12 18:22:29 +01:00
|
|
|
|
} else if ([identifier isEqualToString:PushManagerActionsCallBack]) {
|
2017-05-31 17:49:30 +02:00
|
|
|
|
NSString *recipientId = notification.userInfo[PushManagerUserInfoKeysCallBackSignalRecipientId];
|
|
|
|
|
if (!recipientId) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogError(@"missing call back id");
|
2017-05-31 17:49:30 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-11-12 18:22:29 +01:00
|
|
|
|
|
2018-05-02 16:08:47 +02:00
|
|
|
|
[self.callUIAdapter startAndShowOutgoingCallWithRecipientId:recipientId hasLocalVideo:NO];
|
2017-05-31 17:49:30 +02:00
|
|
|
|
completionHandler();
|
|
|
|
|
} else if ([identifier isEqualToString:PushManagerActionsShowThread]) {
|
|
|
|
|
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
|
|
|
|
|
if (threadId) {
|
2018-07-07 01:55:37 +02:00
|
|
|
|
[self presentOncePerActivationConversationWithThreadId:threadId];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
} else {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"threadId was unexpectedly nil in action with identifier: %@", identifier);
|
2017-09-28 17:39:25 +02:00
|
|
|
|
}
|
2017-05-31 17:49:30 +02:00
|
|
|
|
completionHandler();
|
2015-09-01 19:22:08 +02:00
|
|
|
|
} else {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"Unhandled action with identifier: %@", identifier);
|
2015-09-01 19:22:08 +02:00
|
|
|
|
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
if (threadId) {
|
2018-07-07 01:55:37 +02:00
|
|
|
|
[self presentOncePerActivationConversationWithThreadId:threadId];
|
2017-09-28 17:39:25 +02:00
|
|
|
|
} else {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"threadId was unexpectedly nil in action with identifier: %@", identifier);
|
2017-09-28 17:39:25 +02:00
|
|
|
|
}
|
2015-04-14 21:49:00 +02:00
|
|
|
|
completionHandler();
|
|
|
|
|
}
|
2015-09-01 19:22:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 20:04:51 +01:00
|
|
|
|
- (void)markAllInThreadAsRead:(NSDictionary *)userInfo completionHandler:(void (^)(void))completionHandler
|
|
|
|
|
{
|
2015-09-01 19:22:08 +02:00
|
|
|
|
NSString *threadId = userInfo[Signal_Thread_UserInfo_Key];
|
2018-04-17 21:23:05 +02:00
|
|
|
|
if (!threadId) {
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSFailDebug(@"missing thread id for notification.");
|
2018-04-17 21:23:05 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-09-01 19:22:08 +02:00
|
|
|
|
TSThread *thread = [TSThread fetchObjectWithUniqueID:threadId];
|
2018-03-05 15:30:58 +01:00
|
|
|
|
[OWSPrimaryStorage.dbReadWriteConnection
|
2017-06-12 17:52:21 +02:00
|
|
|
|
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
|
|
|
|
// TODO: I suspect we only want to mark the message in
|
|
|
|
|
// question as read.
|
|
|
|
|
[thread markAllAsReadWithTransaction:transaction];
|
|
|
|
|
}
|
2015-12-22 12:45:09 +01:00
|
|
|
|
completionBlock:^{
|
2017-06-12 17:52:21 +02:00
|
|
|
|
[self cancelNotificationsWithThreadId:threadId];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2017-06-12 17:52:21 +02:00
|
|
|
|
completionHandler();
|
2015-12-22 12:45:09 +01:00
|
|
|
|
}];
|
2015-04-14 21:49:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
- (UIUserNotificationCategory *)fullNewMessageNotificationCategory {
|
2017-06-23 19:55:21 +02:00
|
|
|
|
UIMutableUserNotificationAction *action_markRead = [self markAsReadAction];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationAction *action_reply = [UIMutableUserNotificationAction new];
|
|
|
|
|
action_reply.identifier = Signal_Message_Reply_Identifier;
|
|
|
|
|
action_reply.title = NSLocalizedString(@"PUSH_MANAGER_REPLY", @"");
|
|
|
|
|
action_reply.destructive = NO;
|
2017-05-26 04:19:20 +02:00
|
|
|
|
action_reply.authenticationRequired = NO;
|
2018-02-23 18:46:04 +01:00
|
|
|
|
action_reply.behavior = UIUserNotificationActionBehaviorTextInput;
|
|
|
|
|
action_reply.activationMode = UIUserNotificationActivationModeBackground;
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
UIMutableUserNotificationCategory *messageCategory = [UIMutableUserNotificationCategory new];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
messageCategory.identifier = Signal_Full_New_Message_Category;
|
|
|
|
|
[messageCategory setActions:@[ action_markRead, action_reply ] forContext:UIUserNotificationActionContextMinimal];
|
2017-05-26 04:19:20 +02:00
|
|
|
|
[messageCategory setActions:@[ action_markRead, action_reply ] forContext:UIUserNotificationActionContextDefault];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
return messageCategory;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-23 19:55:21 +02:00
|
|
|
|
- (UIUserNotificationCategory *)fullNewMessageNoLongerVerifiedNotificationCategory
|
|
|
|
|
{
|
|
|
|
|
UIMutableUserNotificationAction *action_markRead = [self markAsReadAction];
|
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationCategory *messageCategory = [UIMutableUserNotificationCategory new];
|
|
|
|
|
messageCategory.identifier = Signal_Full_New_Message_Category_No_Longer_Verified;
|
|
|
|
|
[messageCategory setActions:@[ action_markRead ] forContext:UIUserNotificationActionContextMinimal];
|
|
|
|
|
[messageCategory setActions:@[ action_markRead ] forContext:UIUserNotificationActionContextDefault];
|
|
|
|
|
|
|
|
|
|
return messageCategory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UIMutableUserNotificationAction *)markAsReadAction
|
|
|
|
|
{
|
|
|
|
|
UIMutableUserNotificationAction *action = [UIMutableUserNotificationAction new];
|
|
|
|
|
action.identifier = Signal_Message_MarkAsRead_Identifier;
|
|
|
|
|
action.title = NSLocalizedString(@"PUSH_MANAGER_MARKREAD", nil);
|
|
|
|
|
action.destructive = NO;
|
|
|
|
|
action.authenticationRequired = NO;
|
|
|
|
|
action.activationMode = UIUserNotificationActivationModeBackground;
|
|
|
|
|
return action;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-12 18:22:29 +01:00
|
|
|
|
#pragma mark - Signal Calls
|
|
|
|
|
|
|
|
|
|
NSString *const PushManagerCategoriesIncomingCall = @"PushManagerCategoriesIncomingCall";
|
|
|
|
|
NSString *const PushManagerCategoriesMissedCall = @"PushManagerCategoriesMissedCall";
|
2017-06-07 00:59:38 +02:00
|
|
|
|
NSString *const PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity =
|
|
|
|
|
@"PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity";
|
2016-11-12 18:22:29 +01:00
|
|
|
|
|
|
|
|
|
NSString *const PushManagerActionsAcceptCall = @"PushManagerActionsAcceptCall";
|
|
|
|
|
NSString *const PushManagerActionsDeclineCall = @"PushManagerActionsDeclineCall";
|
|
|
|
|
NSString *const PushManagerActionsCallBack = @"PushManagerActionsCallBack";
|
2017-06-06 22:31:09 +02:00
|
|
|
|
NSString *const PushManagerActionsIgnoreIdentityChangeAndCallBack =
|
|
|
|
|
@"PushManagerActionsIgnoreIdentityChangeAndCallBack";
|
2017-05-31 17:49:30 +02:00
|
|
|
|
NSString *const PushManagerActionsShowThread = @"PushManagerActionsShowThread";
|
2016-11-12 18:22:29 +01:00
|
|
|
|
|
|
|
|
|
NSString *const PushManagerUserInfoKeysLocalCallId = @"PushManagerUserInfoKeysLocalCallId";
|
|
|
|
|
NSString *const PushManagerUserInfoKeysCallBackSignalRecipientId = @"PushManagerUserInfoKeysCallBackSignalRecipientId";
|
|
|
|
|
|
|
|
|
|
- (UIUserNotificationCategory *)signalIncomingCallCategory
|
|
|
|
|
{
|
|
|
|
|
UIMutableUserNotificationAction *acceptAction = [UIMutableUserNotificationAction new];
|
|
|
|
|
acceptAction.identifier = PushManagerActionsAcceptCall;
|
|
|
|
|
acceptAction.title = NSLocalizedString(@"ANSWER_CALL_BUTTON_TITLE", @"");
|
|
|
|
|
acceptAction.activationMode = UIUserNotificationActivationModeForeground;
|
|
|
|
|
acceptAction.destructive = NO;
|
|
|
|
|
acceptAction.authenticationRequired = NO;
|
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationAction *declineAction = [UIMutableUserNotificationAction new];
|
|
|
|
|
declineAction.identifier = PushManagerActionsDeclineCall;
|
|
|
|
|
declineAction.title = NSLocalizedString(@"REJECT_CALL_BUTTON_TITLE", @"");
|
|
|
|
|
declineAction.activationMode = UIUserNotificationActivationModeBackground;
|
|
|
|
|
declineAction.destructive = NO;
|
|
|
|
|
declineAction.authenticationRequired = NO;
|
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationCategory *callCategory = [UIMutableUserNotificationCategory new];
|
|
|
|
|
callCategory.identifier = PushManagerCategoriesIncomingCall;
|
|
|
|
|
[callCategory setActions:@[ acceptAction, declineAction ] forContext:UIUserNotificationActionContextMinimal];
|
|
|
|
|
[callCategory setActions:@[ acceptAction, declineAction ] forContext:UIUserNotificationActionContextDefault];
|
|
|
|
|
|
|
|
|
|
return callCategory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (UIUserNotificationCategory *)signalMissedCallCategory
|
|
|
|
|
{
|
|
|
|
|
UIMutableUserNotificationAction *callBackAction = [UIMutableUserNotificationAction new];
|
|
|
|
|
callBackAction.identifier = PushManagerActionsCallBack;
|
2017-02-02 23:42:06 +01:00
|
|
|
|
callBackAction.title = [CallStrings callBackButtonTitle];
|
2016-11-12 18:22:29 +01:00
|
|
|
|
callBackAction.activationMode = UIUserNotificationActivationModeForeground;
|
|
|
|
|
callBackAction.destructive = NO;
|
|
|
|
|
callBackAction.authenticationRequired = YES;
|
|
|
|
|
|
2017-05-31 17:49:30 +02:00
|
|
|
|
UIMutableUserNotificationCategory *missedCallCategory = [UIMutableUserNotificationCategory new];
|
|
|
|
|
missedCallCategory.identifier = PushManagerCategoriesMissedCall;
|
|
|
|
|
[missedCallCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextMinimal];
|
|
|
|
|
[missedCallCategory setActions:@[ callBackAction ] forContext:UIUserNotificationActionContextDefault];
|
2016-11-12 18:22:29 +01:00
|
|
|
|
|
2017-05-31 17:49:30 +02:00
|
|
|
|
return missedCallCategory;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-07 00:59:38 +02:00
|
|
|
|
- (UIUserNotificationCategory *)signalMissedCallWithNoLongerVerifiedIdentityChangeCategory
|
2017-05-31 17:49:30 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationAction *showThreadAction = [UIMutableUserNotificationAction new];
|
|
|
|
|
showThreadAction.identifier = PushManagerActionsShowThread;
|
|
|
|
|
showThreadAction.title = [CallStrings showThreadButtonTitle];
|
|
|
|
|
showThreadAction.activationMode = UIUserNotificationActivationModeForeground;
|
|
|
|
|
showThreadAction.destructive = NO;
|
|
|
|
|
showThreadAction.authenticationRequired = YES;
|
|
|
|
|
|
|
|
|
|
UIMutableUserNotificationCategory *rejectedCallCategory = [UIMutableUserNotificationCategory new];
|
2017-06-07 00:59:38 +02:00
|
|
|
|
rejectedCallCategory.identifier = PushManagerCategoriesMissedCallFromNoLongerVerifiedIdentity;
|
|
|
|
|
[rejectedCallCategory setActions:@[ showThreadAction ] forContext:UIUserNotificationActionContextMinimal];
|
|
|
|
|
[rejectedCallCategory setActions:@[ showThreadAction ] forContext:UIUserNotificationActionContextDefault];
|
2017-05-31 17:49:30 +02:00
|
|
|
|
|
|
|
|
|
return rejectedCallCategory;
|
2014-10-07 00:04:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-12 18:22:29 +01:00
|
|
|
|
#pragma mark Util
|
|
|
|
|
|
2015-12-22 12:45:09 +01:00
|
|
|
|
- (int)allNotificationTypes {
|
2014-11-19 21:17:53 +01:00
|
|
|
|
return UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge;
|
2014-09-15 01:32:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
- (UIUserNotificationSettings *)userNotificationSettings
|
2016-10-10 22:02:09 +02:00
|
|
|
|
{
|
2018-08-27 18:51:32 +02:00
|
|
|
|
OWSLogDebug(@"registering user notification settings");
|
2017-06-07 00:59:38 +02:00
|
|
|
|
UIUserNotificationSettings *settings = [UIUserNotificationSettings
|
|
|
|
|
settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
|
|
|
|
|
categories:[NSSet setWithObjects:[self fullNewMessageNotificationCategory],
|
2017-06-23 19:55:21 +02:00
|
|
|
|
[self fullNewMessageNoLongerVerifiedNotificationCategory],
|
2017-06-07 00:59:38 +02:00
|
|
|
|
[self signalIncomingCallCategory],
|
|
|
|
|
[self signalMissedCallCategory],
|
|
|
|
|
[self signalMissedCallWithNoLongerVerifiedIdentityChangeCategory],
|
|
|
|
|
nil]];
|
2016-10-10 22:02:09 +02:00
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
return settings;
|
2015-04-07 17:22:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
- (BOOL)applicationIsActive {
|
|
|
|
|
UIApplication *app = [UIApplication sharedApplication];
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
if (app.applicationState == UIApplicationStateActive) {
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2015-12-22 12:45:09 +01:00
|
|
|
|
|
2015-04-14 21:49:00 +02:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
// TODO: consolidate notification tracking with NotificationsManager, which also maintains a list of notifications.
|
2017-04-05 17:13:09 +02:00
|
|
|
|
- (void)presentNotification:(UILocalNotification *)notification checkForCancel:(BOOL)checkForCancel
|
|
|
|
|
{
|
2018-02-16 02:45:28 +01:00
|
|
|
|
notification.alertBody = notification.alertBody.filterStringForDisplay;
|
|
|
|
|
|
2017-04-14 21:27:31 +02:00
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
|
|
|
|
if (checkForCancel && threadId != nil) {
|
2017-11-16 15:54:55 +01:00
|
|
|
|
if ([[OWSDeviceManager sharedManager] hasReceivedSyncMessageInLastSeconds:60.f]) {
|
|
|
|
|
// "If you’ve heard from desktop in last minute, wait 5 seconds."
|
|
|
|
|
//
|
|
|
|
|
// This provides a window in which we can cancel notifications
|
|
|
|
|
// already viewed on desktop before they are presented here.
|
|
|
|
|
const CGFloat kDelaySeconds = 5.f;
|
|
|
|
|
notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:kDelaySeconds];
|
|
|
|
|
} else {
|
|
|
|
|
notification.fireDate = [NSDate new];
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-14 21:27:31 +02:00
|
|
|
|
notification.timeZone = [NSTimeZone localTimeZone];
|
|
|
|
|
}
|
2017-04-12 16:03:09 +02:00
|
|
|
|
|
2017-04-14 21:27:31 +02:00
|
|
|
|
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
|
|
|
|
|
[self.currentNotifications addObject:notification];
|
|
|
|
|
});
|
2015-09-01 19:22:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
Rework push registration
== Account Registration ==
Not complete until push tokens are uploaded
== Remote Notifications Registration ==
Extracted from PushManager
- wait for notification-settings registration to complete before
requesting push tokens, otherwise it's possible token requests will
be ignored.
- Less state required for push notification callbacks, specifically, we
no longer need to ensure we've created a promise before the
registration delegate methods get called.
- no more TOCFuture in Signal-iOS (still in SSK for now). It's not in
cases of inexplicable behavior - one a recently, push notification
premature free, in redphone, and more popular use, and I've seen two
futures inexplicably being nil. Instead, let's consolidate around
PromiseKit for popularly used, maintained, strongly-typed futures.
- separate logic for registering for vanilla push/voip notifications
(few dependencies) from responding to UILocalNotifications (lots of
dependencies). Ultimately I'd like to consolidate the remaining
UILocalNotifications logic with the existing NotificationsManager
== Misc ==
more debug logging
more uniform logging
remove stale logic around newly registered user
// FREEBIE
2017-09-20 23:47:12 +02:00
|
|
|
|
// TODO: consolidate notification tracking with NotificationsManager, which also maintains a list of notifications.
|
2017-04-14 21:27:31 +02:00
|
|
|
|
- (void)cancelNotificationsWithThreadId:(NSString *)threadId
|
|
|
|
|
{
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
NSMutableArray *toDelete = [NSMutableArray array];
|
|
|
|
|
[self.currentNotifications
|
|
|
|
|
enumerateObjectsUsingBlock:^(UILocalNotification *notif, NSUInteger idx, BOOL *stop) {
|
|
|
|
|
if ([notif.userInfo[Signal_Thread_UserInfo_Key] isEqualToString:threadId]) {
|
|
|
|
|
[[UIApplication sharedApplication] cancelLocalNotification:notif];
|
|
|
|
|
[toDelete addObject:notif];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
[self.currentNotifications removeObjectsInArray:toDelete];
|
|
|
|
|
});
|
2015-09-01 19:22:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-01 07:53:58 +02:00
|
|
|
|
@end
|