mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-15 02:36:12 -04:00
Add cache to (10s grace period) to listed pods.
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user