kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
refactor: improve `BluetoothState.bondedDevices` updates
- add `BluetoothState` updates from `BluetoothDevice.ACTION_BOND_STATE_CHANGED` intents - convert `bondedDevices` to List instead of nested Flowpull/650/head
rodzic
cdea292169
commit
b41d92be32
|
@ -50,10 +50,10 @@ class BTScanModel @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
combine(
|
combine(
|
||||||
bluetoothRepository.state.value.bondedDevices,
|
bluetoothRepository.state,
|
||||||
usbRepository.serialDevicesWithDrivers
|
usbRepository.serialDevicesWithDrivers
|
||||||
) { ble, usb ->
|
) { ble, usb ->
|
||||||
bleDevices.value = ble
|
bleDevices.value = ble.bondedDevices
|
||||||
usbDevices.value = usb
|
usbDevices.value = usb
|
||||||
}.onEach { setupScan() }.launchIn(viewModelScope)
|
}.onEach { setupScan() }.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.geeksville.mesh.repository.bluetooth
|
package com.geeksville.mesh.repository.bluetooth
|
||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -14,7 +15,10 @@ import javax.inject.Inject
|
||||||
class BluetoothBroadcastReceiver @Inject constructor(
|
class BluetoothBroadcastReceiver @Inject constructor(
|
||||||
private val bluetoothRepository: BluetoothRepository
|
private val bluetoothRepository: BluetoothRepository
|
||||||
) : BroadcastReceiver() {
|
) : 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 {
|
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
|
||||||
if (intent.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
|
if (intent.action == BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||||
|
@ -24,8 +28,11 @@ class BluetoothBroadcastReceiver @Inject constructor(
|
||||||
BluetoothAdapter.STATE_ON -> bluetoothRepository.refreshState()
|
BluetoothAdapter.STATE_ON -> bluetoothRepository.refreshState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (intent.action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) {
|
||||||
|
bluetoothRepository.refreshState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Intent.bluetoothAdapterState: Int
|
private val Intent.bluetoothAdapterState: Int
|
||||||
get() = getIntExtra(BluetoothAdapter.EXTRA_STATE,-1)
|
get() = getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import androidx.lifecycle.coroutineScope
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.CoroutineDispatchers
|
import com.geeksville.mesh.CoroutineDispatchers
|
||||||
import com.geeksville.mesh.android.hasBluetoothPermission
|
import com.geeksville.mesh.android.hasBluetoothPermission
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -74,10 +73,14 @@ class BluetoothRepository @Inject constructor(
|
||||||
}
|
}
|
||||||
}?.let { adapter ->
|
}?.let { adapter ->
|
||||||
/// ask the adapter if we have access
|
/// ask the adapter if we have access
|
||||||
|
val enabled = adapter.isEnabled
|
||||||
|
val bondedDevices = adapter.bondedDevices ?: emptySet()
|
||||||
|
|
||||||
BluetoothState(
|
BluetoothState(
|
||||||
hasPermissions = true,
|
hasPermissions = true,
|
||||||
enabled = adapter.isEnabled,
|
enabled = enabled,
|
||||||
bondedDevices = createBondedDevicesFlow(adapter),
|
bondedDevices = if (!enabled) emptyList()
|
||||||
|
else bondedDevices.filter { it.name?.matches(Regex(BLE_NAME_PATTERN)) == true },
|
||||||
)
|
)
|
||||||
} ?: BluetoothState()
|
} ?: BluetoothState()
|
||||||
|
|
||||||
|
@ -85,22 +88,7 @@ class BluetoothRepository @Inject constructor(
|
||||||
debug("Detected our bluetooth access=$newState")
|
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 {
|
companion object {
|
||||||
const val BLE_NAME_PATTERN = "^.*_([0-9a-fA-F]{4})$"
|
const val BLE_NAME_PATTERN = "^.*_([0-9a-fA-F]{4})$"
|
||||||
const val REFRESH_DELAY_MS = 1000L
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package com.geeksville.mesh.repository.bluetooth
|
package com.geeksville.mesh.repository.bluetooth
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice
|
import android.bluetooth.BluetoothDevice
|
||||||
import kotlinx.coroutines.flow.Flow
|
import com.geeksville.mesh.util.anonymize
|
||||||
import kotlinx.coroutines.flow.flowOf
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A snapshot in time of the state of the bluetooth subsystem.
|
* A snapshot in time of the state of the bluetooth subsystem.
|
||||||
|
@ -12,6 +11,9 @@ data class BluetoothState(
|
||||||
val hasPermissions: Boolean = false,
|
val hasPermissions: Boolean = false,
|
||||||
/** If we have adequate permissions and bluetooth is enabled */
|
/** If we have adequate permissions and bluetooth is enabled */
|
||||||
val enabled: Boolean = false,
|
val enabled: Boolean = false,
|
||||||
/** If enabled, a cold flow of the currently bonded devices */
|
/** If enabled, a list of the currently bonded devices */
|
||||||
val bondedDevices: Flow<List<BluetoothDevice>> = flowOf(emptyList())
|
val bondedDevices: List<BluetoothDevice> = emptyList()
|
||||||
)
|
) {
|
||||||
|
override fun toString(): String =
|
||||||
|
"BluetoothState(hasPermissions=$hasPermissions, enabled=$enabled, bondedDevices=${bondedDevices.map { it.anonymize }})"
|
||||||
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ class RadioInterfaceService @Inject constructor(
|
||||||
init {
|
init {
|
||||||
processLifecycle.coroutineScope.launch {
|
processLifecycle.coroutineScope.launch {
|
||||||
bluetoothRepository.state.collect { state ->
|
bluetoothRepository.state.collect { state ->
|
||||||
if (state.enabled && !isStarted) {
|
if (state.enabled) {
|
||||||
startInterface()
|
startInterface()
|
||||||
} else if (radioIf is BluetoothInterface) {
|
} else if (radioIf is BluetoothInterface) {
|
||||||
stopInterface()
|
stopInterface()
|
||||||
|
|
Ładowanie…
Reference in New Issue