diff --git a/app/src/main/java/com/github/droidworksstudio/launcher/service/NotificationBadgeService.kt b/app/src/main/java/com/github/droidworksstudio/launcher/service/NotificationBadgeService.kt index 9b72510..2ece4a5 100644 --- a/app/src/main/java/com/github/droidworksstudio/launcher/service/NotificationBadgeService.kt +++ b/app/src/main/java/com/github/droidworksstudio/launcher/service/NotificationBadgeService.kt @@ -3,6 +3,7 @@ package com.github.droidworksstudio.launcher.service import android.app.Notification import android.service.notification.NotificationListenerService import android.service.notification.StatusBarNotification +import android.util.Log import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -16,36 +17,43 @@ import kotlinx.coroutines.flow.StateFlow */ class NotificationBadgeService : NotificationListenerService() { - /** Notification key -> "userId/packageName". Keyed to dedupe updates. */ - private val keyToPackage = HashMap() + /** Notification key -> which app it belongs to and its badge number. */ + private val keyToEntry = HashMap() + + private data class BadgeEntry(val packageKey: String, val number: Int) override fun onListenerConnected() { super.onListenerConnected() - synchronized(keyToPackage) { - keyToPackage.clear() + synchronized(keyToEntry) { + keyToEntry.clear() activeNotifications.forEach { sbn -> - if (isCounted(sbn)) keyToPackage[sbn.key] = userIdKey(sbn) + if (isCounted(sbn)) keyToEntry[sbn.key] = entryFor(sbn) } publish() } + Log.d("BadgeService", "connected, active=" + activeNotifications.size + + " counts=" + notificationCounts.value) } override fun onNotificationPosted(sbn: StatusBarNotification) { if (!isCounted(sbn)) return - synchronized(keyToPackage) { + synchronized(keyToEntry) { // A posted notification with an existing key is just an update. - if (keyToPackage.containsKey(sbn.key)) return - keyToPackage[sbn.key] = userIdKey(sbn) + if (keyToEntry.containsKey(sbn.key)) return + keyToEntry[sbn.key] = entryFor(sbn) publish() } } override fun onNotificationRemoved(sbn: StatusBarNotification) { - synchronized(keyToPackage) { - if (keyToPackage.remove(sbn.key) != null) publish() + synchronized(keyToEntry) { + if (keyToEntry.remove(sbn.key) != null) publish() } } + private fun entryFor(sbn: StatusBarNotification) = + BadgeEntry(userIdKey(sbn), sbn.notification.number) + /** Only swipe-away, non-ongoing notifications get a dot. */ private fun isCounted(sbn: StatusBarNotification): Boolean { val notification = sbn.notification @@ -58,9 +66,13 @@ class NotificationBadgeService : NotificationListenerService() { "${sbn.userId}/" + sbn.packageName private fun publish() { + // AOSP launcher badge semantics: for each counted notification add + // its badge number (Notification.number), or 1 when unset, so e.g. + // K-9's unread-count badge shows a dot. val counts = HashMap() - keyToPackage.values.forEach { key -> - counts[key] = (counts[key] ?: 0) + 1 + keyToEntry.values.forEach { entry -> + val increment = entry.number.coerceAtLeast(1) + counts[entry.packageKey] = (counts[entry.packageKey] ?: 0) + increment } notificationCounts.value = counts } diff --git a/dist/EasyLauncher-Internet-v0.3.5-Signed.apk b/dist/EasyLauncher-Internet-v0.3.5-Signed.apk index 929dc34..58371c6 100644 Binary files a/dist/EasyLauncher-Internet-v0.3.5-Signed.apk and b/dist/EasyLauncher-Internet-v0.3.5-Signed.apk differ diff --git a/dist/EasyLauncher-Internet-v0.3.5-Signed.apk.idsig b/dist/EasyLauncher-Internet-v0.3.5-Signed.apk.idsig index eeafb22..83885d8 100644 Binary files a/dist/EasyLauncher-Internet-v0.3.5-Signed.apk.idsig and b/dist/EasyLauncher-Internet-v0.3.5-Signed.apk.idsig differ