feat: update `devices` list from repositories

master
andrekir 2023-04-06 21:04:03 -03:00
rodzic 2d0d7b3986
commit 804d4f0e27
5 zmienionych plików z 31 dodań i 35 usunięć

Wyświetl plik

@ -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"
}
}

Wyświetl plik

@ -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
}
}

Wyświetl plik

@ -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())
)

Wyświetl plik

@ -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"
}
}

Wyświetl plik

@ -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)