new bt scan gui kinda works

pull/8/head
geeksville 2020-02-13 19:02:40 -08:00
rodzic bd65bfee0a
commit d4cf41c98a
3 zmienionych plików z 97 dodań i 48 usunięć

10
TODO.md
Wyświetl plik

@ -1,6 +1,14 @@
# High priority # High priority
MVP features required for first public alpha MVP features required for first public alpha
* if no radio is selected, launch app on the radio select screen
* warn user to bt pair
* show bt scan progress centered and towards the bottom of the screen
* get rid of green bar at top
* change titlebar based off which screen we are showing
* fix app icon in title bar
* add alphatest screen at boot
* prompt user to turnon bluetooth and bind
* test bt boot behavior * test bt boot behavior
* fix BT device scanning - make a setup screen * fix BT device scanning - make a setup screen
* when a text arrives, move that node info card to the bottom on the window - put the text to the left of the card. with a small arrow/distance/shortname * when a text arrives, move that node info card to the bottom on the window - put the text to the left of the card. with a small arrow/distance/shortname
@ -17,6 +25,8 @@ MVP features required for first public alpha
* call crashlytics from exceptionReporter!!! currently not logging failures caught there * call crashlytics from exceptionReporter!!! currently not logging failures caught there
* test with oldest compatible android in emulator (see below for testing with hardware) * test with oldest compatible android in emulator (see below for testing with hardware)
* make playstore entry, first public alpha * make playstore entry, first public alpha
* tell Compose geeks
* tell various vendors & post in forum
# Signal alpha release # Signal alpha release
Do this "Signal app compatible" release relatively soon after the alpha release of the android app. Do this "Signal app compatible" release relatively soon after the alpha release of the android app.

Wyświetl plik

@ -1,30 +0,0 @@
package com.geeksville.mesh.ui
import androidx.compose.Composable
import androidx.compose.Model
import androidx.ui.core.Text
import androidx.ui.layout.Column
import androidx.ui.layout.Row
import androidx.ui.tooling.preview.Preview
@Model
data class BTScanEntry(val name: String, val macAddress: String, var selected: Boolean)
@Composable
fun BTScanCard(node: BTScanEntry) {
// Text("Node: ${it.user?.longName}")
Row {
Text(node.name)
Text(node.selected.toString())
}
}
@Preview
@Composable
fun btScanPreview() {
Column {
BTScanCard(BTScanEntry("Meshtastic_ab12", "xx", true))
BTScanCard(BTScanEntry("Meshtastic_32ac", "xx", false))
}
}

Wyświetl plik

@ -6,19 +6,32 @@ import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings import android.bluetooth.le.ScanSettings
import android.os.ParcelUuid import android.os.ParcelUuid
import androidx.compose.Composable import androidx.compose.*
import androidx.compose.Context import androidx.compose.frames.modelMapOf
import androidx.compose.ambient
import androidx.compose.onActive
import androidx.ui.core.ContextAmbient import androidx.ui.core.ContextAmbient
import androidx.ui.core.Text import androidx.ui.core.Text
import androidx.ui.layout.Column import androidx.ui.layout.Column
import androidx.ui.material.CircularProgressIndicator
import androidx.ui.material.RadioGroup
import androidx.ui.tooling.preview.Preview import androidx.ui.tooling.preview.Preview
import com.geeksville.android.Logging import com.geeksville.android.Logging
import com.geeksville.mesh.service.RadioInterfaceService import com.geeksville.mesh.service.RadioInterfaceService
object BTLog : Logging object BTLog : Logging
@Model
object ScanState {
var selectedMacAddr: String? = null
var errorText: String? = null
}
@Model
data class BTScanEntry(val name: String, val macAddress: String) {
val isSelected get() = macAddress == ScanState.selectedMacAddr
}
@Composable @Composable
fun BTScanScreen() { fun BTScanScreen() {
val context = ambient(ContextAmbient) val context = ambient(ContextAmbient)
@ -27,16 +40,39 @@ fun BTScanScreen() {
val bluetoothAdapter = val bluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
val devices = modelMapOf<String, BTScanEntry>()
ScanState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
fun changeSelection(newAddr: String) {
ScanState.selectedMacAddr = newAddr
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
}
onActive { onActive {
if (bluetoothAdapter == null) if (bluetoothAdapter == null) {
BTLog.warn("No bluetooth adapter. Running under emulation?") BTLog.warn("No bluetooth adapter. Running under emulation?")
else {
val testnodes = listOf(
BTScanEntry("Meshtastic_ab12", "xx"),
BTScanEntry("Meshtastic_32ac", "xb")
)
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)
} else {
val scanner = bluetoothAdapter.bluetoothLeScanner val scanner = bluetoothAdapter.bluetoothLeScanner
// ScanState.scanner = scanner
val scanCallback = object : ScanCallback() { val scanCallback = object : ScanCallback() {
override fun onScanFailed(errorCode: Int) { override fun onScanFailed(errorCode: Int) {
TODO() // FIXME, update gui with message about this 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, // For each device that appears in our scan, ask for its GATT, when the gatt arrives,
@ -44,10 +80,14 @@ fun BTScanScreen() {
// if that device later disconnects remove it as a candidate // if that device later disconnects remove it as a candidate
override fun onScanResult(callbackType: Int, result: ScanResult) { override fun onScanResult(callbackType: Int, result: ScanResult) {
BTLog.info("onScanResult ${result.device.address}") val addr = result.device.address
BTLog.debug("onScanResult ${addr}")
devices[addr] =
BTScanEntry(result.device.name, addr)
// We don't need any more results now // If nothing was selected, by default select the first thing we see
// scanner.stopScan(this) if (ScanState.selectedMacAddr == null)
changeSelection(addr)
} }
} }
@ -59,14 +99,8 @@ fun BTScanScreen() {
.setServiceUuid(ParcelUuid(RadioInterfaceService.BTM_SERVICE_UUID)) .setServiceUuid(ParcelUuid(RadioInterfaceService.BTM_SERVICE_UUID))
.build() .build()
/* ScanSettings.CALLBACK_TYPE_FIRST_MATCH seems to trigger a bug returning an error of
SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES (error #5)
*/
val settings = val settings =
ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY). ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
// setMatchMode(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT).
// setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH).
build()
scanner.startScan(listOf(filter), settings, scanCallback) scanner.startScan(listOf(filter), settings, scanCallback)
onDispose { onDispose {
@ -76,8 +110,43 @@ fun BTScanScreen() {
} }
} }
Column { Column {
Text("FIXME") if (ScanState.errorText != null) {
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanState.errorText}")
} else {
if (devices.isEmpty())
Text("Looking for Meshtastic devices... (zero found)")
else {
val allPaired = bluetoothAdapter?.bondedDevices.orEmpty().map { it.address }
// Only let user select paired devices
val paired = devices.values.filter { allPaired.contains(it.macAddress) }
if (paired.size < devices.size) {
Text(
"Warning: there are nearby Meshtastic devices that are not paired with this phone. Before you can select a device, you will need to pair it in Bluetooth Settings."
)
}
RadioGroup {
Column {
paired.forEach {
// disabled pending https://issuetracker.google.com/issues/149528535
//ProvideEmphasis(emphasis = if (allPaired.contains(it.macAddress)) EmphasisLevels().medium else EmphasisLevels().disabled) {
RadioGroupTextItem(
selected = (it.isSelected),
onSelect = { changeSelection(it.macAddress) },
text = it.name
)
//}
}
}
}
}
CircularProgressIndicator() // Show that we are searching still
}
} }
} }