mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Cache main pod device
This commit is contained in:
@@ -3,14 +3,17 @@ package eu.darken.capod.common.bluetooth
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.os.Parcelable
|
||||
import androidx.core.util.forEach
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class BleScanResult(
|
||||
val address: String,
|
||||
val rssi: Int,
|
||||
val generatedAtNanos: Long,
|
||||
val manufacturerSpecificData: Map<Int, ByteArray>
|
||||
@Json(name = "address") val address: String,
|
||||
@Json(name = "rssi") val rssi: Int,
|
||||
@Json(name = "generatedAtNanos") val generatedAtNanos: Long,
|
||||
@Json(name = "manufacturerSpecificData") val manufacturerSpecificData: Map<Int, ByteArray>
|
||||
) : Parcelable {
|
||||
|
||||
fun getManufacturerSpecificData(id: Int): ByteArray? = manufacturerSpecificData[id]
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package eu.darken.capod.monitor.core
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapter
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import eu.darken.capod.common.bluetooth.BleScanResult
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.ERROR
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.VERBOSE
|
||||
import eu.darken.capod.common.debug.logging.asLog
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
@Singleton
|
||||
class PodDeviceCache @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
moshi: Moshi,
|
||||
) {
|
||||
private val cacheDir by lazy {
|
||||
File(context.cacheDir, "device_cache").apply { mkdirs() }
|
||||
}
|
||||
private val mainDeviceCacheFile = File(cacheDir, "main_device.raw")
|
||||
private val jsonAdapter = moshi.adapter<BleScanResult>()
|
||||
private val lock = Mutex()
|
||||
|
||||
suspend fun saveMainDevice(device: BleScanResult?) = withContext(dispatcherProvider.IO) {
|
||||
log(TAG, VERBOSE) { "saveMainDevice(device=$device)" }
|
||||
lock.withLock {
|
||||
try {
|
||||
if (device == null) {
|
||||
mainDeviceCacheFile.delete()
|
||||
} else {
|
||||
val json = jsonAdapter.toJson(device)
|
||||
mainDeviceCacheFile.writeText(json)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
log(TAG, ERROR) { "Failed to save $device:${e.asLog()}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun loadMainDevice(): BleScanResult? = withContext(dispatcherProvider.IO) {
|
||||
log(TAG) { "loadMainDevice()" }
|
||||
lock.withLock {
|
||||
try {
|
||||
val raw = mainDeviceCacheFile.readText()
|
||||
jsonAdapter.fromJson(raw)
|
||||
} catch (e: Exception) {
|
||||
log(TAG, ERROR) { "Failed to read main-device:${e.asLog()}" }
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Monitor", "PodMonitor", "Cache")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,13 @@ import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class PodMonitor @Inject constructor(
|
||||
@AppScope private val appScope: CoroutineScope,
|
||||
private val bleScanner: BleScanner,
|
||||
private val podFactory: PodFactory,
|
||||
private val generalSettings: GeneralSettings,
|
||||
private val bluetoothManager: BluetoothManager2,
|
||||
private val debugSettings: DebugSettings,
|
||||
@AppScope private val appScope: CoroutineScope
|
||||
private val podDeviceCache: PodDeviceCache,
|
||||
) {
|
||||
|
||||
private val deviceCache = mutableMapOf<PodDevice.Id, PodDevice>()
|
||||
@@ -42,7 +43,7 @@ class PodMonitor @Inject constructor(
|
||||
|
||||
private suspend fun List<BleScanResult>.preFilterAndMap(
|
||||
scannerMode: ScannerMode
|
||||
): List<PodDevice> = this
|
||||
): List<PodFactory.Result> = this
|
||||
.groupBy { it.address }
|
||||
.values
|
||||
.map { sameAdrDevs ->
|
||||
@@ -103,7 +104,7 @@ class PodMonitor @Inject constructor(
|
||||
|
||||
pods.putAll(deviceCache)
|
||||
|
||||
newPods.forEach {
|
||||
newPods.map { it.device }.forEach {
|
||||
deviceCache[it.identifier] = it
|
||||
pods[it.identifier] = it
|
||||
}
|
||||
@@ -111,6 +112,9 @@ class PodMonitor @Inject constructor(
|
||||
|
||||
val presorted = pods.values.sortPodsToInterest()
|
||||
val main = presorted.determineMainDevice()
|
||||
newPods?.firstOrNull { it.device.identifier == main?.identifier }?.let {
|
||||
podDeviceCache.saveMainDevice(it.scanResult)
|
||||
}
|
||||
|
||||
presorted.sortedByDescending { it == main }
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class PodFactory @Inject constructor(
|
||||
private val unknownFactory: UnknownDeviceFactory,
|
||||
) {
|
||||
|
||||
suspend fun createPod(scanResult: BleScanResult): PodDevice? {
|
||||
suspend fun createPod(scanResult: BleScanResult): Result? {
|
||||
log(TAG, VERBOSE) { "Trying to create Pod for $scanResult" }
|
||||
|
||||
log(TAG, INFO) { "Decoding $scanResult" }
|
||||
@@ -29,9 +29,16 @@ class PodFactory @Inject constructor(
|
||||
}
|
||||
|
||||
log(TAG, INFO) { "Pod created: $device" }
|
||||
return device
|
||||
return device?.let {
|
||||
Result(scanResult = scanResult, device = it)
|
||||
}
|
||||
}
|
||||
|
||||
data class Result(
|
||||
val scanResult: BleScanResult,
|
||||
val device: PodDevice
|
||||
)
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Pod", "Factory")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user