From de5ea4e2fb440ca8b99a71ddedd2422d7d026752 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Thu, 10 Jun 2021 11:43:08 +0300 Subject: [PATCH 1/5] Handle app inactive state too --- .../PushNotificationService.m | 115 +++++++++--------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index 350cd564f4..b1b3ce6385 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -178,16 +178,17 @@ - (void)applicationWillResignActive { [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; [[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:nil]; -} - -- (void)applicationDidEnterBackground -{ if (_pushNotificationStore.pushKitToken) { self.shouldReceiveVoIPPushes = YES; } } +- (void)applicationDidEnterBackground +{ + +} + - (void)applicationDidBecomeActive { [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; @@ -547,83 +548,81 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; [[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:roomId]; - if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) + if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) { - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is in bg"); + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is active. There is something wrong."); + completion(); + return; + } + + if (@available(iOS 13.0, *)) + { + // for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here. + MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId]; + // remove event + [_pushNotificationStore removeCallInviteWithEventId:eventId]; + MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject; + // when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it. + [[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session]; - if (@available(iOS 13.0, *)) + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: callInvite: %@", callInvite); + + if (callInvite) { - // for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here. - MXEvent *callInvite = [_pushNotificationStore callInviteForEventId:eventId]; - // remove event - [_pushNotificationStore removeCallInviteWithEventId:eventId]; - MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject; - // when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it. - [[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session]; + // We're using this dispatch_group to continue event stream after cache fully processed. + dispatch_group_t dispatchGroup = dispatch_group_create(); - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: callInvite: %@", callInvite); + dispatch_group_enter(dispatchGroup); + // Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop. + // 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously. + [session handleBackgroundSyncCacheIfRequiredWithCompletion:^{ + dispatch_group_leave(dispatchGroup); + }]; - if (callInvite) + if (callInvite.eventType == MXEventTypeCallInvite) { - // We're using this dispatch_group to continue event stream after cache fully processed. - dispatch_group_t dispatchGroup = dispatch_group_create(); - - dispatch_group_enter(dispatchGroup); - // Not continuing in completion block here, because PushKit mandates reporting a new call in the same run loop. - // 'handleBackgroundSyncCacheIfRequiredWithCompletion' is processing to-device events synchronously. - [session handleBackgroundSyncCacheIfRequiredWithCompletion:^{ - dispatch_group_leave(dispatchGroup); - }]; - - if (callInvite.eventType == MXEventTypeCallInvite) - { - // process the call invite synchronously - [session.callManager handleCallEvent:callInvite]; - MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content]; - MXCall *call = [session.callManager callWithCallId:content.callId]; - if (call) - { - [session.callManager.callKitAdapter reportIncomingCall:call]; - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId); - - // Wait for the sync response in cache to be processed for data integrity. - dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ - // After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user. - [self launchBackgroundSync]; - }); - } - else - { - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId); - } - } - else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] || - [callInvite.type isEqualToString:kWidgetModularEventTypeString]) + // process the call invite synchronously + [session.callManager handleCallEvent:callInvite]; + MXCallInviteEventContent *content = [MXCallInviteEventContent modelFromJSON:callInvite.content]; + MXCall *call = [session.callManager callWithCallId:content.callId]; + if (call) { - [[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite - inSession:session]; + [session.callManager.callKitAdapter reportIncomingCall:call]; + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Reporting new call in room %@ for the event: %@", roomId, eventId); + + // Wait for the sync response in cache to be processed for data integrity. + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + // After reporting the call, we can continue async. Launch a background sync to handle call answers/declines on other devices of the user. + [self launchBackgroundSync]; + }); } else { - // It's a serious error. There is nothing to avoid iOS to kill us here. - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId); + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Error on call object on room %@ for the event: %@", roomId, eventId); } } + else if ([callInvite.type isEqualToString:kWidgetMatrixEventTypeString] || + [callInvite.type isEqualToString:kWidgetModularEventTypeString]) + { + [[AppDelegate theDelegate].callPresenter processWidgetEvent:callInvite + inSession:session]; + } else { // It's a serious error. There is nothing to avoid iOS to kill us here. - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the callInvite event for the eventId: %@. There is something wrong.", eventId); + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: We have an unknown type of event for %@. There is something wrong.", eventId); } } else { - // below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit. - [self launchBackgroundSync]; + // It's a serious error. There is nothing to avoid iOS to kill us here. + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the callInvite event for the eventId: %@. There is something wrong.", eventId); } } else { - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is not in bg. There is something wrong."); + // below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit. + [self launchBackgroundSync]; } completion(); From 7f534738ff3cdedf38c6d29653a20c14f4a675d3 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 11 Jun 2021 14:37:53 +0300 Subject: [PATCH 2/5] Handle app state better --- .../PushNotificationService.m | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index b1b3ce6385..c4ed917ff6 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -548,13 +548,6 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa [[UNUserNotificationCenter currentNotificationCenter] removeUnwantedNotifications]; [[UNUserNotificationCenter currentNotificationCenter] removeCallNotificationsFor:roomId]; - if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) - { - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: application is active. There is something wrong."); - completion(); - return; - } - if (@available(iOS 13.0, *)) { // for iOS 13, we'll just report the incoming call in the same runloop. It means we cannot call an async API here. @@ -565,7 +558,7 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa // when we have a VoIP push while the application is killed, session.callManager will not be ready yet. Configure it. [[AppDelegate theDelegate] configureCallManagerIfRequiredForSession:session]; - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: callInvite: %@", callInvite); + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, callInvite: %@", callInvite); if (callInvite) { @@ -616,11 +609,20 @@ - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayloa else { // It's a serious error. There is nothing to avoid iOS to kill us here. - MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13 and in bg, but we don't have the callInvite event for the eventId: %@. There is something wrong.", eventId); + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: iOS 13+, but we don't have the callInvite event for the eventId: %@.", eventId); } } else { + if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) + { + // below iOS 13, we don't have to report a call immediately. + // We can wait for a call invite from event stream and process. + MXLogDebug(@"[PushNotificationService] didReceiveIncomingPushWithPayload: Below iOS 13 and active app. Do nothing."); + completion(); + return; + } + // below iOS 13, we can call an async API. After background sync, we'll hopefully fetch the call invite and report a new call to the CallKit. [self launchBackgroundSync]; } From 4f9cb2e1791e18e981732f4e3c605507f33e9d27 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 11 Jun 2021 14:38:07 +0300 Subject: [PATCH 3/5] Enhance logs --- .../PushNotification/PushNotificationService.m | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Riot/Managers/PushNotification/PushNotificationService.m b/Riot/Managers/PushNotification/PushNotificationService.m index c4ed917ff6..bef062452a 100644 --- a/Riot/Managers/PushNotification/PushNotificationService.m +++ b/Riot/Managers/PushNotification/PushNotificationService.m @@ -228,6 +228,8 @@ - (void)setShouldReceiveVoIPPushes:(BOOL)shouldReceiveVoIPPushes { _shouldReceiveVoIPPushes = shouldReceiveVoIPPushes; + MXLogDebug(@"[PushNotificationService] setShouldReceiveVoIPPushes: %u", _shouldReceiveVoIPPushes) + if (_shouldReceiveVoIPPushes && _pushNotificationStore.pushKitToken) { MXSession *session = [AppDelegate theDelegate].mxSessions.firstObject; @@ -257,16 +259,25 @@ - (void)setShouldReceiveVoIPPushes:(BOOL)shouldReceiveVoIPPushes } else { - _pushRegistry.delegate = nil; + [self deconfigurePushKit]; } } - (void)configurePushKit { + MXLogDebug(@"[PushNotificationService] configurePushKit") + _pushRegistry.delegate = self; _pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; } +- (void)deconfigurePushKit +{ + MXLogDebug(@"[PushNotificationService] deconfigurePushKit") + + _pushRegistry.delegate = nil; +} + - (void)removePusher:(MXPusher*)pusher inSession:(MXSession*)session { MXLogDebug(@"[PushNotificationService][Push] removePusher: %@", pusher.appId); From 5812750c5036162e91b24f13e7c5f38d2698a386 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 11 Jun 2021 15:45:49 +0300 Subject: [PATCH 4/5] Do not terminate the app according to isProtectedDataAvailable --- Riot/Modules/Application/LegacyAppDelegate.m | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index e7057271e3..5e8dd9d34f 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -369,12 +369,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: isProtectedDataAvailable: %@", @([application isProtectedDataAvailable])); - if (![application isProtectedDataAvailable]) - { - MXLogDebug(@"[AppDelegate] didFinishLaunchingWithOptions: Terminating the app because protected data not available"); - exit(0); - } - _configuration = [AppConfiguration new]; self.appInfo = AppInfo.current; From ff6b4bcde109d8710d7adb5271b27fb224ecdf37 Mon Sep 17 00:00:00 2001 From: ismailgulek Date: Fri, 11 Jun 2021 16:01:04 +0300 Subject: [PATCH 5/5] Update CHANGES.rst --- CHANGES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index bd72b4413e..47c0dbe116 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,8 @@ Changes to be released in next version * RoomDirectCallStatusBubbleCell: Fix crash when entering a DM after a call is hung-up/rejected while being answered (#4403). * ContactsDataSource: iPad Crashes when you select a contact in search and then collapse a section or clear the query text (#4414). * SettingsViewController: Fix "auto" theme message to clarify that it matches the system theme on iOS 13+ (#2860). + * VoIP: Handle application inactive state too for VoIP pushes (#4269). + * VoIP: Do not terminate the app if protected data not available (#4419). ⚠️ API Changes *