From 8bc1a193c87a435a9a0ba2eca74600cfa6266623 Mon Sep 17 00:00:00 2001 From: darken Date: Wed, 12 Jan 2022 16:37:26 +0100 Subject: [PATCH] Improve notifications --- .../capod/common/bluetooth/BleScanner.kt | 2 +- .../capod/monitor/ui/MonitorNotifications.kt | 42 +++++------ .../monitor/ui/NotificationViewFactory.kt | 70 +++++++++++++++++++ .../eu/darken/capod/pods/core/PodDevice.kt | 4 -- .../pods/core/apple/BasicSingleApplePods.kt | 12 ---- .../capod/pods/core/apple/DualApplePods.kt | 41 +---------- .../capod/pods/core/apple/SingleApplePods.kt | 12 ---- .../pods/core/apple/UnknownAppleDevice.kt | 7 -- .../ic_baseline_battery_charging_full_24.xml | 10 +++ .../drawable/ic_baseline_question_mark_24.xml | 10 +++ .../monitor_notification_dual_pods_big.xml | 6 ++ .../monitor_notification_dual_pods_small.xml | 56 +++++++++++++++ ...monitor_notification_single_pods_small.xml | 25 +++++++ ...itor_notification_unknown_device_small.xml | 17 +++++ app/src/main/res/values/dimens.xml | 4 ++ app/src/main/res/values/strings.xml | 1 - 16 files changed, 223 insertions(+), 96 deletions(-) create mode 100644 app/src/main/java/eu/darken/capod/monitor/ui/NotificationViewFactory.kt create mode 100644 app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml create mode 100644 app/src/main/res/drawable/ic_baseline_question_mark_24.xml create mode 100644 app/src/main/res/layout/monitor_notification_dual_pods_big.xml create mode 100644 app/src/main/res/layout/monitor_notification_dual_pods_small.xml create mode 100644 app/src/main/res/layout/monitor_notification_single_pods_small.xml create mode 100644 app/src/main/res/layout/monitor_notification_unknown_device_small.xml create mode 100644 app/src/main/res/values/dimens.xml diff --git a/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt b/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt index 92794aa0..2b68488a 100644 --- a/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt +++ b/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt @@ -92,7 +92,7 @@ class BleScanner @Inject constructor( // AirPods Max BleScanResult( address = "7E:E5:C7:65:D2:B5", - rssi = -57, + rssi = -30, generatedAtNanos = SystemClockWrap.elapsedRealtimeNanos + 300, manufacturerSpecificData = mapOf(76 to "07 19 01 0A 20 02 05 80 04 0F 44 A7 60 9B F8 3C FD B1 D8 1C 61 EA 82 60 A3 2C 4E".hexToByteArray()) ).run { fakeDevices.add(this) } 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 b555c760..a27d4521 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 @@ -26,6 +26,7 @@ import javax.inject.Inject class MonitorNotifications @Inject constructor( @ApplicationContext private val context: Context, notificationManager: NotificationManager, + private val notificationViewFactory: NotificationViewFactory ) { private val builder: NotificationCompat.Builder @@ -45,33 +46,32 @@ class MonitorNotifications @Inject constructor( PendingIntentCompat.FLAG_IMMUTABLE ) - builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) - .setChannelId(NOTIFICATION_CHANNEL_ID) - .setContentIntent(openPi) - .setPriority(NotificationCompat.PRIORITY_LOW) - .setSmallIcon(R.drawable.ic_device_generic_earbuds) - .setOngoing(true) - .setContentTitle(context.getString(R.string.app_name)) + builder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID).apply { + setChannelId(NOTIFICATION_CHANNEL_ID) + setContentIntent(openPi) + priority = NotificationCompat.PRIORITY_LOW + setSmallIcon(R.drawable.ic_device_generic_earbuds) + setOngoing(true) + setContentTitle(context.getString(R.string.app_name)) + } } fun getBuilder(device: PodDevice?): NotificationCompat.Builder { if (device == null) { - builder.setContentTitle(context.getString(R.string.pods_none_label_short)) - builder.setSubText(context.getString(R.string.app_name)) - builder.setSmallIcon(R.drawable.ic_device_generic_earbuds) - return builder + return builder.apply { + setContentTitle(context.getString(R.string.pods_none_label_short)) + setSubText(context.getString(R.string.app_name)) + setSmallIcon(R.drawable.ic_device_generic_earbuds) + } } - builder.setSmallIcon(device.iconRes) - builder.setSubText(null) - builder.setContentTitle(device.getStatusShort(context)) - builder.setStyle( - NotificationCompat.BigTextStyle() - .setBigContentTitle(device.getLabel(context)) - .bigText(device.getStatusLong(context).joinToString("\n")) - ) - log(TAG, VERBOSE) { "updatingNotification(): $device" } - return builder + return builder.apply { + setSmallIcon(device.iconRes) + setSubText(null) + setStyle(NotificationCompat.DecoratedCustomViewStyle()) + setCustomContentView(notificationViewFactory.createContentView(device)) + log(TAG, VERBOSE) { "updatingNotification(): $device" } + } } fun getNotification(podDevice: PodDevice?): Notification = getBuilder(podDevice).build() diff --git a/app/src/main/java/eu/darken/capod/monitor/ui/NotificationViewFactory.kt b/app/src/main/java/eu/darken/capod/monitor/ui/NotificationViewFactory.kt new file mode 100644 index 00000000..1357eba5 --- /dev/null +++ b/app/src/main/java/eu/darken/capod/monitor/ui/NotificationViewFactory.kt @@ -0,0 +1,70 @@ +package eu.darken.capod.monitor.ui + +import android.content.Context +import android.widget.RemoteViews +import dagger.hilt.android.qualifiers.ApplicationContext +import eu.darken.capod.R +import eu.darken.capod.pods.core.* +import eu.darken.capod.pods.core.apple.BasicSingleApplePods +import eu.darken.capod.pods.core.apple.DualApplePods +import eu.darken.capod.pods.core.apple.SingleApplePods +import javax.inject.Inject + + +class NotificationViewFactory @Inject constructor( + @ApplicationContext private val context: Context +) { + + fun createContentView(device: PodDevice): RemoteViews = when (device) { + is DualApplePods -> createDualApplePods(device) + is SingleApplePods -> createSingleApplePods(device) + is BasicSingleApplePods -> createSingleBasicApplePods(device) + else -> createUnknownDevice(device) + } + + private fun createDualApplePods(device: DualApplePods): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_dual_pods_small + ).apply { + device.getBatteryLevelLeftPod(context) + .let { if (device.isLeftPodCharging) "$it⚡" else it } + .run { setTextViewText(R.id.pod_left, this) } + + device.getBatteryLevelCase(context) + .let { if (device.isCaseCharging) "$it⚡" else it } + .run { setTextViewText(R.id.pod_case, this) } + + device.getBatteryLevelRightPod(context) + .let { if (device.isRightPodCharging) "$it⚡" else it } + .run { setTextViewText(R.id.pod_right, this) } + } + + private fun createSingleApplePods(device: SingleApplePods): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_single_pods_small + ).apply { + setTextViewText(R.id.headphones_label, device.getLabel(context)) + + device.getBatteryLevelHeadset(context) + .let { if (!device.isHeadsetBeingCharged) "$it⚡" else it } + .run { setTextViewText(R.id.headphones, this) } + } + + private fun createSingleBasicApplePods(device: BasicSingleApplePods): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_single_pods_small + ).apply { + setTextViewText(R.id.headphones_label, device.getLabel(context)) + + device.getBatteryLevelHeadset(context) + .run { setTextViewText(R.id.headphones, this) } + } + + private fun createUnknownDevice(device: PodDevice): RemoteViews = RemoteViews( + context.packageName, + R.layout.monitor_notification_dual_pods_small + ).apply { + setTextViewText(R.id.device, device.getLabel(context)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/darken/capod/pods/core/PodDevice.kt b/app/src/main/java/eu/darken/capod/pods/core/PodDevice.kt index 5c169250..63b119ef 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/PodDevice.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/PodDevice.kt @@ -31,10 +31,6 @@ interface PodDevice { fun getLabel(context: Context): String - fun getStatusShort(context: Context): String - - fun getStatusLong(context: Context): List - @get:DrawableRes val iconRes: Int get() = R.drawable.ic_device_generic_earbuds diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/BasicSingleApplePods.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/BasicSingleApplePods.kt index faa08f8a..a4dd3a5e 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/BasicSingleApplePods.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/BasicSingleApplePods.kt @@ -1,23 +1,11 @@ package eu.darken.capod.pods.core.apple -import android.content.Context -import eu.darken.capod.R import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.lowerNibble import eu.darken.capod.pods.core.HasSinglePod -import eu.darken.capod.pods.core.getBatteryLevelHeadset interface BasicSingleApplePods : ApplePods, HasSinglePod { - override fun getStatusShort(context: Context): String = context.getString( - R.string.pods_single_basic_status_short, - getBatteryLevelHeadset(context), - ) - - override fun getStatusLong(context: Context): List { - return listOf("${context.getString(R.string.pods_single_headphones_label)}: ${getBatteryLevelHeadset(context)}") - } - override val batteryHeadsetPercent: Float? get() = when (val value = rawPodsBattery.lowerNibble.toInt()) { 15 -> null diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt index 1d764429..77b3d674 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/DualApplePods.kt @@ -7,48 +7,13 @@ import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.isBitSet import eu.darken.capod.common.lowerNibble import eu.darken.capod.common.upperNibble -import eu.darken.capod.pods.core.* +import eu.darken.capod.pods.core.HasCase +import eu.darken.capod.pods.core.HasDualPods import eu.darken.capod.pods.core.HasDualPods.Pod +import eu.darken.capod.pods.core.HasEarDetection interface DualApplePods : ApplePods, HasDualPods, HasEarDetection, HasCase { - override fun getStatusShort(context: Context): String = context.getString( - R.string.pods_dual_case_status_short, - getBatteryLevelLeftPod(context).let { - if (isLeftPodCharging) "$it*" else it - }, - getBatteryLevelCase(context).let { - if (isCaseCharging) "$it*" else it - }, - getBatteryLevelRightPod(context).let { - if (isRightPodCharging) "$it*" else it - }, - ) - - override fun getStatusLong(context: Context): List { - val list = mutableListOf() - - StringBuilder("${context.getString(R.string.pods_dual_left_label)}: ${getBatteryLevelLeftPod(context)}").apply { - if (isLeftPodCharging) append(", ${context.getString(R.string.pods_charging_label)}") - if (isLeftPodInEar) append(", ${context.getString(R.string.pods_inear_label)}") - list.add(this.toString()) - } - - StringBuilder("${context.getString(R.string.pods_dual_right_label)}: ${getBatteryLevelRightPod(context)}").apply { - if (isRightPodCharging) append(", ${context.getString(R.string.pods_charging_label)}") - if (isRightPodInEar) append(", ${context.getString(R.string.pods_inear_label)}") - if (microPhonePod == Pod.RIGHT) append(", ${context.getString(R.string.pods_microphone_label)}") - list.add(this.toString()) - } - - StringBuilder("${context.getString(R.string.pods_case_label)}: ${getBatteryLevelCase(context)}").apply { - if (isCaseCharging) append(", ${context.getString(R.string.pods_charging_label)}") - list.add(this.toString()) - } - - return list - } - val microPhonePod: Pod get() = when (rawStatus.isBitSet(5)) { true -> Pod.LEFT diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/SingleApplePods.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/SingleApplePods.kt index a1f0bce5..7ddb43bf 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/SingleApplePods.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/SingleApplePods.kt @@ -1,24 +1,12 @@ package eu.darken.capod.pods.core.apple -import android.content.Context -import eu.darken.capod.R import eu.darken.capod.common.isBitSet import eu.darken.capod.common.upperNibble import eu.darken.capod.pods.core.HasEarDetection import eu.darken.capod.pods.core.HasSinglePod -import eu.darken.capod.pods.core.getBatteryLevelHeadset interface SingleApplePods : BasicSingleApplePods, HasEarDetection, HasSinglePod { - override fun getStatusShort(context: Context): String = context.getString( - R.string.pods_single_basic_status_short, - getBatteryLevelHeadset(context), - ) - - override fun getStatusLong(context: Context): List { - TODO("Not yet implemented") - } - val isHeadphonesBeingWorn: Boolean get() = rawStatus.isBitSet(1) diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/UnknownAppleDevice.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/UnknownAppleDevice.kt index f171d3dc..77ad1e60 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/UnknownAppleDevice.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/UnknownAppleDevice.kt @@ -18,11 +18,4 @@ data class UnknownAppleDevice( return context.getString(R.string.pods_unknown_label) } - override fun getStatusShort(context: Context): String { - return context.getString(R.string.pods_unknown_label) - } - - override fun getStatusLong(context: Context): List { - return listOf(rawDataHex) - } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml b/app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml new file mode 100644 index 00000000..20758530 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_battery_charging_full_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_question_mark_24.xml b/app/src/main/res/drawable/ic_baseline_question_mark_24.xml new file mode 100644 index 00000000..0e1bfc82 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_question_mark_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/monitor_notification_dual_pods_big.xml b/app/src/main/res/layout/monitor_notification_dual_pods_big.xml new file mode 100644 index 00000000..77d9ef65 --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_dual_pods_big.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/monitor_notification_dual_pods_small.xml b/app/src/main/res/layout/monitor_notification_dual_pods_small.xml new file mode 100644 index 00000000..f223b0c3 --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_dual_pods_small.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/monitor_notification_single_pods_small.xml b/app/src/main/res/layout/monitor_notification_single_pods_small.xml new file mode 100644 index 00000000..2c9577cd --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_single_pods_small.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/monitor_notification_unknown_device_small.xml b/app/src/main/res/layout/monitor_notification_unknown_device_small.xml new file mode 100644 index 00000000..ff1ff580 --- /dev/null +++ b/app/src/main/res/layout/monitor_notification_unknown_device_small.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..59ece707 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,4 @@ + + + 64dp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9963d974..1243eea8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -36,7 +36,6 @@ Headphones Left pod Right pod - L %1$s | C %2$s | R %3$s Case Open Closed