diff --git a/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt b/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
index 881c5b8b..fa15c86a 100644
--- a/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
+++ b/app-common/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt
@@ -24,6 +24,9 @@ class GeneralSettings @Inject constructor(
override val preferences: SharedPreferences = context.getSharedPreferences("settings_general", Context.MODE_PRIVATE)
val monitorMode = preferences.createFlowPreference("core.monitor.mode", MonitorMode.AUTOMATIC, moshi)
+
+ val useExtraMonitorNotification = preferences.createFlowPreference("core.monitor.notification.connected", false)
+
val scannerMode = preferences.createFlowPreference("core.scanner.mode", ScannerMode.BALANCED, moshi)
val showAll = preferences.createFlowPreference("core.showall.enabled", true)
@@ -44,6 +47,7 @@ class GeneralSettings @Inject constructor(
override val preferenceDataStore: PreferenceDataStore = PreferenceStoreMapper(
monitorMode,
+ useExtraMonitorNotification,
scannerMode,
showAll,
minimumSignalQuality,
diff --git a/app-common/src/main/res/drawable/ic_checkbox_blank_badge_24.xml b/app-common/src/main/res/drawable/ic_checkbox_blank_badge_24.xml
new file mode 100644
index 00000000..f7f183c9
--- /dev/null
+++ b/app-common/src/main/res/drawable/ic_checkbox_blank_badge_24.xml
@@ -0,0 +1,10 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/eu/darken/capod/monitor/core/worker/MonitorWorker.kt b/app/src/main/java/eu/darken/capod/monitor/core/worker/MonitorWorker.kt
index 4598ccc4..4d259c1b 100644
--- a/app/src/main/java/eu/darken/capod/monitor/core/worker/MonitorWorker.kt
+++ b/app/src/main/java/eu/darken/capod/monitor/core/worker/MonitorWorker.kt
@@ -22,7 +22,6 @@ import eu.darken.capod.common.flow.throttleLatest
import eu.darken.capod.main.core.GeneralSettings
import eu.darken.capod.main.core.MonitorMode
import eu.darken.capod.main.core.PermissionTool
-import eu.darken.capod.main.ui.widget.WidgetManager
import eu.darken.capod.monitor.core.MonitorCoroutineScope
import eu.darken.capod.monitor.core.PodMonitor
import eu.darken.capod.monitor.ui.MonitorNotifications
@@ -51,7 +50,7 @@ class MonitorWorker @AssistedInject constructor(
@Assisted private val context: Context,
@Assisted private val params: WorkerParameters,
private val dispatcherProvider: DispatcherProvider,
- private val monitorNotifications: MonitorNotifications,
+ private val notifications: MonitorNotifications,
private val notificationManager: NotificationManager,
private val generalSettings: GeneralSettings,
private val permissionTool: PermissionTool,
@@ -61,7 +60,6 @@ class MonitorWorker @AssistedInject constructor(
private val autoConnect: AutoConnect,
private val popUpReaction: PopUpReaction,
private val popUpWindow: PopUpWindow,
- private val widgetManager: WidgetManager,
) : CoroutineWorker(context, params) {
private val workerScope = MonitorCoroutineScope()
@@ -73,7 +71,7 @@ class MonitorWorker @AssistedInject constructor(
}
override suspend fun getForegroundInfo(): ForegroundInfo {
- return monitorNotifications.getForegroundInfo(null)
+ return notifications.getForegroundInfo(null)
}
override suspend fun doWork(): Result = try {
@@ -106,7 +104,7 @@ class MonitorWorker @AssistedInject constructor(
return
}
- setForeground(monitorNotifications.getForegroundInfo(null))
+ setForeground(notifications.getForegroundInfo(null))
val monitorJob = podMonitor.mainDevice
.setupCommonEventHandlers(TAG) { "PodMonitor" }
@@ -115,8 +113,14 @@ class MonitorWorker @AssistedInject constructor(
.onEach { currentDevice ->
notificationManager.notify(
MonitorNotifications.NOTIFICATION_ID,
- monitorNotifications.getNotification(currentDevice)
+ notifications.getNotification(currentDevice),
)
+ if (generalSettings.useExtraMonitorNotification.value && currentDevice != null) {
+ notificationManager.notify(
+ MonitorNotifications.NOTIFICATION_ID_CONNECTED,
+ notifications.getNotificationConnected(currentDevice),
+ )
+ }
}
.catch {
log(TAG, WARN) { "Pod Flow failed:\n${it.asLog()}" }
@@ -128,20 +132,23 @@ class MonitorWorker @AssistedInject constructor(
if (missingPermsFlow.isNotEmpty()) {
log(TAG, WARN) { "Aborting, permissions are missing: $missingPermsFlow" }
workerScope.coroutineContext.cancelChildren()
- return@flatMapLatest emptyFlow()
- }
- combine(
- generalSettings.monitorMode.flow,
- generalSettings.mainDeviceAddress.flow,
- bluetoothManager.connectedDevices(),
- ) { monitorMode, mainAddress, connectedDevices ->
- listOf(monitorMode, mainAddress, connectedDevices)
+ emptyFlow()
+ } else {
+ combine(
+ generalSettings.monitorMode.flow,
+ generalSettings.mainDeviceAddress.flow,
+ bluetoothManager.connectedDevices(),
+ ) { monitorMode, mainAddress, connectedDevices ->
+ listOf(monitorMode, mainAddress, connectedDevices)
+ }
}
}
.setupCommonEventHandlers(TAG) { "MonitorMode" }
.flatMapLatest { arguments ->
val monitorMode = arguments[0] as MonitorMode
val mainAddress = arguments[1] as String?
+
+ @Suppress("UNCHECKED_CAST")
val devices = arguments[2] as Collection
log(TAG) { "Monitor mode: $monitorMode" }
@@ -150,15 +157,18 @@ class MonitorWorker @AssistedInject constructor(
// Cancel worker, ui scans manually
workerScope.coroutineContext.cancelChildren()
}
+
MonitorMode.ALWAYS -> emptyFlow()
MonitorMode.AUTOMATIC -> flow {
when {
mainAddress == null && devices.isNotEmpty() -> {
log(TAG, WARN) { "Main device address not set, staying alive while any is connected" }
}
+
devices.any { it.address == mainAddress } -> {
log(TAG) { "Main device is connected ($mainAddress), aborting any timeout." }
}
+
else -> {
log(TAG) { "No known Pods are connected, canceling worker soon." }
delay(15 * 1000)
diff --git a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt
index a45a43dc..b373e7be 100644
--- a/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt
+++ b/app/src/main/java/eu/darken/capod/monitor/ui/MonitorNotifications.kt
@@ -49,6 +49,11 @@ class MonitorNotifications @Inject constructor(
context.getString(R.string.notification_channel_device_status_label),
NotificationManager.IMPORTANCE_LOW
).run { notificationManager.createNotificationChannel(this) }
+ NotificationChannel(
+ NOTIFICATION_CHANNEL_ID_CONNECTED,
+ context.getString(R.string.notification_channel_device_status_connected_label),
+ NotificationManager.IMPORTANCE_LOW
+ ).run { notificationManager.createNotificationChannel(this) }
val openIntent = Intent(context, MainActivity::class.java)
val openPi = PendingIntent.getActivity(
@@ -59,7 +64,6 @@ class MonitorNotifications @Inject constructor(
)
builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID).apply {
- setChannelId(NOTIFICATION_CHANNEL_ID)
setContentIntent(openPi)
priority = NotificationCompat.PRIORITY_LOW
setSmallIcon(eu.darken.capod.common.R.drawable.devic_earbuds_generic_both)
@@ -145,11 +149,21 @@ class MonitorNotifications @Inject constructor(
}
suspend fun getNotification(podDevice: PodDevice?): Notification = builderLock.withLock {
- getBuilder(podDevice).build()
+ getBuilder(podDevice).apply {
+ setChannelId(NOTIFICATION_CHANNEL_ID)
+ }.build()
+ }
+
+ suspend fun getNotificationConnected(podDevice: PodDevice?): Notification = builderLock.withLock {
+ getBuilder(podDevice).apply {
+ setChannelId(NOTIFICATION_CHANNEL_ID_CONNECTED)
+ }.build()
}
suspend fun getForegroundInfo(podDevice: PodDevice?): ForegroundInfo = builderLock.withLock {
- getBuilder(podDevice).toForegroundInfo()
+ getBuilder(podDevice).apply {
+ setChannelId(NOTIFICATION_CHANNEL_ID)
+ }.toForegroundInfo()
}
@SuppressLint("InlinedApi")
@@ -168,8 +182,10 @@ class MonitorNotifications @Inject constructor(
companion object {
val TAG = logTag("Monitor", "Notifications")
- private val NOTIFICATION_CHANNEL_ID =
- "${BuildConfigWrap.APPLICATION_ID}.notification.channel.device.status"
+ private val NOTIFICATION_CHANNEL_ID = "${BuildConfigWrap.APPLICATION_ID}.notification.channel.device.status"
+ private val NOTIFICATION_CHANNEL_ID_CONNECTED =
+ "${BuildConfigWrap.APPLICATION_ID}.notification.channel.device.status.connected"
internal const val NOTIFICATION_ID = 1
+ internal const val NOTIFICATION_ID_CONNECTED = 2
}
}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index b41800bc..78c071c6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -51,6 +51,7 @@
Verbindungs-Popup anzeigen
Zeigt ein Popup an, wenn das Gerät zum ersten Mal eine Verbindung herstellt.
Geräte Status
+ Verbundenes Gerät
Debug-Protokoll
Zeichne alle Aktivitäten der App in einer Textdatei auf, die du weitergeben kannst.
Größe
@@ -77,7 +78,7 @@
Lizenzen
Andere
Einstellungen
- Allgemeine Optimierungen, die die gesamte App betreffen.
+ Allgemeine Optimierungen, die die gesamte App betreffen.
Danksagungen
Automatische Fehlerberichte
Meldet Probleme automatisch, z.B. Details zu einem App-Absturz, damit ich herausfinden kann, wie ich ihn beheben kann.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 70e444c9..f68d8af2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,6 +13,8 @@
Monitor mode
Under which circumstances this app monitors Bluetooth data.
+ Extra notification
+ Shows an extra notification when a device is connected. This lets you hide the permanent \"No devices\" notification by disabling the \"Device status\" channel.
Scanner mode
Should the Bluetooth Low Energy data scanner prioritize performance or conserve energy?
Auto pause
@@ -55,6 +57,7 @@
Show a popup when the device connects for the first time.
Device status
+ Connected device
Debug log
Record everything the app is doing into a text file that you can share.
diff --git a/app/src/main/res/xml/preferences_general.xml b/app/src/main/res/xml/preferences_general.xml
index d8629c6c..3ff44fda 100644
--- a/app/src/main/res/xml/preferences_general.xml
+++ b/app/src/main/res/xml/preferences_general.xml
@@ -70,6 +70,13 @@
+
+
+