Cache main pod device

This commit is contained in:
darken
2022-09-14 18:00:18 +02:00
committed by Matthias Urhahn
parent 87bef9cb9c
commit 62afb7a130
5 changed files with 108 additions and 29 deletions
@@ -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")
}