From cb395147051efc112a8551b409e3811b8797e395 Mon Sep 17 00:00:00 2001 From: canyie Date: Sat, 31 Dec 2022 23:52:23 +0800 Subject: [PATCH] Fix NotificationService implementation - Fix #6385. (Maybe the reason is, the call to stopForeground() with STOP_FOREGROUND_DETACH ensures the notification is shown so it reposts the notification?) - Use FOREGROUND_SERVICE_IMMEDIATE on Android 12+ to make sure the downloading notification always shows immediately --- .../core/download/NotificationService.kt | 36 +++++++++++++------ .../topjohnwu/magisk/view/Notifications.kt | 2 ++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt index 7960e557a..a957a17eb 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/NotificationService.kt @@ -20,6 +20,8 @@ open class NotificationService : BaseService() { protected val service get() = ServiceLocator.networkService + private var attachedNotificationId = 0 + override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) notifications.forEach { Notifications.mgr.cancel(it.key) } @@ -74,32 +76,44 @@ open class NotificationService : BaseService() { subject.pendingIntent(this)?.let { intent -> it.setContentIntent(intent) } } - private fun updateForegroundState() { + private fun attachNotification(id: Int, notification: Notification) { + attachedNotificationId = id + startForeground(id, notification) + } + + private fun maybeDetachNotification(id: Int) : Boolean { + if (attachedNotificationId != id) return false if (hasNotifications) { - val (id, notification) = notifications.entries.first() - startForeground(id, notification.build()) - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - stopForeground(STOP_FOREGROUND_DETACH) + val (anotherId, notification) = notifications.entries.first() + // Attaching a new notification will remove the current showing one + attachNotification(anotherId, notification.build()) + return true + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + stopForeground(STOP_FOREGROUND_REMOVE) } else { @Suppress("DEPRECATION") - stopForeground(false) + stopForeground(true) } + attachedNotificationId = 0 + return true } protected fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) { fun create() = Notifications.startProgress("") val wasEmpty = !hasNotifications - val notification = notifications.getOrPut(id, ::create).also(editor) + val notification = notifications.getOrPut(id, ::create).also(editor).build() if (wasEmpty) - updateForegroundState() + attachNotification(id, notification) else - Notifications.mgr.notify(id, notification.build()) + Notifications.mgr.notify(id, notification) } protected fun notifyRemove(id: Int): Notification.Builder? { - val n = notifications.remove(id)?.also { updateForegroundState() } - Notifications.mgr.cancel(id) + val n = notifications.remove(id) + if (n == null || !maybeDetachNotification(id)) + Notifications.mgr.cancel(id) return n } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt index 26d259849..512ea4088 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt @@ -96,6 +96,8 @@ object Notifications { .setContentTitle(title) .setProgress(0, 0, true) .setOngoing(true) + if (SDK_INT >= Build.VERSION_CODES.S) + builder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE) return builder }