diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 58f2d7b4e..d380e0aa4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -113,6 +113,13 @@ + + + + + + + get() = listOf(lastNotification) + override val enabledByDefault: Boolean + get() = false + + override fun requiredPermissions(sensorId: String): Array { + return arrayOf(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE) + } + + override fun checkPermission(context: Context, sensorId: String): Boolean { + return NotificationManagerCompat + .getEnabledListenerPackages(context) + .contains(context.packageName) + } + + override fun requestSensorUpdate(context: Context) { + // Noop + } + + override fun onNotificationPosted(sbn: StatusBarNotification) { + super.onNotificationPosted(sbn) + + if (!isEnabled(applicationContext, lastNotification.id)) + return + + val allowPackages = getSetting( + applicationContext, + lastNotification, + "Allow List", + "list-apps", + "" + ).split(", ").filter { it.isNotBlank() } + + if (sbn.packageName == application.packageName || + (allowPackages.isNotEmpty() && sbn.packageName !in allowPackages)) { + return + } + + val attr = sbn.notification.extras.keySet() + .map { it to sbn.notification.extras.get(it) } + .toMap() + .plus("package" to sbn.packageName) + + // Attempt to use the text of the notification but fallback to package name if all else fails. + val state = attr["android.text"] ?: attr["android.title"] ?: sbn.packageName + + onSensorUpdated( + applicationContext, + lastNotification, + state.toString(), + "mdi:bell-ring", + attr + ) + + // Need to send update! + SensorWorker.start(applicationContext) + } +} diff --git a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorDetailFragment.kt b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorDetailFragment.kt index 4f9901b13..3afce1012 100644 --- a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorDetailFragment.kt +++ b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorDetailFragment.kt @@ -1,8 +1,11 @@ package io.homeassistant.companion.android.sensors +import android.Manifest +import android.content.Intent import android.content.pm.PackageManager import android.os.Bundle import android.os.Handler +import android.provider.Settings import android.text.InputType import androidx.preference.EditTextPreference import androidx.preference.MultiSelectListPreference @@ -67,7 +70,12 @@ class SensorDetailFragment( val isEnabled = newState as Boolean if (isEnabled && !sensorManager.checkPermission(requireContext(), basicSensor.id)) { - requestPermissions(sensorManager.requiredPermissions(basicSensor.id), 0) + val permissions = sensorManager.requiredPermissions(basicSensor.id) + when { + permissions.any { perm -> perm == Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE } -> + startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)) + else -> requestPermissions(permissions, 0) + } return@setOnPreferenceChangeListener false } diff --git a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorManager.kt b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorManager.kt index 8f94747d9..b107256bb 100644 --- a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorManager.kt +++ b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorManager.kt @@ -8,6 +8,7 @@ import io.homeassistant.companion.android.R import io.homeassistant.companion.android.database.AppDatabase import io.homeassistant.companion.android.database.sensor.Attribute import io.homeassistant.companion.android.database.sensor.Sensor +import io.homeassistant.companion.android.database.sensor.Setting interface SensorManager { @@ -58,6 +59,24 @@ interface SensorManager { return true } + fun getSetting( + context: Context, + sensor: BasicSensor, + settingName: String, + settingType: String, + default: String + ): String { + val sensorDao = AppDatabase.getInstance(context).sensorDao() + val setting = sensorDao + .getSettings(sensor.id) + .firstOrNull { it.name == settingName } + ?.value + if (setting == null) + sensorDao.add(Setting(sensor.id, settingName, default, settingType)) + + return setting ?: default + } + fun onSensorUpdated( context: Context, basicSensor: BasicSensor, diff --git a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorReceiver.kt b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorReceiver.kt index 927196891..aedbcb959 100644 --- a/app/src/main/java/io/homeassistant/companion/android/sensors/SensorReceiver.kt +++ b/app/src/main/java/io/homeassistant/companion/android/sensors/SensorReceiver.kt @@ -34,6 +34,7 @@ class SensorReceiver : BroadcastReceiver() { LocationSensorManager(), NetworkSensorManager(), NextAlarmManager(), + NotificationSensorManager(), PhoneStateSensorManager(), PowerSensorManager(), PressureSensorManager(), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86bbadad8..02adc0800 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -40,6 +40,7 @@ Geocoded Location Interactive Internal Storage + Last Notification Last Reboot Single Accurate Location Background Location @@ -217,6 +218,7 @@ like to connect to: Whether or not headphones are plugged into the device Whether or not the device is in an interactive state Information about the total and available storage space internally + The details of the last notification. The date and time of the devices last reboot. The setting below will allow you to adjust the deadband in milliseconds, if you still find the value to jump incorrectly. The default value is 60000 (1 minute). The current level of illuminance Allow Home Assistant to send a notification to request an accurate location along with the application periodically requesting an accurate location. The Minimum Accuracy setting will allow you to decide how accurate the device location (in meters) has to be in order to send to Home Assistant. The Minimum time between updates (in milliseconds) keeps the device from sending the accurate location too often. @@ -261,6 +263,7 @@ like to connect to: Do Not Disturb Sensor Geolocation Sensors Headphones + Notification Sensors Last Reboot Sensor Light Sensor Location Sensors