kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
new bt scan gui kinda works
rodzic
bd65bfee0a
commit
d4cf41c98a
10
TODO.md
10
TODO.md
|
@ -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.
|
||||||
|
|
|
@ -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))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue