sforkowany z mirror/meshtastic-android
feat: update `devices` list from repositories
rodzic
2d0d7b3986
commit
804d4f0e27
|
@ -29,6 +29,7 @@ import com.geeksville.mesh.util.anonymize
|
|||
import com.hoho.android.usbserial.driver.UsbSerialDriver
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import java.util.regex.Pattern
|
||||
|
@ -45,11 +46,17 @@ class BTScanModel @Inject constructor(
|
|||
|
||||
private val context: Context get() = application.applicationContext
|
||||
val devices = MutableLiveData<MutableMap<String, DeviceListEntry>>(mutableMapOf())
|
||||
private val bleDevices = MutableLiveData<List<BluetoothDevice>>(listOf())
|
||||
private val usbDevices = MutableLiveData<Map<String, UsbSerialDriver>>(mapOf())
|
||||
|
||||
init {
|
||||
bluetoothRepository.state.value.bondedDevices.onEach {
|
||||
setupScan() // TODO clean up device list updates
|
||||
}.launchIn(viewModelScope)
|
||||
combine(
|
||||
bluetoothRepository.state.value.bondedDevices,
|
||||
usbRepository.serialDevicesWithDrivers
|
||||
) { ble, usb ->
|
||||
bleDevices.value = ble
|
||||
usbDevices.value = usb
|
||||
}.onEach { setupScan() }.launchIn(viewModelScope)
|
||||
|
||||
debug("BTScanModel created")
|
||||
}
|
||||
|
@ -166,7 +173,7 @@ class BTScanModel @Inject constructor(
|
|||
/**
|
||||
* returns true if we could start scanning, false otherwise
|
||||
*/
|
||||
fun setupScan(): Boolean {
|
||||
private fun setupScan(): Boolean {
|
||||
selectedAddress = radioInterfaceService.getDeviceAddress()
|
||||
|
||||
return if (MockInterface.addressValid(context, usbRepository, "")) {
|
||||
|
@ -192,24 +199,30 @@ class BTScanModel @Inject constructor(
|
|||
true
|
||||
} else {
|
||||
if (scanner == null) {
|
||||
// Clear the old device list
|
||||
devices.value?.clear()
|
||||
val newDevs = mutableMapOf<String, DeviceListEntry>()
|
||||
|
||||
fun addDevice(entry: DeviceListEntry) {
|
||||
newDevs[entry.fullAddress] = entry
|
||||
}
|
||||
|
||||
// Include a placeholder for "None"
|
||||
addDevice(DeviceListEntry(context.getString(R.string.none), "n", true))
|
||||
|
||||
// Include paired Bluetooth devices
|
||||
addBluetoothDevices()
|
||||
bleDevices.value?.forEach {
|
||||
addDevice(BLEDeviceListEntry(it))
|
||||
}
|
||||
|
||||
// Include Network Service Discovery
|
||||
nsdRepository.resolvedList?.forEach { service ->
|
||||
addDevice(TCPDeviceListEntry(service))
|
||||
}
|
||||
|
||||
val serialDevices by lazy { usbRepository.serialDevicesWithDrivers.value }
|
||||
serialDevices.forEach { (_, d) ->
|
||||
usbDevices.value?.forEach { (_, d) ->
|
||||
addDevice(USBDeviceListEntry(context.usbManager, d))
|
||||
}
|
||||
|
||||
devices.value = newDevs
|
||||
} else {
|
||||
debug("scan already running")
|
||||
}
|
||||
|
@ -271,15 +284,6 @@ class BTScanModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun addBluetoothDevices() {
|
||||
bluetoothRepository.getBondedDevices()
|
||||
?.filter { it.name != null && it.name.matches(Regex(BLE_NAME_PATTERN)) }
|
||||
?.forEach {
|
||||
addDevice(BLEDeviceListEntry(it))
|
||||
}
|
||||
}
|
||||
|
||||
private val _spinner = MutableLiveData(false)
|
||||
val spinner: LiveData<Boolean> get() = _spinner
|
||||
|
||||
|
@ -355,7 +359,7 @@ class BTScanModel @Inject constructor(
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val BLE_NAME_PATTERN = "^.*_([0-9a-fA-F]{4})$"
|
||||
const val BLE_NAME_PATTERN = BluetoothRepository.BLE_NAME_PATTERN
|
||||
const val ACTION_USB_PERMISSION = "com.geeksville.mesh.USB_PERMISSION"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,13 +66,6 @@ class BluetoothRepository @Inject constructor(
|
|||
?.bluetoothLeScanner
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun getBondedDevices(): Set<BluetoothDevice>? {
|
||||
return bluetoothAdapterLazy.get()
|
||||
?.takeIf { application.hasBluetoothPermission() }
|
||||
?.bondedDevices
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
internal suspend fun updateBluetoothState() {
|
||||
val newState: BluetoothState = bluetoothAdapterLazy.get()?.takeIf {
|
||||
|
@ -96,16 +89,18 @@ class BluetoothRepository @Inject constructor(
|
|||
* 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<Set<BluetoothDevice>> {
|
||||
return flow<Set<BluetoothDevice>> {
|
||||
private suspend fun createBondedDevicesFlow(adapter: BluetoothAdapter): Flow<List<BluetoothDevice>> {
|
||||
return flow<List<BluetoothDevice>> {
|
||||
val devices = adapter.bondedDevices ?: emptySet()
|
||||
while (true) {
|
||||
emit(adapter.bondedDevices ?: emptySet())
|
||||
emit(devices.filter { it.name != null && it.name.matches(Regex(BLE_NAME_PATTERN)) })
|
||||
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
|
||||
}
|
||||
}
|
|
@ -13,5 +13,5 @@ data class BluetoothState(
|
|||
/** 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<Set<BluetoothDevice>> = flowOf(emptySet())
|
||||
val bondedDevices: Flow<List<BluetoothDevice>> = flowOf(emptyList())
|
||||
)
|
||||
|
|
|
@ -12,7 +12,6 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.sync.Semaphore
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Singleton
|
||||
class NsdRepository @Inject constructor(
|
||||
|
@ -21,7 +20,7 @@ class NsdRepository @Inject constructor(
|
|||
) : Logging {
|
||||
|
||||
private val resolveQueue = Semaphore(1)
|
||||
private var hostsList: ArrayList<NsdServiceInfo>? = ArrayList()
|
||||
private var hostsList: ArrayList<NsdServiceInfo>? = null
|
||||
|
||||
val resolvedList: List<NsdServiceInfo>? get() = hostsList
|
||||
|
||||
|
@ -91,7 +90,7 @@ class NsdRepository @Inject constructor(
|
|||
|
||||
companion object {
|
||||
//To find all the available networks SERVICE_TYPE = "_services._dns-sd._udp"
|
||||
const val SERVICE_TYPE = "_http._tcp."
|
||||
const val SERVICE_TYPE = "_https._tcp."
|
||||
const val serviceName = "Meshtastic"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -712,8 +712,6 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
scanModel.setupScan()
|
||||
|
||||
// system permissions might have changed while we were away
|
||||
binding.provideLocationCheckbox.isChecked = requireContext().hasBackgroundPermission() && (model.provideLocation.value ?: false)
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue