Respect notification badge settings
This commit is contained in:
@@ -3,5 +3,5 @@ package de.mm20.launcher2.notifications
|
||||
import org.koin.dsl.module
|
||||
|
||||
val notificationsModule = module {
|
||||
single<NotificationRepository> { NotificationRepositoryImpl() }
|
||||
single<NotificationRepository> { NotificationRepository() }
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.mm20.launcher2.notifications
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.graphics.drawable.Icon
|
||||
import android.media.session.MediaSession
|
||||
import android.os.Bundle
|
||||
import android.service.notification.NotificationListenerService.Ranking
|
||||
import android.service.notification.StatusBarNotification
|
||||
import androidx.core.app.NotificationCompat
|
||||
|
||||
data class Notification(
|
||||
val id: Int,
|
||||
val key: String,
|
||||
val packageName: String,
|
||||
val postTime: Long,
|
||||
val canShowBadge: Boolean,
|
||||
val number: Int,
|
||||
val smallIcon: Icon?,
|
||||
val extras: Bundle,
|
||||
val flags: Int = 0,
|
||||
val contentIntent: PendingIntent?,
|
||||
) {
|
||||
constructor(
|
||||
sbn: StatusBarNotification,
|
||||
ranking: Ranking
|
||||
) : this(
|
||||
id = sbn.id,
|
||||
key = sbn.key,
|
||||
packageName = sbn.packageName,
|
||||
postTime = sbn.postTime,
|
||||
canShowBadge = ranking.canShowBadge(),
|
||||
number = sbn.notification.number,
|
||||
smallIcon = sbn.notification.smallIcon,
|
||||
extras = sbn.notification.extras,
|
||||
flags = sbn.notification.flags,
|
||||
contentIntent = sbn.notification.contentIntent,
|
||||
)
|
||||
|
||||
constructor(
|
||||
notification: Notification,
|
||||
ranking: Ranking,
|
||||
) : this(
|
||||
id = notification.id,
|
||||
key = notification.key,
|
||||
packageName = notification.packageName,
|
||||
postTime = notification.postTime,
|
||||
canShowBadge = ranking.canShowBadge(),
|
||||
number = notification.number,
|
||||
smallIcon = notification.smallIcon,
|
||||
extras = notification.extras,
|
||||
contentIntent = notification.contentIntent
|
||||
)
|
||||
|
||||
val mediaSessionToken: MediaSession.Token?
|
||||
get() = extras.getParcelable(NotificationCompat.EXTRA_MEDIA_SESSION) as? MediaSession.Token
|
||||
|
||||
val progress: Int?
|
||||
get() = if (extras.containsKey(android.app.Notification.EXTRA_PROGRESS))
|
||||
extras.getInt(NotificationCompat.EXTRA_PROGRESS)
|
||||
else null
|
||||
|
||||
|
||||
val progressMax: Int?
|
||||
get() = extras.getInt(NotificationCompat.EXTRA_PROGRESS_MAX).takeIf { it > 0 }
|
||||
|
||||
val title: String?
|
||||
get() = extras.getString(NotificationCompat.EXTRA_TITLE)
|
||||
|
||||
val text: String?
|
||||
get() = extras.getString(NotificationCompat.EXTRA_TEXT)
|
||||
|
||||
val isGroupSummary: Boolean
|
||||
get() = flags and NotificationCompat.FLAG_GROUP_SUMMARY != 0
|
||||
}
|
||||
+16
-35
@@ -1,62 +1,43 @@
|
||||
package de.mm20.launcher2.notifications
|
||||
|
||||
import android.service.notification.StatusBarNotification
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
interface NotificationRepository {
|
||||
val notifications: Flow<List<StatusBarNotification>>
|
||||
|
||||
/**
|
||||
* Internal use only. Used by NotificationService.
|
||||
*/
|
||||
fun setNotifications(notifications: List<StatusBarNotification>)
|
||||
|
||||
/**
|
||||
* Internal use only. Used by NotificationService.
|
||||
*/
|
||||
fun postNotification(notification: StatusBarNotification)
|
||||
|
||||
/**
|
||||
* Internal use only. Used by NotificationService.
|
||||
*/
|
||||
fun removeNotification(notification: StatusBarNotification)
|
||||
|
||||
/**
|
||||
* Cancel a notification
|
||||
*/
|
||||
fun cancelNotification(notification: StatusBarNotification)
|
||||
}
|
||||
|
||||
internal class NotificationRepositoryImpl : NotificationRepository {
|
||||
class NotificationRepository {
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
override val notifications: MutableStateFlow<List<StatusBarNotification>> = MutableStateFlow(
|
||||
|
||||
private val _notifications: MutableStateFlow<List<Notification>> = MutableStateFlow(
|
||||
emptyList()
|
||||
)
|
||||
|
||||
override fun setNotifications(notifications: List<StatusBarNotification>) {
|
||||
this.notifications.value = notifications
|
||||
val notifications: Flow<List<Notification>> = _notifications
|
||||
|
||||
internal fun setNotifications(notifications: List<Notification>) {
|
||||
_notifications.value = notifications
|
||||
}
|
||||
|
||||
override fun postNotification(notification: StatusBarNotification) {
|
||||
notifications.value = notifications.value.filter { !isEqual(it, notification) } + notification
|
||||
internal fun getNotifications(): List<Notification> = _notifications.value
|
||||
|
||||
internal fun onNotificationPosted(notification: Notification) {
|
||||
_notifications.value = _notifications.value.filter { !isEqual(it, notification) } + notification
|
||||
}
|
||||
|
||||
override fun removeNotification(notification: StatusBarNotification) {
|
||||
notifications.value = notifications.value.filter { !isEqual(it, notification) }
|
||||
internal fun onNotificationRemoved(key: String) {
|
||||
_notifications.value = _notifications.value.filter { it.key != key }
|
||||
}
|
||||
|
||||
private fun isEqual(
|
||||
notification1: StatusBarNotification,
|
||||
notification2: StatusBarNotification
|
||||
notification1: Notification,
|
||||
notification2: Notification
|
||||
): Boolean {
|
||||
return notification1.key == notification2.key
|
||||
}
|
||||
|
||||
override fun cancelNotification(notification: StatusBarNotification) {
|
||||
fun cancelNotification(notification: Notification) {
|
||||
NotificationService.getInstance()?.cancelNotification(notification.key)
|
||||
}
|
||||
|
||||
|
||||
+44
-7
@@ -6,11 +6,17 @@ import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.Log
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class NotificationService : NotificationListenerService() {
|
||||
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
|
||||
private val notificationRepository: NotificationRepository by inject()
|
||||
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
@@ -24,8 +30,34 @@ class NotificationService : NotificationListenerService() {
|
||||
Log.d("MM20", "Notification listener connected")
|
||||
permissionsManager.reportNotificationListenerState(true)
|
||||
instance = WeakReference(this)
|
||||
val notifications = getNotifications().sortedBy { it.postTime }
|
||||
notificationRepository.setNotifications(notifications)
|
||||
|
||||
scope.launch {
|
||||
val statusBarNotifications = getNotifications().sortedBy { it.postTime }
|
||||
val ranking = Ranking()
|
||||
val rankingMap = currentRanking
|
||||
|
||||
val notifications = statusBarNotifications.map {
|
||||
rankingMap.getRanking(it.key, ranking)
|
||||
Notification(it, ranking)
|
||||
}
|
||||
|
||||
notificationRepository.setNotifications(notifications)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNotificationRankingUpdate(rankingMap: RankingMap?) {
|
||||
super.onNotificationRankingUpdate(rankingMap)
|
||||
scope.launch {
|
||||
val notifications = notificationRepository.getNotifications()
|
||||
|
||||
val ranking = Ranking()
|
||||
val updatedNotifications = notifications.map {
|
||||
rankingMap?.getRanking(it.key, ranking)
|
||||
Notification(it, ranking)
|
||||
}
|
||||
|
||||
notificationRepository.setNotifications(updatedNotifications)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNotifications(): Array<StatusBarNotification> {
|
||||
@@ -36,14 +68,19 @@ class NotificationService : NotificationListenerService() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNotificationPosted(sbn: StatusBarNotification) {
|
||||
notificationRepository.postNotification(sbn)
|
||||
}
|
||||
|
||||
override fun onNotificationRemoved(sbn: StatusBarNotification) {
|
||||
super.onNotificationRemoved(sbn)
|
||||
notificationRepository.onNotificationRemoved(sbn.key)
|
||||
}
|
||||
|
||||
notificationRepository.removeNotification(sbn)
|
||||
override fun onNotificationPosted(sbn: StatusBarNotification, rankingMap: RankingMap) {
|
||||
super.onNotificationPosted(sbn, rankingMap)
|
||||
|
||||
val ranking = Ranking()
|
||||
rankingMap.getRanking(sbn.key, ranking)
|
||||
val notification = Notification(sbn, ranking)
|
||||
|
||||
notificationRepository.onNotificationPosted(notification)
|
||||
}
|
||||
|
||||
override fun onListenerDisconnected() {
|
||||
|
||||
Reference in New Issue
Block a user