Add cache to (10s grace period) to listed pods.

This commit is contained in:
darken
2022-01-05 20:08:17 +01:00
parent cb7248327d
commit 6240a02c6c
14 changed files with 53 additions and 59 deletions
@@ -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<PodDevice.Id, PodDevice>()
val devices: Flow<List<PodDevice>> = generalSettings.scannerMode.flow
.flatMapLatest {
val mode = when (it) {
@@ -53,39 +57,26 @@ class PodMonitor @Inject constructor(
}
.onStart { emptyList<PodDevice>() }
.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<Byte>(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<Byte>(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<PodDevice.Id, PodDevice>()
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<PodDevice?>
@@ -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())
}
@@ -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<UUID, KnownDevice>()
private val knownDevs = mutableMapOf<PodDevice.Id, KnownDevice>()
data class ValueCache(
val caseBatteryPercentage: Float?
)
private val cachedValues = mutableMapOf<UUID, ValueCache>()
private val cachedValues = mutableMapOf<PodDevice.Id, ValueCache>()
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
@@ -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
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,