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
This commit is contained in:
canyie 2022-12-31 23:52:23 +08:00 committed by John Wu
parent 78a444d601
commit cb39514705
2 changed files with 27 additions and 11 deletions

View File

@ -20,6 +20,8 @@ open class NotificationService : BaseService() {
protected val service get() = ServiceLocator.networkService protected val service get() = ServiceLocator.networkService
private var attachedNotificationId = 0
override fun onTaskRemoved(rootIntent: Intent?) { override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent) super.onTaskRemoved(rootIntent)
notifications.forEach { Notifications.mgr.cancel(it.key) } notifications.forEach { Notifications.mgr.cancel(it.key) }
@ -74,32 +76,44 @@ open class NotificationService : BaseService() {
subject.pendingIntent(this)?.let { intent -> it.setContentIntent(intent) } 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) { if (hasNotifications) {
val (id, notification) = notifications.entries.first() val (anotherId, notification) = notifications.entries.first()
startForeground(id, notification.build()) // Attaching a new notification will remove the current showing one
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { attachNotification(anotherId, notification.build())
stopForeground(STOP_FOREGROUND_DETACH) return true
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stopForeground(STOP_FOREGROUND_REMOVE)
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
stopForeground(false) stopForeground(true)
} }
attachedNotificationId = 0
return true
} }
protected fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) { protected fun notifyUpdate(id: Int, editor: (Notification.Builder) -> Unit = {}) {
fun create() = Notifications.startProgress("") fun create() = Notifications.startProgress("")
val wasEmpty = !hasNotifications val wasEmpty = !hasNotifications
val notification = notifications.getOrPut(id, ::create).also(editor) val notification = notifications.getOrPut(id, ::create).also(editor).build()
if (wasEmpty) if (wasEmpty)
updateForegroundState() attachNotification(id, notification)
else else
Notifications.mgr.notify(id, notification.build()) Notifications.mgr.notify(id, notification)
} }
protected fun notifyRemove(id: Int): Notification.Builder? { protected fun notifyRemove(id: Int): Notification.Builder? {
val n = notifications.remove(id)?.also { updateForegroundState() } val n = notifications.remove(id)
Notifications.mgr.cancel(id) if (n == null || !maybeDetachNotification(id))
Notifications.mgr.cancel(id)
return n return n
} }

View File

@ -96,6 +96,8 @@ object Notifications {
.setContentTitle(title) .setContentTitle(title)
.setProgress(0, 0, true) .setProgress(0, 0, true)
.setOngoing(true) .setOngoing(true)
if (SDK_INT >= Build.VERSION_CODES.S)
builder.setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
return builder return builder
} }