diff --git a/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt b/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt index 617620e1..4dcc50c0 100644 --- a/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt +++ b/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt @@ -12,6 +12,8 @@ import eu.darken.capod.main.core.ScannerMode import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.PodFactory import kotlinx.coroutines.flow.* +import java.time.Duration +import java.time.Instant import javax.inject.Inject import javax.inject.Singleton @@ -23,6 +25,8 @@ class PodMonitor @Inject constructor( private val bluetoothManager: BluetoothManager2 ) { + private val deviceCache = mutableMapOf() + val devices: Flow> = generalSettings.scannerMode.flow .flatMapLatest { val mode = when (it) { @@ -53,39 +57,26 @@ class PodMonitor @Inject constructor( } .onStart { emptyList() } .map { scanResults -> - val pods = scanResults + val newPods = scanResults .sortedByDescending { it.rssi } .mapNotNull { podFactory.createPod(it) } -// if (BuildConfigWrap.DEBUG && scanResults.isNotEmpty()) { -// val fake1 = AirPodsMax( -// identifier = UUID.fromString("63436171-5433-4506-8bf5-faf6c35ffa8a"), -// scanResult = scanResults.first(), -// proximityMessage = ProximityPairing.Decoder().decode( -// message = ContinuityProtocol.Message( -// type = 0x07.toUByte(), -// length = 25, -// data = arrayOf(1, 10, 32, 98, 4, -128, 1, 15, 64, 13, 112, 80, 22, -14, 64, -125, 22, -65, 16, 22, 52, -101, 116, -124, -24).toByteArray().toUByteArray() -// ) -// )!! -// ) -// val fake2 = BeatsFlex( -// identifier = UUID.fromString("e563098d-ea24-4136-a169-5a59344317c3"), -// scanResult = scanResults.first(), -// proximityMessage = ProximityPairing.Decoder().decode( -// message = ContinuityProtocol.Message( -// type = 0x07.toUByte(), -// length = 25, -// data = arrayOf(1, 16, 32, 10, -12, -113, 0, 1, 0, -60, 113, -97, -100, -17, -94, -29, -70, 102, -2, 29, 69, -97, -55, 47, -96).toByteArray().toUByteArray() -// ) -// )!! -// ) -// pods.plus(fake1).plus(fake2) -// } else { -// pods -// } + val pods = mutableMapOf() - pods + pods.putAll(deviceCache) + pods.putAll(newPods.map { it.identifier to it }) + + val now = Instant.now() + pods.toList().forEach { (key, value) -> + if (Duration.between(value.lastSeenAt, now) > Duration.ofSeconds(10)) { + log(TAG, VERBOSE) { "Removing stale device from cache: $value" } + pods.remove(key) + } + } + deviceCache.clear() + deviceCache.putAll(pods) + + pods.values.toList() } val mainDevice: Flow 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 8fc718b1..56c3c370 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 @@ -10,7 +10,7 @@ import kotlin.math.abs interface PodDevice { - val identifier: UUID + val identifier: Id val lastSeenAt: Instant @@ -36,4 +36,7 @@ interface PodDevice { @get:DrawableRes val iconRes: Int get() = R.drawable.ic_device_generic_earbuds + + @JvmInline + value class Id(private val id: UUID = UUID.randomUUID()) } \ No newline at end of file diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/AppleFactory.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/AppleFactory.kt index f7598018..478e37ae 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/AppleFactory.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/AppleFactory.kt @@ -27,7 +27,7 @@ class AppleFactory @Inject constructor( ) { data class KnownDevice( - val identifier: UUID, + val identifier: PodDevice.Id, val scanResult: ScanResult, val message: ProximityPairing.Message, ) { @@ -47,13 +47,13 @@ class AppleFactory @Inject constructor( } private val lock = Mutex() - private val knownDevs = mutableMapOf() + private val knownDevs = mutableMapOf() data class ValueCache( val caseBatteryPercentage: Float? ) - private val cachedValues = mutableMapOf() + private val cachedValues = mutableMapOf() private suspend fun getMessage(scanResult: ScanResult): ProximityPairing.Message? { val messages = try { @@ -80,10 +80,10 @@ class AppleFactory @Inject constructor( return proximityMessage } - private suspend fun recognizeDevice(scanResult: ScanResult, message: ProximityPairing.Message): UUID { + private suspend fun recognizeDevice(scanResult: ScanResult, message: ProximityPairing.Message): PodDevice.Id { val address = scanResult.device.address - var identifier: UUID? = null + var identifier: PodDevice.Id? = null knownDevs.values.firstOrNull { it.address == address }?.let { log(TAG, VERBOSE) { "recognizeDevice: Recovered previous ID via address: $it" } @@ -128,7 +128,7 @@ class AppleFactory @Inject constructor( if (identifier == null) { log(TAG, VERBOSE) { "recognizeDevice: Mapping as new device" } - identifier = UUID.randomUUID() + identifier = PodDevice.Id() } knownDevs[identifier!!] = KnownDevice( @@ -168,7 +168,7 @@ class AppleFactory @Inject constructor( private fun createSpecificDevice( scanResult: ScanResult, pm: ProximityPairing.Message, - identifier: UUID + identifier: PodDevice.Id ): ApplePods { val cachedCaseBattery = cachedValues[identifier]?.caseBatteryPercentage 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 24b735d8..7b8de5e5 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 @@ -3,12 +3,12 @@ package eu.darken.capod.pods.core.apple import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class UnknownAppleDevice constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt index 070bb620..a45cbbb6 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen1.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.airpods import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class AirPodsGen1 constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message, diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt index 8eb62589..4dc46098 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsGen2.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.airpods import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class AirPodsGen2 constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message, diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt index fa636ffc..fc2c540e 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsMax.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.airpods import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.SingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class AirPodsMax constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message, diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt index 215b8125..2e318fdb 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/airpods/AirPodsPro.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.airpods import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class AirPodsPro constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message, diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFlex.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFlex.kt index 18dae06b..82a9c235 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFlex.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsFlex.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BasicSingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class BeatsFlex constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3.kt index 70c4fe37..1dfc8ce1 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsSolo3.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BasicSingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class BeatsSolo3 constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3.kt index cefb2e2e..6b84daed 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsStudio3.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BasicSingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class BeatsStudio3 constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsX.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsX.kt index 3b2e78b4..495e83ae 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsX.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/BeatsX.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BasicSingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class BeatsX constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3.kt index 440bf04e..c225fd37 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeats3.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.BasicSingleApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class PowerBeats3 constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message diff --git a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt index f4e37a28..f1980f19 100644 --- a/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt +++ b/app/src/main/java/eu/darken/capod/pods/core/apple/beats/PowerBeatsPro.kt @@ -3,13 +3,13 @@ package eu.darken.capod.pods.core.apple.beats import android.bluetooth.le.ScanResult import android.content.Context import eu.darken.capod.R +import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.apple.DualApplePods import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import java.time.Instant -import java.util.* data class PowerBeatsPro constructor( - override val identifier: UUID = UUID.randomUUID(), + override val identifier: PodDevice.Id = PodDevice.Id(), override val lastSeenAt: Instant = Instant.now(), override val scanResult: ScanResult, override val proximityMessage: ProximityPairing.Message,