NotificationService.kt raw
1 package io.github.domi04151309.alwayson.services
2
3 import android.app.Notification
4 import android.content.Intent
5 import android.graphics.drawable.Icon
6 import android.os.Handler
7 import android.os.Looper
8 import android.service.notification.NotificationListenerService
9 import android.service.notification.StatusBarNotification
10 import android.util.Log
11 import androidx.preference.PreferenceManager
12 import io.github.domi04151309.alwayson.actions.alwayson.AlwaysOn
13 import io.github.domi04151309.alwayson.helpers.ColorHelper
14 import io.github.domi04151309.alwayson.helpers.Global
15 import io.github.domi04151309.alwayson.helpers.JSON
16 import io.github.domi04151309.alwayson.helpers.Rules
17 import io.github.domi04151309.alwayson.receivers.CombinedServiceReceiver
18 import org.json.JSONArray
19
20 class NotificationService : NotificationListenerService() {
21 private var sentRecently: Boolean = false
22 private var previousCount: Int = -1
23
24 interface OnNotificationsChangedListener {
25 fun onNotificationsChanged()
26 }
27
28 override fun onCreate() {
29 super.onCreate()
30 updateValues()
31 }
32
33 override fun onNotificationPosted(notification: StatusBarNotification) {
34 updateValues()
35
36 val rules = Rules(this)
37 @Suppress("ComplexCondition")
38 if (
39 isValidNotification(notification) &&
40 !CombinedServiceReceiver.isScreenOn &&
41 !CombinedServiceReceiver.isAlwaysOnRunning &&
42 Rules.isAmbientMode(this) &&
43 rules.canShow(this) &&
44 count >= 1
45 ) {
46 startActivity(
47 Intent(
48 this,
49 AlwaysOn::class.java,
50 ).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
51 )
52 }
53 }
54
55 override fun onNotificationRemoved(notification: StatusBarNotification) {
56 updateValues()
57
58 if (
59 CombinedServiceReceiver.isAlwaysOnRunning &&
60 Rules.isAmbientMode(this) &&
61 count < 1
62 ) {
63 AlwaysOn.finish()
64 }
65 }
66
67 private fun updateValues() {
68 if (sentRecently) return
69
70 sentRecently = true
71 try {
72 val apps = ArrayList<String>(detailed.size)
73 detailed = activeNotifications
74 icons = ArrayList(detailed.size)
75 count = 0
76 for (notification in detailed) {
77 if (!isValidNotification(notification)) continue
78 if (
79 notification.notification.flags and Notification.FLAG_GROUP_SUMMARY == 0
80 ) {
81 count++
82 }
83 if (!apps.contains(notification.packageName)) {
84 apps += notification.packageName
85 icons.add(
86 Pair(
87 notification.notification.smallIcon,
88 ColorHelper.boostColor(notification.notification.color),
89 ),
90 )
91 }
92 }
93 } catch (exception: SecurityException) {
94 Log.e(Global.LOG_TAG, exception.toString())
95 count = 0
96 icons = arrayListOf()
97 }
98 if (previousCount != count) {
99 previousCount = count
100 listeners.forEach { it.onNotificationsChanged() }
101 }
102 Handler(Looper.getMainLooper()).postDelayed({ sentRecently = false }, MINIMUM_UPDATE_DELAY)
103 }
104
105 private fun isValidNotification(notification: StatusBarNotification): Boolean =
106 !notification.isOngoing &&
107 !JSON.contains(
108 JSONArray(
109 PreferenceManager.getDefaultSharedPreferences(this)
110 .getString("blocked_notifications", "[]"),
111 ),
112 notification.packageName,
113 )
114
115 companion object {
116 const val MINIMUM_UPDATE_DELAY: Long = 1000
117 internal var count: Int = 0
118 private set
119 internal var icons: ArrayList<Pair<Icon, Int>> = arrayListOf()
120 private set
121 internal var detailed: Array<StatusBarNotification> = arrayOf()
122 private set
123
124 @JvmField
125 internal val listeners: ArrayList<OnNotificationsChangedListener> = arrayListOf()
126 }
127 }
128