From 713b781def2a38b0811abcacc7520d340f6b8375 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Tue, 23 Feb 2021 15:38:55 +1100 Subject: [PATCH] Remove legacy notifications adaptee --- Session.xcodeproj/project.pbxproj | 4 - Session/Meta/AppDelegate.m | 18 -- Session/Meta/AppEnvironment.swift | 20 +- Session/Notifications/AppNotifications.swift | 25 +- .../LegacyNotificationsAdaptee.swift | 280 ------------------ .../UserNotificationsAdaptee.swift | 7 +- Session/Utilities/HapticFeedback.swift | 18 +- 7 files changed, 4 insertions(+), 368 deletions(-) delete mode 100644 Session/Notifications/LegacyNotificationsAdaptee.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index ccd878308..738b0a7d3 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -141,7 +141,6 @@ 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; }; 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */; }; 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; }; - 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */; }; 5DF9AB212C6DB1E8BE70EFF6 /* Pods_SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB523C549815DE935E98151E /* Pods_SessionMessagingKit.framework */; }; 70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; }; 75A5E31037A6F0E5677F3B5C /* Pods_SessionNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62ED73E38E0EC8506A9131AD /* Pods_SessionNotificationServiceExtension.framework */; }; @@ -1122,7 +1121,6 @@ 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = ""; }; 4CC1ECFA211A553000CC13BE /* AppUpdateNag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdateNag.swift; sourceTree = ""; }; 4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = ""; }; - 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyNotificationsAdaptee.swift; sourceTree = ""; }; 53D547348A367C8A14D37FC0 /* Pods_SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F3070F3395081DD0EB4F933 /* Pods-SignalUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SignalUtilitiesKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SignalUtilitiesKit/Pods-SignalUtilitiesKit.debug.xcconfig"; sourceTree = ""; }; 62ED73E38E0EC8506A9131AD /* Pods_SessionNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SessionNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2923,7 +2921,6 @@ 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */, 451A13B01E13DED2000A50FD /* AppNotifications.swift */, 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */, - 4CFE6B6B21F92BA700006701 /* LegacyNotificationsAdaptee.swift */, ); path = Notifications; sourceTree = ""; @@ -4957,7 +4954,6 @@ B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */, 45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */, B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */, - 4CFE6B6C21F92BA700006701 /* LegacyNotificationsAdaptee.swift in Sources */, B8CCF6432397711F0091D419 /* SettingsVC.swift in Sources */, C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */, C32C5D40256DD51E003C73A2 /* Storage+VolumeSamples.swift in Sources */, diff --git a/Session/Meta/AppDelegate.m b/Session/Meta/AppDelegate.m index 92edee00a..144ed077e 100644 --- a/Session/Meta/AppDelegate.m +++ b/Session/Meta/AppDelegate.m @@ -118,11 +118,6 @@ static NSTimeInterval launchStartedAt; return AppEnvironment.shared.userNotificationActionHandler; } -- (OWSLegacyNotificationActionHandler *)legacyNotificationActionHandler -{ - return AppEnvironment.shared.legacyNotificationActionHandler; -} - #pragma mark - Lifecycle - (void)applicationDidEnterBackground:(UIApplication *)application @@ -641,19 +636,6 @@ static NSTimeInterval launchStartedAt; #endif } -- (void)application:(UIApplication *)application - didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings -{ - OWSAssertIsOnMainThread(); - - if (self.didAppLaunchFail) { - OWSFailDebug(@"App launch failed"); - return; - } - - [self.notificationPresenter didRegisterLegacyNotificationSettings]; -} - - (void)clearAllNotificationsAndRestoreBadgeCount { OWSAssertIsOnMainThread(); diff --git a/Session/Meta/AppEnvironment.swift b/Session/Meta/AppEnvironment.swift index c4981ca22..2aa581a91 100644 --- a/Session/Meta/AppEnvironment.swift +++ b/Session/Meta/AppEnvironment.swift @@ -37,26 +37,11 @@ import SignalUtilitiesKit @objc public var backup: OWSBackup - private var _legacyNotificationActionHandler: LegacyNotificationActionHandler - @objc - public var legacyNotificationActionHandler: LegacyNotificationActionHandler { - get { - if #available(iOS 10, *) { - owsFailDebug("shouldn't user legacyNotificationActionHandler on modern iOS") - } - return _legacyNotificationActionHandler - } - set { - _legacyNotificationActionHandler = newValue - } - } - // Stored properties cannot be marked as `@available`, only classes and functions. // Instead, store a private `Any` and wrap it with a public `@available` getter private var _userNotificationActionHandler: Any? @objc - @available(iOS 10.0, *) public var userNotificationActionHandler: UserNotificationActionHandler { return _userNotificationActionHandler as! UserNotificationActionHandler } @@ -70,10 +55,7 @@ import SignalUtilitiesKit self.pushRegistrationManager = PushRegistrationManager() self.backup = OWSBackup() self.backupLazyRestore = BackupLazyRestore() - if #available(iOS 10.0, *) { - self._userNotificationActionHandler = UserNotificationActionHandler() - } - self._legacyNotificationActionHandler = LegacyNotificationActionHandler() + self._userNotificationActionHandler = UserNotificationActionHandler() super.init() diff --git a/Session/Notifications/AppNotifications.swift b/Session/Notifications/AppNotifications.swift index e3d7528bc..77363a61e 100644 --- a/Session/Notifications/AppNotifications.swift +++ b/Session/Notifications/AppNotifications.swift @@ -105,11 +105,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { @objc public override init() { - if #available(iOS 10, *) { - self.adaptee = UserNotificationPresenterAdaptee() - } else { - self.adaptee = LegacyNotificationPresenterAdaptee() - } + self.adaptee = UserNotificationPresenterAdaptee() super.init() @@ -135,25 +131,6 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { // MARK: - - // It is not safe to assume push token requests will be acknowledged until the user has - // registered their notification settings. - // - // e.g. in the case that Background Fetch is disabled, token requests will be ignored until - // we register user notification settings. - // - // For modern UNUserNotificationSettings, the registration takes a callback, so "waiting" for - // notification settings registration is straight forward, however for legacy UIUserNotification - // settings, the settings request is confirmed in the AppDelegate, where we call this method - // to inform the adaptee it's safe to proceed. - @objc - public func didRegisterLegacyNotificationSettings() { - guard let legacyAdaptee = adaptee as? LegacyNotificationPresenterAdaptee else { - owsFailDebug("unexpected notifications adaptee: \(adaptee)") - return - } - legacyAdaptee.didRegisterUserNotificationSettings() - } - @objc func handleMessageRead(notification: Notification) { AssertIsOnMainThread() diff --git a/Session/Notifications/LegacyNotificationsAdaptee.swift b/Session/Notifications/LegacyNotificationsAdaptee.swift deleted file mode 100644 index 10cb0e538..000000000 --- a/Session/Notifications/LegacyNotificationsAdaptee.swift +++ /dev/null @@ -1,280 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import PromiseKit - -struct LegacyNotificationConfig { - - static var allNotificationCategories: Set { - let categories = AppNotificationCategory.allCases.map { notificationCategory($0) } - return Set(categories) - } - - static func notificationActions(for category: AppNotificationCategory) -> [UIUserNotificationAction] { - return category.actions.map { notificationAction($0) } - } - - static func notificationAction(_ action: AppNotificationAction) -> UIUserNotificationAction { - switch action { - case .markAsRead: - let mutableAction = UIMutableUserNotificationAction() - mutableAction.identifier = action.identifier - mutableAction.title = MessageStrings.markAsReadNotificationAction - mutableAction.activationMode = .background - mutableAction.isDestructive = false - mutableAction.isAuthenticationRequired = false - return mutableAction - case .reply: - let mutableAction = UIMutableUserNotificationAction() - mutableAction.identifier = action.identifier - mutableAction.title = MessageStrings.replyNotificationAction - mutableAction.activationMode = .background - mutableAction.isDestructive = false - mutableAction.isAuthenticationRequired = false - mutableAction.behavior = .textInput - return mutableAction - case .showThread: - let mutableAction = UIMutableUserNotificationAction() - mutableAction.identifier = action.identifier - mutableAction.title = CallStrings.showThreadButtonTitle - mutableAction.activationMode = .foreground - mutableAction.isDestructive = false - mutableAction.isAuthenticationRequired = true - return mutableAction - } - } - - static func action(identifier: String) -> AppNotificationAction? { - return AppNotificationAction.allCases.first { notificationAction($0).identifier == identifier } - } - - static func notificationActions(category: AppNotificationCategory) -> [UIUserNotificationAction] { - return category.actions.map { notificationAction($0) } - } - - static func notificationCategory(_ category: AppNotificationCategory) -> UIUserNotificationCategory { - let notificationCategory = UIMutableUserNotificationCategory() - notificationCategory.identifier = category.identifier - - let actions = notificationActions(category: category) - notificationCategory.setActions(actions, for: .minimal) - notificationCategory.setActions(actions, for: .default) - - return notificationCategory - } -} - -class LegacyNotificationPresenterAdaptee { - - private var notifications: [String: UILocalNotification] = [:] - private var userNotificationSettingsPromise: Promise? - private var userNotificationSettingsResolver: Resolver? - - // Notification registration is confirmed via AppDelegate - // Before this occurs, it is not safe to assume push token requests will be acknowledged. - // - // e.g. in the case that Background Fetch is disabled, token requests will be ignored until - // we register user notification settings. - @objc - public func didRegisterUserNotificationSettings() { - AssertIsOnMainThread() - guard let userNotificationSettingsResolver = self.userNotificationSettingsResolver else { - owsFailDebug("promise completion in \(#function) unexpectedly nil") - return - } - - userNotificationSettingsResolver.fulfill(()) - } - -} - -extension LegacyNotificationPresenterAdaptee: NotificationPresenterAdaptee { - - func registerNotificationSettings() -> Promise { - AssertIsOnMainThread() - Logger.debug("") - - guard self.userNotificationSettingsPromise == nil else { - let promise = self.userNotificationSettingsPromise! - Logger.info("already registered user notification settings") - return promise - } - - let (promise, resolver) = Promise.pending() - self.userNotificationSettingsPromise = promise - self.userNotificationSettingsResolver = resolver - - let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], - categories: LegacyNotificationConfig.allNotificationCategories) - UIApplication.shared.registerUserNotificationSettings(settings) - - return promise - } - - func notify(category: AppNotificationCategory, title: String?, body: String, userInfo: [AnyHashable: Any], sound: OWSSound?) { - AssertIsOnMainThread() - notify(category: category, title: title, body: body, userInfo: userInfo, sound: sound, replacingIdentifier: nil) - } - - func notify(category: AppNotificationCategory, title: String?, body: String, userInfo: [AnyHashable: Any], sound: OWSSound?, replacingIdentifier: String?) { - AssertIsOnMainThread() - guard UIApplication.shared.applicationState != .active else { - if let sound = sound { - let soundId = OWSSounds.systemSoundID(for: sound, quiet: true) - - // Vibrate, respect silent switch, respect "Alert" volume, not media volume. - AudioServicesPlayAlertSound(soundId) - } - return - } - - let alertBody: String - if let title = title { - // TODO - Make this a format string for better l10n - alertBody = title.rtlSafeAppend(":").rtlSafeAppend(" ").rtlSafeAppend(body) - } else { - alertBody = body - } - - let notification = UILocalNotification() - notification.category = category.identifier - notification.alertBody = alertBody.filterForDisplay - notification.userInfo = userInfo - notification.soundName = sound?.filename - - var notificationIdentifier: String = UUID().uuidString - if let replacingIdentifier = replacingIdentifier { - notificationIdentifier = replacingIdentifier - Logger.debug("replacing notification with identifier: \(notificationIdentifier)") - cancelNotification(identifier: notificationIdentifier) - } - - let checkForCancel = category == .incomingMessage - if checkForCancel { - assert(userInfo[AppNotificationUserInfoKey.threadId] != nil) - notification.fireDate = Date(timeIntervalSinceNow: kNotificationDelayForRemoteRead) - notification.timeZone = NSTimeZone.local - } - - Logger.debug("presenting notification with identifier: \(notificationIdentifier)") - UIApplication.shared.scheduleLocalNotification(notification) - notifications[notificationIdentifier] = notification - } - - func cancelNotification(_ notification: UILocalNotification) { - AssertIsOnMainThread() - UIApplication.shared.cancelLocalNotification(notification) - } - - func cancelNotification(identifier: String) { - AssertIsOnMainThread() - guard let notification = notifications.removeValue(forKey: identifier) else { - Logger.debug("no notification to cancel with identifier: \(identifier)") - return - } - - cancelNotification(notification) - } - - func cancelNotifications(threadId: String) { - AssertIsOnMainThread() - for notification in notifications.values { - guard let notificationThreadId = notification.userInfo?[AppNotificationUserInfoKey.threadId] as? String else { - continue - } - - guard notificationThreadId == threadId else { - continue - } - - cancelNotification(notification) - } - } - - func clearAllNotifications() { - AssertIsOnMainThread() - for (_, notification) in notifications { - cancelNotification(notification) - } - type(of: self).clearExistingNotifications() - } - - public class func clearExistingNotifications() { - // This will cancel all "scheduled" local notifications that haven't - // been presented yet. - UIApplication.shared.cancelAllLocalNotifications() - // To clear all already presented local notifications, we need to - // set the app badge number to zero after setting it to a non-zero value. - UIApplication.shared.applicationIconBadgeNumber = 1 - UIApplication.shared.applicationIconBadgeNumber = 0 - } -} - -@objc(OWSLegacyNotificationActionHandler) -public class LegacyNotificationActionHandler: NSObject { - - @objc - public static let kDefaultActionIdentifier = "LegacyNotificationActionHandler.kDefaultActionIdentifier" - - var actionHandler: NotificationActionHandler { - return NotificationActionHandler.shared - } - - @objc - func handleNotificationResponse(actionIdentifier: String, - notification: UILocalNotification, - responseInfo: [AnyHashable: Any], - completionHandler: @escaping () -> Void) { - firstly { - try handleNotificationResponse(actionIdentifier: actionIdentifier, notification: notification, responseInfo: responseInfo) - }.done { - completionHandler() - }.catch { error in - completionHandler() - owsFailDebug("error: \(error)") - Logger.error("error: \(error)") - }.retainUntilComplete() - } - - func handleNotificationResponse(actionIdentifier: String, - notification: UILocalNotification, - responseInfo: [AnyHashable: Any]) throws -> Promise { - assert(AppReadiness.isAppReady()) - - let userInfo = notification.userInfo ?? [:] - - switch actionIdentifier { - case type(of: self).kDefaultActionIdentifier: - Logger.debug("default action") - return try actionHandler.showThread(userInfo: userInfo) - default: - // proceed - break - } - - guard let action = LegacyNotificationConfig.action(identifier: actionIdentifier) else { - throw NotificationError.failDebug("unable to find action for actionIdentifier: \(actionIdentifier)") - } - - switch action { - case .markAsRead: - return try actionHandler.markAsRead(userInfo: userInfo) - case .reply: - guard let replyText = responseInfo[UIUserNotificationActionResponseTypedTextKey] as? String else { - throw NotificationError.failDebug("replyText was unexpectedly nil") - } - - return try actionHandler.reply(userInfo: userInfo, replyText: replyText) - case .showThread: - return try actionHandler.showThread(userInfo: userInfo) - } - } -} - -extension OWSSound { - var filename: String? { - return OWSSounds.filename(for: self, quiet: false) - } -} diff --git a/Session/Notifications/UserNotificationsAdaptee.swift b/Session/Notifications/UserNotificationsAdaptee.swift index 07d369ebe..45b9c2a5c 100644 --- a/Session/Notifications/UserNotificationsAdaptee.swift +++ b/Session/Notifications/UserNotificationsAdaptee.swift @@ -6,7 +6,6 @@ import Foundation import UserNotifications import PromiseKit -@available(iOS 10.0, *) class UserNotificationConfig { class var allNotificationCategories: Set { @@ -50,7 +49,6 @@ class UserNotificationConfig { } -@available(iOS 10.0, *) class UserNotificationPresenterAdaptee: NSObject, UNUserNotificationCenterDelegate { private let notificationCenter: UNUserNotificationCenter @@ -64,7 +62,6 @@ class UserNotificationPresenterAdaptee: NSObject, UNUserNotificationCenterDelega } } -@available(iOS 10.0, *) extension UserNotificationPresenterAdaptee: NotificationPresenterAdaptee { func registerNotificationSettings() -> Promise { @@ -170,7 +167,6 @@ extension UserNotificationPresenterAdaptee: NotificationPresenterAdaptee { AssertIsOnMainThread() notificationCenter.removeAllPendingNotificationRequests() notificationCenter.removeAllDeliveredNotifications() - LegacyNotificationPresenterAdaptee.clearExistingNotifications() } func shouldPresentNotification(category: AppNotificationCategory, userInfo: [AnyHashable: Any]) -> Bool { @@ -198,7 +194,6 @@ extension UserNotificationPresenterAdaptee: NotificationPresenterAdaptee { } @objc(OWSUserNotificationActionHandler) -@available(iOS 10.0, *) public class UserNotificationActionHandler: NSObject { var actionHandler: NotificationActionHandler { @@ -258,7 +253,7 @@ public class UserNotificationActionHandler: NSObject { } extension OWSSound { - @available(iOS 10.0, *) + func notificationSound(isQuiet: Bool) -> UNNotificationSound { guard let filename = OWSSounds.filename(for: self, quiet: isQuiet) else { owsFailDebug("filename was unexpectedly nil") diff --git a/Session/Utilities/HapticFeedback.swift b/Session/Utilities/HapticFeedback.swift index c80bbf321..3eaecd86e 100644 --- a/Session/Utilities/HapticFeedback.swift +++ b/Session/Utilities/HapticFeedback.swift @@ -51,7 +51,6 @@ enum NotificationHapticFeedbackType { case error, success, warning } -@available(iOS 10.0, *) extension NotificationHapticFeedbackType { var uiNotificationFeedbackType: UINotificationFeedbackGenerator.FeedbackType { switch self { @@ -71,11 +70,7 @@ class NotificationHapticFeedback: NotificationHapticFeedbackAdapter { let adapter: NotificationHapticFeedbackAdapter init() { - if #available(iOS 10, *) { - adapter = ModernNotificationHapticFeedbackAdapter() - } else { - adapter = LegacyNotificationHapticFeedbackAdapter() - } + adapter = ModernNotificationHapticFeedbackAdapter() } func notificationOccurred(_ notificationType: NotificationHapticFeedbackType) { @@ -83,7 +78,6 @@ class NotificationHapticFeedback: NotificationHapticFeedbackAdapter { } } -@available(iOS 10.0, *) class ModernNotificationHapticFeedbackAdapter: NotificationHapticFeedbackAdapter { let feedbackGenerator = UINotificationFeedbackGenerator() @@ -96,13 +90,3 @@ class ModernNotificationHapticFeedbackAdapter: NotificationHapticFeedbackAdapter feedbackGenerator.prepare() } } - -class LegacyNotificationHapticFeedbackAdapter: NotificationHapticFeedbackAdapter { - func notificationOccurred(_ notificationType: NotificationHapticFeedbackType) { - vibrate() - } - - private func vibrate() { - AudioServicesPlaySystemSound(kSystemSoundID_Vibrate) - } -}