begin making new bt scan gui

This commit is contained in:
geeksville
2020-02-13 09:25:39 -08:00
parent 4e6d1be954
commit bd65bfee0a
9 changed files with 178 additions and 52 deletions

View File

@@ -172,7 +172,7 @@ class MainActivity : AppCompatActivity(), Logging,
/* Do this better FIXME */
val usetbeam = false
val address = if (usetbeam) "B4:E6:2D:EA:32:B7" else "24:6F:28:96:C9:2A"
RadioInterfaceService.setBondedDeviceAddress(this, address)
RadioInterfaceService.setBondedDeviceAddress(this, null)
requestPermission()
}

View File

@@ -97,7 +97,9 @@ class RadioInterfaceService : Service(), Logging {
*/
const val RADIO_CONNECTED_ACTION = "$prefix.CONNECT_CHANGED"
private val BTM_SERVICE_UUID = UUID.fromString("6ba1b218-15a8-461f-9fa8-5dcae273eafd")
/// this service UUID is publically visible for scanning
val BTM_SERVICE_UUID = UUID.fromString("6ba1b218-15a8-461f-9fa8-5dcae273eafd")
private val BTM_FROMRADIO_CHARACTER =
UUID.fromString("8ba2bcc2-ee02-4a55-a531-c525c5e454d5")
private val BTM_TORADIO_CHARACTER =
@@ -131,11 +133,19 @@ class RadioInterfaceService : Service(), Logging {
private fun getPrefs(context: Context) =
context.getSharedPreferences("radio-prefs", Context.MODE_PRIVATE)
/// Return the device we are configured to use, or null for none
fun getBondedDeviceAddress(context: Context) = getPrefs(context).getString("devAddr", null)
private const val DEVADDR_KEY = "devAddr"
fun setBondedDeviceAddress(context: Context, addr: String) =
getPrefs(context).edit(commit = true) { putString("devAddr", addr) }
/// Return the device we are configured to use, or null for none
fun getBondedDeviceAddress(context: Context) =
getPrefs(context).getString(DEVADDR_KEY, null)
fun setBondedDeviceAddress(context: Context, addr: String?) =
getPrefs(context).edit(commit = true) {
if (addr == null)
this.remove(DEVADDR_KEY)
else
putString(DEVADDR_KEY, addr)
}
}
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {

View File

@@ -0,0 +1,30 @@
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))
}
}

View File

@@ -0,0 +1,89 @@
package com.geeksville.mesh.ui
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.os.ParcelUuid
import androidx.compose.Composable
import androidx.compose.Context
import androidx.compose.ambient
import androidx.compose.onActive
import androidx.ui.core.ContextAmbient
import androidx.ui.core.Text
import androidx.ui.layout.Column
import androidx.ui.tooling.preview.Preview
import com.geeksville.android.Logging
import com.geeksville.mesh.service.RadioInterfaceService
object BTLog : Logging
@Composable
fun BTScanScreen() {
val context = ambient(ContextAmbient)
/// Note: may be null on platforms without a bluetooth driver (ie. the emulator)
val bluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
onActive {
if (bluetoothAdapter == null)
BTLog.warn("No bluetooth adapter. Running under emulation?")
else {
val scanner = bluetoothAdapter.bluetoothLeScanner
val scanCallback = object : ScanCallback() {
override fun onScanFailed(errorCode: Int) {
TODO() // FIXME, update gui with message about this
}
// 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) {
BTLog.info("onScanResult ${result.device.address}")
// We don't need any more results now
// scanner.stopScan(this)
}
}
BTLog.debug("starting scan")
// filter and only accept devices that have a sw update service
val filter =
ScanFilter.Builder()
.setServiceUuid(ParcelUuid(RadioInterfaceService.BTM_SERVICE_UUID))
.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 =
ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).
// setMatchMode(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT).
// setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH).
build()
scanner.startScan(listOf(filter), settings, scanCallback)
onDispose {
BTLog.debug("stopping scan")
scanner.stopScan(scanCallback)
}
}
}
Column {
Text("FIXME")
}
}
@Preview
@Composable
fun btScanScreenPreview() {
BTScanScreen()
}

View File

@@ -20,9 +20,6 @@ import com.geeksville.mesh.R
@Composable
fun HomeContent() {
Column {
Text(text = "Meshtastic")
Row {
Container(LayoutSize(40.dp, 40.dp)) {
VectorImage(id = if (UIState.isConnected.value) R.drawable.cloud_on else R.drawable.cloud_off)
@@ -57,23 +54,6 @@ fun HomeContent() {
}
}
@Composable
fun HomeScreen(openDrawer: () -> Unit) {
Column {
TopAppBar(
title = { Text(text = "Meshtastic") },
navigationIcon = {
VectorImageButton(R.drawable.ic_launcher_new_foreground) {
openDrawer()
}
}
)
VerticalScroller(modifier = LayoutFlexible(1f)) {
HomeContent()
}
}
}
@Composable
fun MeshApp() {
@@ -108,10 +88,26 @@ fun previewView() {
private fun AppContent(openDrawer: () -> Unit) {
Crossfade(AppStatus.currentScreen) { screen ->
Surface(color = (MaterialTheme.colors()).background) {
when (screen) {
is Screen.Home -> HomeScreen { openDrawer() }
/* is Screen.Interests -> InterestsScreen { openDrawer() }
is Screen.Article -> ArticleScreen(postId = screen.postId) */
Column {
TopAppBar(
title = { Text(text = "Meshtastic") },
navigationIcon = {
VectorImageButton(R.drawable.ic_launcher_new_foreground) {
openDrawer()
}
}
)
VerticalScroller(modifier = LayoutFlexible(1f)) {
when (screen) {
is Screen.Home -> HomeContent()
is Screen.SelectRadio -> BTScanScreen()
// Question: how to get hooks invoked when this screen gets shown/removed?
// i.e. I need to start/stop a bluetooth scan operation. depending on the
// appearance/disappearance of this screen.
}
}
}
}
}
@@ -133,25 +129,21 @@ private fun AppDrawer(
VectorImage(id = R.drawable.ic_launcher_new_foreground)
}
Divider(color = Color(0x14333333))
DrawerButton(
icon = R.drawable.ic_launcher_new_foreground,
label = "Home",
isSelected = currentScreen == Screen.Home
) {
navigateTo(Screen.Home)
closeDrawer()
@Composable
fun ScreenButton(icon: Int, label: String, screen: Screen) {
DrawerButton(
icon = icon,
label = label,
isSelected = currentScreen == screen
) {
navigateTo(screen)
closeDrawer()
}
}
/*
DrawerButton(
icon = R.drawable.ic_interests,
label = "Interests",
isSelected = currentScreen == Screen.Interests
) {
navigateTo(Screen.Interests)
closeDrawer()
}
*/
ScreenButton(R.drawable.ic_launcher_new_foreground, "Home", Screen.Home)
ScreenButton(R.drawable.ic_launcher_new_foreground, "Setup", Screen.SelectRadio)
}
}

View File

@@ -10,7 +10,7 @@ import java.util.*
// defines the screens we have in the app
sealed class Screen {
object Home : Screen()
// object Settings : Screen()
object SelectRadio : Screen()
}
@Model
@@ -22,7 +22,7 @@ data class TextMessage(val date: Date, val from: String, val text: String)
/// FIXME - figure out how to merge this staate with the AppStatus Model
object UIState {
private val testPositions = arrayOf(
Position(32.776665, -96.796989, 35), // dallas
Position(32.960758, -96.733521, 35), // richardson