refactor: improve `BluetoothState.bondedDevices` updates

- add `BluetoothState` updates from `BluetoothDevice.ACTION_BOND_STATE_CHANGED` intents
- convert `bondedDevices` to List instead of nested Flow
pull/650/head
andrekir 2023-06-29 21:29:38 -03:00
rodzic cdea292169
commit b41d92be32
5 zmienionych plików z 27 dodań i 30 usunięć

Wyświetl plik

@ -50,10 +50,10 @@ class BTScanModel @Inject constructor(
init {
combine(
bluetoothRepository.state.value.bondedDevices,
bluetoothRepository.state,
usbRepository.serialDevicesWithDrivers
) { ble, usb ->
bleDevices.value = ble
bleDevices.value = ble.bondedDevices
usbDevices.value = usb
}.onEach { setupScan() }.launchIn(viewModelScope)

Wyświetl plik

@ -1,6 +1,7 @@
package com.geeksville.mesh.repository.bluetooth
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@ -14,7 +15,10 @@ import javax.inject.Inject
class BluetoothBroadcastReceiver @Inject constructor(
private val bluetoothRepository: BluetoothRepository
) : BroadcastReceiver() {
internal val intentFilter get() = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) // Can be used for registering
internal val intentFilter = IntentFilter().apply {
addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED)
}
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
if (intent.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
@ -24,8 +28,11 @@ class BluetoothBroadcastReceiver @Inject constructor(
BluetoothAdapter.STATE_ON -> bluetoothRepository.refreshState()
}
}
if (intent.action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) {
bluetoothRepository.refreshState()
}
}
private val Intent.bluetoothAdapterState: Int
get() = getIntExtra(BluetoothAdapter.EXTRA_STATE,-1)
}
get() = getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
}

Wyświetl plik

@ -10,7 +10,6 @@ import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.android.hasBluetoothPermission
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ -74,10 +73,14 @@ class BluetoothRepository @Inject constructor(
}
}?.let { adapter ->
/// ask the adapter if we have access
val enabled = adapter.isEnabled
val bondedDevices = adapter.bondedDevices ?: emptySet()
BluetoothState(
hasPermissions = true,
enabled = adapter.isEnabled,
bondedDevices = createBondedDevicesFlow(adapter),
enabled = enabled,
bondedDevices = if (!enabled) emptyList()
else bondedDevices.filter { it.name?.matches(Regex(BLE_NAME_PATTERN)) == true },
)
} ?: BluetoothState()
@ -85,22 +88,7 @@ class BluetoothRepository @Inject constructor(
debug("Detected our bluetooth access=$newState")
}
/**
* Creates a cold Flow used to obtain the set of bonded devices.
*/
@SuppressLint("MissingPermission") // Already checked prior to calling
private suspend fun createBondedDevicesFlow(adapter: BluetoothAdapter): Flow<List<BluetoothDevice>> {
return flow<List<BluetoothDevice>> {
val devices = adapter.bondedDevices ?: emptySet()
while (true) {
emit(devices.filter { it.name?.matches(Regex(BLE_NAME_PATTERN)) == true })
delay(REFRESH_DELAY_MS)
}
}.flowOn(dispatchers.default).distinctUntilChanged()
}
companion object {
const val BLE_NAME_PATTERN = "^.*_([0-9a-fA-F]{4})$"
const val REFRESH_DELAY_MS = 1000L
}
}
}

Wyświetl plik

@ -1,8 +1,7 @@
package com.geeksville.mesh.repository.bluetooth
import android.bluetooth.BluetoothDevice
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import com.geeksville.mesh.util.anonymize
/**
* A snapshot in time of the state of the bluetooth subsystem.
@ -12,6 +11,9 @@ data class BluetoothState(
val hasPermissions: Boolean = false,
/** If we have adequate permissions and bluetooth is enabled */
val enabled: Boolean = false,
/** If enabled, a cold flow of the currently bonded devices */
val bondedDevices: Flow<List<BluetoothDevice>> = flowOf(emptyList())
)
/** If enabled, a list of the currently bonded devices */
val bondedDevices: List<BluetoothDevice> = emptyList()
) {
override fun toString(): String =
"BluetoothState(hasPermissions=$hasPermissions, enabled=$enabled, bondedDevices=${bondedDevices.map { it.anonymize }})"
}

Wyświetl plik

@ -74,7 +74,7 @@ class RadioInterfaceService @Inject constructor(
init {
processLifecycle.coroutineScope.launch {
bluetoothRepository.state.collect { state ->
if (state.enabled && !isStarted) {
if (state.enabled) {
startInterface()
} else if (radioIf is BluetoothInterface) {
stopInterface()