begin bt scan cleanup

pull/8/head
geeksville 2020-02-18 08:56:53 -08:00
rodzic 26055038f7
commit f715091399
2 zmienionych plików z 83 dodań i 69 usunięć

Wyświetl plik

@ -1,8 +1,12 @@
# High priority
MVP features required for first public alpha
* describe user experience: devices always point to each other and show distance, you can send texts between nodes
the channel is encrypted, you can share the the channel key with others by qr code or by sharing a special link
* let user set name and shortname
* take video
* make a working currently vs not working list
* when we connect to radio, distances to nodes in the chat log should automatically redraw
* show pointer arrow on the outside of the user icons, always pointing towoards them

Wyświetl plik

@ -2,10 +2,7 @@ package com.geeksville.mesh.ui
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.bluetooth.le.*
import android.os.ParcelUuid
import androidx.compose.*
import androidx.compose.frames.modelMapOf
@ -20,18 +17,70 @@ import androidx.ui.tooling.preview.Preview
import com.geeksville.android.Logging
import com.geeksville.mesh.service.RadioInterfaceService
object BTLog : Logging
@Model
object ScanState {
object ScanUIState {
var selectedMacAddr: String? = null
var errorText: String? = null
val devices = modelMapOf<String, BTScanEntry>()
val scanCallback = object : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
val msg = "Unexpected bluetooth scan failure: $errorCode"
ScanUIState.errorText = msg
ScanState.reportError(msg)
}
// For each device that appears in our scan, ask for its GATT, when the gatt arrives,
// check if it is an eligable device and store it in our list of candidates
// if that device later disconnects remove it as a candidate
override fun onScanResult(callbackType: Int, result: ScanResult) {
val addr = result.device.address
// prevent logspam because weill get get lots of redundant scan results
if (!devices.contains(addr)) {
val entry = BTScanEntry(
result.device.name,
addr,
result.device.bondState == BluetoothDevice.BOND_BONDED
)
ScanState.debug("onScanResult ${entry}")
devices[addr] = entry
// If nothing was selected, by default select the first thing we see
if (ScanUIState.selectedMacAddr == null && entry.bonded)
changeSelection(addr)
}
}
}
/// Change to a new macaddr selection, updating GUI and radio
fun changeSelection(newAddr: String) {
ScanState.info("Changing BT device to $newAddr")
val context = ambient(ContextAmbient)
selectedMacAddr = newAddr
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
}
}
/// FIXME, remove once compose has better lifecycle management
object ScanState : Logging {
var scanner: BluetoothLeScanner? = null
var callback: ScanCallback? = null // SUPER NASTY FIXME
fun stopScan() {
if (callback != null) {
debug("stopping scan")
scanner!!.stopScan(callback)
} else
debug("not stopping bt scanner")
}
}
@Model
data class BTScanEntry(val name: String, val macAddress: String, val bonded: Boolean) {
val isSelected get() = macAddress == ScanState.selectedMacAddr
val isSelected get() = macAddress == ScanUIState.selectedMacAddr
}
@ -41,68 +90,29 @@ fun BTScanScreen() {
/// Note: may be null on platforms without a bluetooth driver (ie. the emulator)
val bluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
val devices = modelMapOf<String, BTScanEntry>()
ScanState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
fun changeSelection(newAddr: String) {
BTLog.info("Changing BT device to $newAddr")
ScanState.selectedMacAddr = newAddr
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
}
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager)?.adapter
onActive {
ScanUIState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
if (bluetoothAdapter == null) {
BTLog.warn("No bluetooth adapter. Running under emulation?")
ScanState.warn("No bluetooth adapter. Running under emulation?")
val testnodes = listOf(
BTScanEntry("Meshtastic_ab12", "xx", false),
BTScanEntry("Meshtastic_32ac", "xb", true)
)
devices.putAll(testnodes.map { it.macAddress to it })
ScanUIState.devices.putAll(testnodes.map { it.macAddress to it })
// If nothing was selected, by default select the first thing we see
if (ScanState.selectedMacAddr == null)
changeSelection(testnodes.first().macAddress)
if (ScanUIState.selectedMacAddr == null)
ScanUIState.changeSelection(testnodes.first().macAddress)
} else {
val scanner = bluetoothAdapter.bluetoothLeScanner
val s = bluetoothAdapter.bluetoothLeScanner
// ScanState.scanner = scanner
val scanCallback = object : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
val msg = "Unexpected bluetooth scan failure: $errorCode"
ScanState.errorText = msg
BTLog.reportError(msg)
}
// For each device that appears in our scan, ask for its GATT, when the gatt arrives,
// check if it is an eligable device and store it in our list of candidates
// if that device later disconnects remove it as a candidate
override fun onScanResult(callbackType: Int, result: ScanResult) {
val addr = result.device.address
// prevent logspam because weill get get lots of redundant scan results
if (!devices.contains(addr)) {
val entry = BTScanEntry(
result.device.name,
addr,
result.device.bondState == BluetoothDevice.BOND_BONDED
)
BTLog.debug("onScanResult ${entry}")
devices[addr] = entry
// If nothing was selected, by default select the first thing we see
if (ScanState.selectedMacAddr == null && entry.bonded)
changeSelection(addr)
}
}
}
BTLog.debug("starting scan")
ScanState.debug("starting scan")
// filter and only accept devices that have a sw update service
val filter =
@ -112,22 +122,21 @@ fun BTScanScreen() {
val settings =
ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
scanner.startScan(listOf(filter), settings, scanCallback)
s.startScan(listOf(filter), settings, ScanUIState.scanCallback)
ScanState.scanner = s
ScanState.callback = ScanUIState.scanCallback
}
onDispose {
BTLog.debug("stopping scan")
scanner.stopScan(scanCallback)
}
onDispose {
ScanState.stopScan()
}
}
Column {
if (ScanState.errorText != null) {
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanState.errorText}")
if (ScanUIState.errorText != null) {
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanUIState.errorText}")
} else {
if (devices.isEmpty()) {
if (ScanUIState.devices.isEmpty()) {
Text("Looking for Meshtastic devices... (zero found)")
CircularProgressIndicator() // Show that we are searching still
@ -144,7 +153,7 @@ fun BTScanScreen() {
RadioGroup {
Column {
devices.values.forEach {
ScanUIState.devices.values.forEach {
// disabled pending https://issuetracker.google.com/issues/149528535
ProvideEmphasis(emphasis = if (it.bonded) EmphasisLevels().high else EmphasisLevels().disabled) {
RadioGroupTextItem(
@ -152,12 +161,13 @@ fun BTScanScreen() {
onSelect = {
// If the device is paired, let user select it, otherwise start the pairing flow
if (it.bonded)
changeSelection(it.macAddress)
ScanUIState.changeSelection(it.macAddress)
else {
BTLog.info("Starting bonding for $it")
ScanState.info("Starting bonding for $it")
// We ignore missing BT adapters, because it lets us run on the emulator
bluetoothAdapter?.getRemoteDevice(it.macAddress)
bluetoothAdapter
?.getRemoteDevice(it.macAddress)
?.createBond()
}
},