From 2b9ce77df40dca150f6701682b87f8ace95c1200 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 10:31:16 +0100 Subject: [PATCH 1/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. This fixes the case logged at https://riot.im/bugreports/listing/2017-12-27/163238/console.2.log.gz --- Riot/AppDelegate.m | 84 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 6 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index b8782185c..d576a9944 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1210,8 +1210,8 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } failure:^(NSError *error) { - NSLog(@"[AppDelegate][Push] launchBackgroundSync: the background sync fails"); - + NSLog(@"[AppDelegate][Push] launchBackgroundSync: the background sync failed for %tu pending notifications. Error: %@ (%@)", self.incomingPushEventIds[@(account.mxSession.hash)].count, error.domain, @(error.code)); + }]; } } @@ -1249,7 +1249,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Ignore redacted event. if (event.isRedactedEvent) { - NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip redacted event"); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip redacted event. Event id: %@", event.eventId); continue; } @@ -1259,7 +1259,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Ignore call invite when callkit is active. if (isCallKitActive) { - NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip call event"); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip call event. Event id: %@", event.eventId); continue; } else @@ -1285,7 +1285,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN MXEvent *readReceiptEvent = [account.mxSession.store eventWithEventId:readReceipt.eventId inRoom:roomId]; if (event.originServerTs <= readReceiptEvent.originServerTs) { - NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip already read event"); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip already read event. Event id: %@", event.eventId); continue; } } @@ -1444,6 +1444,64 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN return notificationBody; } +- (void)handleLocalNotificationsForFailedSync:(MXSession*)mxSession events:(NSArray *)events +{ + NSString *userId = mxSession.matrixRestClient.credentials.userId; + + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: %@", userId); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: eventsToNotify: %@", eventsToNotify[@(mxSession.hash)]); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: incomingPushEventIds: %@", self.incomingPushEventIds[@(mxSession.hash)]); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: events: %@", events); + + if (events.count) + { + return; + } + + for (NSString *eventId in events) + { + if ([self displayedFailedSyncLocalNotificationForEvent:eventId andUser:userId]) + { + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Notification for event %@ already exists", eventId); + continue; + } + + UILocalNotification *localNotificationForFailedSync = [[UILocalNotification alloc] init]; + localNotificationForFailedSync.userInfo = @{ + @"type": @"failed_sync", + @"event_id": eventId, + @"user_id": userId + }; + + localNotificationForFailedSync.alertBody = [self notificationBodyForFailedSyncEvent:eventId inMatrixSession:mxSession]; + + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Display notification for event %@", eventId); + [[UIApplication sharedApplication] scheduleLocalNotification:localNotificationForFailedSync]; + } +} + +- (UILocalNotification*)displayedFailedSyncLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId +{ + UILocalNotification *localNotificationForFailedSync; + for (UILocalNotification *localNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) + { + if ([localNotification.userInfo[@"type"] isEqualToString:@"failed_sync"] + && [localNotification.userInfo[@"event_id"] isEqualToString:eventId] + && [localNotification.userInfo[@"user_id"] isEqualToString:userId]) + { + localNotificationForFailedSync = localNotification; + break; + } + } + + return localNotificationForFailedSync; +} + +- (nullable NSString *)notificationBodyForFailedSyncEvent:(NSString *)eventId inMatrixSession:(MXSession*)mxSession +{ + return @"todo"; +} + - (void)refreshApplicationIconBadgeNumber { // Consider the total number of missed discussions including the invites. @@ -1985,10 +2043,24 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN // Check whether some push notifications are pending for this session. if (self.incomingPushEventIds[@(mxSession.hash)].count) { - NSLog(@"[AppDelegate][Push] relaunch a background sync for the kMXSessionStateDidChangeNotification pending incoming push"); + NSLog(@"[AppDelegate][Push] relaunch a background sync for %tu kMXSessionStateDidChangeNotification pending incoming pushes", self.incomingPushEventIds[@(mxSession.hash)].count); [self launchBackgroundSync]; } } + else if (mxSession.state == MXSessionStateInitialSyncFailed) + { + // Display failure sync notifications for pending events if any + if (self.incomingPushEventIds[@(mxSession.hash)].count) + { + NSLog(@"[AppDelegate][Push] initial sync failed with %tu pending incoming pushes", self.incomingPushEventIds[@(mxSession.hash)].count); + + // Trigger local notifications when the sync with HS fails + [self handleLocalNotificationsForFailedSync:mxSession events:self.incomingPushEventIds[@(mxSession.hash)]]; + + // Update app icon badge number + [self refreshApplicationIconBadgeNumber]; + } + } } else if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) { From b17693d7d2f5e6808ce4bda4ecd9cdc8bb114f6e Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 13:04:57 +0100 Subject: [PATCH 2/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. Build the string for the notification --- Riot/AppDelegate.m | 108 ++++++++++++++++++++--- Riot/Assets/en.lproj/Localizable.strings | 6 ++ 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index d576a9944..bb21b013b 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -177,6 +177,14 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN */ NSMutableDictionary *> *eventsToNotify; + /** + Cache for payloads received with incoming push notifications. + The key is the event id. The value, the payload. + Note: for the moment, objets in this dictionary are never removed but + the impact on memory is low. + */ + NSMutableDictionary *incomingPushPayloads; + /** Currently displayed "Call not supported" alert. */ @@ -395,6 +403,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN callEventsListeners = [NSMutableDictionary dictionary]; notificationListenerBlocks = [NSMutableDictionary dictionary]; eventsToNotify = [NSMutableDictionary dictionary]; + incomingPushPayloads = [NSMutableDictionary dictionary]; // To simplify navigation into the app, we retrieve here the main navigation controller and the tab bar controller. UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; @@ -1085,6 +1094,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN if (roomId.length) { // TODO retrieve the right matrix session + // We can use the "user_id" value in notification.userInfo //************** // Patch consider the first session which knows the room id @@ -1165,6 +1175,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { [array addObject:eventId]; } + + // Cache payload for further usage + incomingPushPayloads[eventId] = payload.dictionaryPayload; } else { @@ -1238,6 +1251,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSString *roomId = eventDict[@"room_id"]; BOOL checkReadEvent = YES; MXEvent *event; + + // Ignore event already notified to the user + if ([self displayedFailedSyncLocalNotificationForEvent:eventId andUser:account.mxCredentials.userId]) + { + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event already displayed in a failed sync notif. Event id: %@", eventId); + continue; + } if (eventId && roomId) { @@ -1303,7 +1323,11 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; eventNotification.alertBody = notificationBody; - eventNotification.userInfo = @{ @"room_id" : event.roomId }; + eventNotification.userInfo = @{ + @"room_id": event.roomId, + @"event_id": event.eventId, + @"user_id": account.mxCredentials.userId + }; // Set sound name based on the value provided in action of MXPushRule for (MXPushRuleAction *action in rule.actions) @@ -1444,6 +1468,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN return notificationBody; } +/** + Display limited notifications for events the app was not able to get data + (because of /sync failure). + + @param mxSession the matrix session where the /sync failed. + @param events the list of events id we did not get data. + */ - (void)handleLocalNotificationsForFailedSync:(MXSession*)mxSession events:(NSArray *)events { NSString *userId = mxSession.matrixRestClient.credentials.userId; @@ -1466,13 +1497,27 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN continue; } - UILocalNotification *localNotificationForFailedSync = [[UILocalNotification alloc] init]; - localNotificationForFailedSync.userInfo = @{ - @"type": @"failed_sync", - @"event_id": eventId, - @"user_id": userId - }; + // Build notification user info + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:@{ + @"type": @"failed_sync", + @"event_id": eventId, + @"user_id": userId + }]; + // Add the room_id so that user will open the room when tapping on the notif + NSDictionary *payload = incomingPushPayloads[eventId]; + NSString *roomId = payload[@"room_id"]; + if (roomId) + { + userInfo[@"room_id"] = roomId; + } + else + { + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: room_id is missing for event %@ in payload %@", eventId, payload); + } + + UILocalNotification *localNotificationForFailedSync = [[UILocalNotification alloc] init]; + localNotificationForFailedSync.userInfo = userInfo; localNotificationForFailedSync.alertBody = [self notificationBodyForFailedSyncEvent:eventId inMatrixSession:mxSession]; NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Display notification for event %@", eventId); @@ -1480,6 +1525,50 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } } +/** + Build the body of the "limited" notification to display to the user. + + @param eventId the id of the event the app failed to get data. + @param mxSession the matrix session where the /sync failed. + @return the string to display in the local notification. + */ +- (nullable NSString *)limited otificationBodyForEvent:(MXEvent *)event pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account +- (nullable NSString *)notificationBodyForFailedSyncEvent:(NSString *)eventId inMatrixSession:(MXSession*)mxSession +{ + NSString *notificationBody; + + NSString *roomDisplayName; + + NSDictionary *payload = incomingPushPayloads[eventId]; + NSString *roomId = payload[@"room_id"]; + if (roomId) + { + MXRoomSummary *roomSummary = [mxSession roomSummaryWithRoomId:roomId]; + if (roomSummary) + { + roomDisplayName = roomSummary.displayname; + } + } + + if (roomDisplayName.length) + { + [NSString stringWithFormat:NSLocalizedString(@"SINGLE_UNREAD_IN_ROOM", nil), roomDisplayName]; + } + else + { + [NSString stringWithFormat:NSLocalizedString(@"SINGLE_UNREAD", nil), roomDisplayName]; + } + + return notificationBody; +} + +/** + Return already displayed notification for a failed sync. + + @param eventId the id of the event attached to the notification to find. + @param userId the id of the user attached to the notification to find. + @return the local notification if any. + */ - (UILocalNotification*)displayedFailedSyncLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId { UILocalNotification *localNotificationForFailedSync; @@ -1497,11 +1586,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN return localNotificationForFailedSync; } -- (nullable NSString *)notificationBodyForFailedSyncEvent:(NSString *)eventId inMatrixSession:(MXSession*)mxSession -{ - return @"todo"; -} - - (void)refreshApplicationIconBadgeNumber { // Consider the total number of missed discussions including the invites. diff --git a/Riot/Assets/en.lproj/Localizable.strings b/Riot/Assets/en.lproj/Localizable.strings index 2c7af440a..33e5d39f4 100644 --- a/Riot/Assets/en.lproj/Localizable.strings +++ b/Riot/Assets/en.lproj/Localizable.strings @@ -44,6 +44,12 @@ /* New action message from a specific person in a named room. */ "IMAGE_FROM_USER_IN_ROOM" = "%@ posted a picture %@ in %@"; +/* A single unread message in a room */ +"SINGLE_UNREAD_IN_ROOM" = "You received a message in %@"; + +/* A single unread message */ +"SINGLE_UNREAD" = "You received a message"; + /** Coalesced messages **/ /* Multiple unread messages in a room */ From 3e5172a2499133338a0dea9dda360068b14f0161 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 13:22:29 +0100 Subject: [PATCH 3/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. Renaming --- Riot/AppDelegate.m | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index bb21b013b..35834ba9b 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1469,13 +1469,15 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } /** - Display limited notifications for events the app was not able to get data + Display "limited" notifications for events the app was not able to get data (because of /sync failure). + In this situation, we are only able to display "You received a message in %@". + @param mxSession the matrix session where the /sync failed. @param events the list of events id we did not get data. */ -- (void)handleLocalNotificationsForFailedSync:(MXSession*)mxSession events:(NSArray *)events +- (void)handleLimitedLocalNotifications:(MXSession*)mxSession events:(NSArray *)events { NSString *userId = mxSession.matrixRestClient.credentials.userId; @@ -1518,7 +1520,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN UILocalNotification *localNotificationForFailedSync = [[UILocalNotification alloc] init]; localNotificationForFailedSync.userInfo = userInfo; - localNotificationForFailedSync.alertBody = [self notificationBodyForFailedSyncEvent:eventId inMatrixSession:mxSession]; + localNotificationForFailedSync.alertBody = [self limitedNotificationBodyForEvent:eventId inMatrixSession:mxSession]; NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Display notification for event %@", eventId); [[UIApplication sharedApplication] scheduleLocalNotification:localNotificationForFailedSync]; @@ -1532,8 +1534,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN @param mxSession the matrix session where the /sync failed. @return the string to display in the local notification. */ -- (nullable NSString *)limited otificationBodyForEvent:(MXEvent *)event pushRule:(MXPushRule*)rule inAccount:(MXKAccount*)account -- (nullable NSString *)notificationBodyForFailedSyncEvent:(NSString *)eventId inMatrixSession:(MXSession*)mxSession +- (nullable NSString *)limitedNotificationBodyForEvent:(NSString *)eventId inMatrixSession:(MXSession*)mxSession { NSString *notificationBody; @@ -2139,7 +2140,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"[AppDelegate][Push] initial sync failed with %tu pending incoming pushes", self.incomingPushEventIds[@(mxSession.hash)].count); // Trigger local notifications when the sync with HS fails - [self handleLocalNotificationsForFailedSync:mxSession events:self.incomingPushEventIds[@(mxSession.hash)]]; + [self handleLimitedLocalNotifications:mxSession events:self.incomingPushEventIds[@(mxSession.hash)]]; // Update app icon badge number [self refreshApplicationIconBadgeNumber]; From 7776a92c23bd426f8cea8584af6fb59a886d8529 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 13:33:55 +0100 Subject: [PATCH 4/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. Show notif on /sync failure callback too --- Riot/AppDelegate.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 35834ba9b..0996d77f4 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1200,9 +1200,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { NSLog(@"[AppDelegate][Push] launchBackgroundSync"); __weak typeof(self) weakSelf = self; + + NSMutableArray *incomingPushEventIds = self.incomingPushEventIds[@(account.mxSession.hash)]; + NSMutableArray *incomingPushEventIdsCopy = [incomingPushEventIds copy]; // Flush all the pending push notifications for this session. - [self.incomingPushEventIds[@(account.mxSession.hash)] removeAllObjects]; + [incomingPushEventIds removeAllObjects]; [account backgroundSync:20000 success:^{ @@ -1223,7 +1226,13 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } failure:^(NSError *error) { - NSLog(@"[AppDelegate][Push] launchBackgroundSync: the background sync failed for %tu pending notifications. Error: %@ (%@)", self.incomingPushEventIds[@(account.mxSession.hash)].count, error.domain, @(error.code)); + NSLog(@"[AppDelegate][Push] launchBackgroundSync: the background sync failed. Error: %@ (%@). incomingPushEventIdsCopy: %@ - self.incomingPushEventIds: %@", error.domain, @(error.code), incomingPushEventIdsCopy, incomingPushEventIds); + + // Trigger local notifications when the sync with HS fails + [self handleLimitedLocalNotifications:account.mxSession events:incomingPushEventIdsCopy]; + + // Update app icon badge number + [self refreshApplicationIconBadgeNumber]; }]; } From f9f9f5a0e4a756d1626c82f452645ac370718553 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 13:40:55 +0100 Subject: [PATCH 5/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. wording --- Riot/AppDelegate.m | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index 0996d77f4..e3b10cfa3 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -180,7 +180,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN /** Cache for payloads received with incoming push notifications. The key is the event id. The value, the payload. - Note: for the moment, objets in this dictionary are never removed but + Note: for the moment, objects in this dictionary are never removed but the impact on memory is low. */ NSMutableDictionary *incomingPushPayloads; @@ -1228,7 +1228,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"[AppDelegate][Push] launchBackgroundSync: the background sync failed. Error: %@ (%@). incomingPushEventIdsCopy: %@ - self.incomingPushEventIds: %@", error.domain, @(error.code), incomingPushEventIdsCopy, incomingPushEventIds); - // Trigger local notifications when the sync with HS fails + // Trigger limited local notifications when the sync with HS fails [self handleLimitedLocalNotifications:account.mxSession events:incomingPushEventIdsCopy]; // Update app icon badge number @@ -1262,7 +1262,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN MXEvent *event; // Ignore event already notified to the user - if ([self displayedFailedSyncLocalNotificationForEvent:eventId andUser:account.mxCredentials.userId]) + if ([self displayedLimitedLocalNotificationForEvent:eventId andUser:account.mxCredentials.userId]) { NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event already displayed in a failed sync notif. Event id: %@", eventId); continue; @@ -1502,7 +1502,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN for (NSString *eventId in events) { - if ([self displayedFailedSyncLocalNotificationForEvent:eventId andUser:userId]) + if ([self displayedLimitedLocalNotificationForEvent:eventId andUser:userId]) { NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Notification for event %@ already exists", eventId); continue; @@ -1537,7 +1537,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } /** - Build the body of the "limited" notification to display to the user. + Build the body for the "limited" notification to display to the user. @param eventId the id of the event the app failed to get data. @param mxSession the matrix session where the /sync failed. @@ -1573,27 +1573,27 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } /** - Return already displayed notification for a failed sync. + Return the already displayed limited notification for an event. @param eventId the id of the event attached to the notification to find. @param userId the id of the user attached to the notification to find. @return the local notification if any. */ -- (UILocalNotification*)displayedFailedSyncLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId +- (UILocalNotification*)displayedLimitedLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId { - UILocalNotification *localNotificationForFailedSync; + UILocalNotification *limitedLocalNotification; for (UILocalNotification *localNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) { if ([localNotification.userInfo[@"type"] isEqualToString:@"failed_sync"] && [localNotification.userInfo[@"event_id"] isEqualToString:eventId] && [localNotification.userInfo[@"user_id"] isEqualToString:userId]) { - localNotificationForFailedSync = localNotification; + limitedLocalNotification = localNotification; break; } } - return localNotificationForFailedSync; + return limitedLocalNotification; } - (void)refreshApplicationIconBadgeNumber @@ -2148,7 +2148,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { NSLog(@"[AppDelegate][Push] initial sync failed with %tu pending incoming pushes", self.incomingPushEventIds[@(mxSession.hash)].count); - // Trigger local notifications when the sync with HS fails + // Trigger limited local notifications when the sync with HS fails [self handleLimitedLocalNotifications:mxSession events:self.incomingPushEventIds[@(mxSession.hash)]]; // Update app icon badge number From c63443602293d04a5047618b9535f99e98a318b5 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 15:20:12 +0100 Subject: [PATCH 6/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. Fixed easy Giom's remarks --- Riot/AppDelegate.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index e3b10cfa3..ee0321813 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -180,8 +180,6 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN /** Cache for payloads received with incoming push notifications. The key is the event id. The value, the payload. - Note: for the moment, objects in this dictionary are never removed but - the impact on memory is low. */ NSMutableDictionary *incomingPushPayloads; @@ -548,6 +546,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN { [array removeAllObjects]; } + [incomingPushPayloads removeAllObjects]; // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. @@ -1495,7 +1494,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: incomingPushEventIds: %@", self.incomingPushEventIds[@(mxSession.hash)]); NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: events: %@", events); - if (events.count) + if (!events.count) { return; } From af6bdd9d368aba3538f5e4daa856adb49a72f1c7 Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 29 Dec 2017 16:43:20 +0100 Subject: [PATCH 7/7] Missing Push Notifications (#1696): Show a notification even if the app fails to sync with its hs to get all data. Fix last Giom's remark: Make sure we do not display a "limited" notif for an event with already a "full" notif. --- Riot/AppDelegate.m | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index ee0321813..a9d651a71 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -1261,9 +1261,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN MXEvent *event; // Ignore event already notified to the user - if ([self displayedLimitedLocalNotificationForEvent:eventId andUser:account.mxCredentials.userId]) + if ([self displayedLocalNotificationForEvent:eventId andUser:account.mxCredentials.userId type:nil]) { - NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event already displayed in a failed sync notif. Event id: %@", eventId); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event already displayed in a notification. Event id: %@", eventId); continue; } @@ -1332,6 +1332,7 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN UILocalNotification *eventNotification = [[UILocalNotification alloc] init]; eventNotification.alertBody = notificationBody; eventNotification.userInfo = @{ + @"type": @"full", @"room_id": event.roomId, @"event_id": event.eventId, @"user_id": account.mxCredentials.userId @@ -1501,15 +1502,16 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN for (NSString *eventId in events) { - if ([self displayedLimitedLocalNotificationForEvent:eventId andUser:userId]) + // Ignore event already notified to the user + if ([self displayedLocalNotificationForEvent:eventId andUser:userId type:nil]) { - NSLog(@"[AppDelegate][Push] handleLocalNotificationsForFailedSync: Notification for event %@ already exists", eventId); + NSLog(@"[AppDelegate][Push] handleLocalNotificationsForAccount: Skip event already displayed in a notification. Event id: %@", eventId); continue; } // Build notification user info NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:@{ - @"type": @"failed_sync", + @"type": @"limited", @"event_id": eventId, @"user_id": userId }]; @@ -1572,20 +1574,21 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN } /** - Return the already displayed limited notification for an event. + Return the already displayed notification for an event. @param eventId the id of the event attached to the notification to find. @param userId the id of the user attached to the notification to find. + @param type the type of notification. @"full" or @"limited". nil for any type. @return the local notification if any. */ -- (UILocalNotification*)displayedLimitedLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId +- (UILocalNotification*)displayedLocalNotificationForEvent:(NSString*)eventId andUser:(NSString*)userId type:(NSString*)type { UILocalNotification *limitedLocalNotification; for (UILocalNotification *localNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) { - if ([localNotification.userInfo[@"type"] isEqualToString:@"failed_sync"] - && [localNotification.userInfo[@"event_id"] isEqualToString:eventId] - && [localNotification.userInfo[@"user_id"] isEqualToString:userId]) + if ([localNotification.userInfo[@"event_id"] isEqualToString:eventId] + && [localNotification.userInfo[@"user_id"] isEqualToString:userId] + && (!type || [localNotification.userInfo[@"type"] isEqualToString:type])) { limitedLocalNotification = localNotification; break;