diff --git a/app/src/main/java/de/felixnuesse/timedsilence/Constants.kt b/app/src/main/java/de/felixnuesse/timedsilence/Constants.kt index 0175a48..315a9ce 100644 --- a/app/src/main/java/de/felixnuesse/timedsilence/Constants.kt +++ b/app/src/main/java/de/felixnuesse/timedsilence/Constants.kt @@ -73,6 +73,7 @@ class Constants { const val REASON_KEYWORD = 3 const val REASON_MANUALLY_SET = 4 const val REASON_BLUETOOTH_CONNECTED = 5 + const val REASON_NOTIFICATION_VISIBLE = 6 } } diff --git a/app/src/main/java/de/felixnuesse/timedsilence/handler/volume/VolumeState.kt b/app/src/main/java/de/felixnuesse/timedsilence/handler/volume/VolumeState.kt index 17f70f8..7f503e6 100644 --- a/app/src/main/java/de/felixnuesse/timedsilence/handler/volume/VolumeState.kt +++ b/app/src/main/java/de/felixnuesse/timedsilence/handler/volume/VolumeState.kt @@ -1,8 +1,10 @@ package de.felixnuesse.timedsilence.handler.volume +import de.felixnuesse.timedsilence.Constants.Companion.REASON_BLUETOOTH_CONNECTED import de.felixnuesse.timedsilence.Constants.Companion.REASON_CALENDAR import de.felixnuesse.timedsilence.Constants.Companion.REASON_KEYWORD import de.felixnuesse.timedsilence.Constants.Companion.REASON_MANUALLY_SET +import de.felixnuesse.timedsilence.Constants.Companion.REASON_NOTIFICATION_VISIBLE import de.felixnuesse.timedsilence.Constants.Companion.REASON_TIME import de.felixnuesse.timedsilence.Constants.Companion.REASON_UNDEFINED import de.felixnuesse.timedsilence.Constants.Companion.REASON_WIFI @@ -44,6 +46,7 @@ class VolumeState(var state: Int) { this.reasonDescription = reasonDescription } + // in milliseconds var startTime: Long = 0 var endTime: Long = startTime @@ -69,6 +72,8 @@ class VolumeState(var state: Int) { REASON_UNDEFINED -> s = "Default Volume." REASON_WIFI -> s = "Volume changed because of wifi: $reasonDescription" REASON_MANUALLY_SET -> s = "Volume was set manually: $reasonDescription" + REASON_BLUETOOTH_CONNECTED -> s = "Volume was set because bluetooth was connected: $reasonDescription" + REASON_NOTIFICATION_VISIBLE -> s = "Notification Visible: $reasonDescription" } return s } diff --git a/app/src/main/java/de/felixnuesse/timedsilence/receiver/NotificationListener.kt b/app/src/main/java/de/felixnuesse/timedsilence/receiver/NotificationListener.kt index 6bea1a2..39651cf 100644 --- a/app/src/main/java/de/felixnuesse/timedsilence/receiver/NotificationListener.kt +++ b/app/src/main/java/de/felixnuesse/timedsilence/receiver/NotificationListener.kt @@ -1,55 +1,61 @@ package de.felixnuesse.timedsilence.receiver - +import android.os.Build import android.service.notification.NotificationListenerService import android.service.notification.StatusBarNotification import android.util.Log -import de.felixnuesse.timedsilence.Constants +import androidx.annotation.RequiresApi import de.felixnuesse.timedsilence.extensions.TAG import de.felixnuesse.timedsilence.handler.PreferencesManager import de.felixnuesse.timedsilence.handler.volume.VolumeHandler -import de.felixnuesse.timedsilence.handler.volume.VolumeState -import de.felixnuesse.timedsilence.model.database.DatabaseHandler import de.felixnuesse.timedsilence.volumestate.StateGenerator class NotificationListener : NotificationListenerService() { - private val TAG: String = this.javaClass.simpleName + companion object { + private var service: NotificationListener? = null + fun getService(): NotificationListener? { + return service + } + } - override fun onNotificationPosted(notification: StatusBarNotification) { - handleNotification(false, notification) + var allNotifications = arrayListOf() + + override fun onCreate() { + super.onCreate() + service = this } - override fun onNotificationRemoved(notification: StatusBarNotification) { - handleNotification(true, notification) + fun getAllActiveNotifications(): ArrayList { + return allNotifications } - fun handleNotification(isRemove: Boolean, notification: StatusBarNotification) { - val proceed = PreferencesManager(this).shouldSearchInNotifications() - if(!proceed) { + override fun onNotificationPosted(notification: StatusBarNotification) { + if(notification.packageName == this.baseContext.packageName) { return } + allNotifications.clear() + allNotifications.addAll(activeNotifications) + handleNotification() + } - if(isRemove) { - Log.e(TAG(), "NotificationListener: Removed notification, check!") - VolumeHandler(this, "NotificationListener").setVolumeStateAndApply(StateGenerator(this).stateAt(System.currentTimeMillis())) + override fun onNotificationRemoved(notification: StatusBarNotification) { + if(notification.packageName == this.baseContext.packageName) { return } + allNotifications.clear() + allNotifications.addAll(activeNotifications) + handleNotification() + } - Log.e(TAG(), "NotificationListener: Posted notification, check!") - - val toSearch = notification.notification.extras.toString()+notification.notification.toString()+notification.toString() - - val db = DatabaseHandler(this) - db.getKeywords().forEach { - if (toSearch.lowercase().contains(it.keyword.lowercase())) { - val state = VolumeState(it.volume) - state.setReason(Constants.REASON_MANUALLY_SET, "Keyword ${it.keyword} was found in notification") - VolumeHandler(this, "NotificationListener").setVolumeStateAndApply(state) - return - } + private fun handleNotification() { + val proceed = PreferencesManager(this).shouldSearchInNotifications() + if(!proceed) { + return } - } + Log.e(TAG(), "NotificationListener: Posted or removed notification, check!") + VolumeHandler(this, "NotificationListener").setVolumeStateAndApply(StateGenerator(this).stateAt(System.currentTimeMillis())) + } } diff --git a/app/src/main/java/de/felixnuesse/timedsilence/volumestate/Notifications.kt b/app/src/main/java/de/felixnuesse/timedsilence/volumestate/Notifications.kt new file mode 100644 index 0000000..948f436 --- /dev/null +++ b/app/src/main/java/de/felixnuesse/timedsilence/volumestate/Notifications.kt @@ -0,0 +1,66 @@ +package de.felixnuesse.timedsilence.volumestate + + +import android.app.NotificationManager +import android.content.Context +import android.service.notification.StatusBarNotification +import android.util.Log +import de.felixnuesse.timedsilence.Constants +import de.felixnuesse.timedsilence.extensions.TAG +import de.felixnuesse.timedsilence.handler.PreferencesManager +import de.felixnuesse.timedsilence.handler.volume.VolumeState +import de.felixnuesse.timedsilence.handler.volume.VolumeState.Companion.TIME_SETTING_UNSET +import de.felixnuesse.timedsilence.handler.volume.VolumeState.Companion.isFirstLouder +import de.felixnuesse.timedsilence.model.database.DatabaseHandler +import de.felixnuesse.timedsilence.receiver.NotificationListener + + +open class Notifications(private var mContext: Context): DeterministicCalculationInterface() { + + private val mPrefs = PreferencesManager(mContext) + private val mDB = DatabaseHandler(mContext) + + override fun stateAt(timeInMs: Long): ArrayList { + return ArrayList() + } + + override fun states(): ArrayList { + val list = ArrayList() + + if(mPrefs.shouldSearchInNotifications()) { + var currentVolumeState = VolumeState(TIME_SETTING_UNSET) + NotificationListener.getService()?.getAllActiveNotifications()?.forEach { + val checkedState = handleNotification(it)?: VolumeState(TIME_SETTING_UNSET) + if (isFirstLouder(checkedState, currentVolumeState)) { + currentVolumeState = checkedState + } + } + if(currentVolumeState.state != TIME_SETTING_UNSET){ + list.add(currentVolumeState) + } + } + + Log.e(TAG(), "Size: ${list.size}") + return list + } + + private fun handleNotification(notification: StatusBarNotification): VolumeState? { + Log.e(TAG(), "Size: ${notification.notification}") + val toSearch = notification.notification.extras.toString()+notification.notification.toString()+notification.toString() + + mDB.getKeywords().forEach { + if (toSearch.lowercase().contains(it.keyword.lowercase())) { + val state = VolumeState(it.volume) + state.startTime = System.currentTimeMillis() + state.endTime = state.startTime + 60*1000 // add a minute + state.setReason(Constants.REASON_NOTIFICATION_VISIBLE, "Keyword: ${it.keyword}") + return state + } + } + return null + } + + override fun isEnabled(): Boolean { + return mPrefs.shouldSearchInNotifications() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/felixnuesse/timedsilence/volumestate/StateGenerator.kt b/app/src/main/java/de/felixnuesse/timedsilence/volumestate/StateGenerator.kt index ca4092e..e15d6e6 100644 --- a/app/src/main/java/de/felixnuesse/timedsilence/volumestate/StateGenerator.kt +++ b/app/src/main/java/de/felixnuesse/timedsilence/volumestate/StateGenerator.kt @@ -24,6 +24,7 @@ class StateGenerator(private var mContext: Context) { private var mEvents = Events(mContext) private var mKeywords = Keywords(mContext) private var mSchedules = Schedule(mContext) + private var mNotifications = Notifications(mContext) init { LogHandler.writeLog(mContext, TAG(), "instantiate","VolumeCalculator was now instantiated") @@ -50,6 +51,7 @@ class StateGenerator(private var mContext: Context) { stateList.addAll(mEvents.states()) stateList.addAll(mKeywords.states()) stateList.addAll(mSchedules.states()) + stateList.addAll(mNotifications.states()) Collections.sort(stateList, VolumeStateStartComparator()) @@ -64,13 +66,13 @@ class StateGenerator(private var mContext: Context) { // Todo: check if the performance can be improved timeList.forEach { - var deleteList = ArrayList() - var addList = ArrayList() + val deleteList = ArrayList() + val addList = ArrayList() for(state in stateList) { if(state.startTime < it && it < state.endTime) { - var a = state.copy() - var b = state.copy() + val a = state.copy() + val b = state.copy() a.endTime = it b.startTime = it @@ -95,7 +97,7 @@ class StateGenerator(private var mContext: Context) { } } - var linearList = ArrayList() + val linearList = ArrayList() map.forEach { (_, value) -> if(value.size > 1) { Collections.sort(value, VolumeStateStateComparator())