begin making new bt scan gui

pull/8/head
geeksville 2020-02-13 09:25:39 -08:00
rodzic 4e6d1be954
commit bd65bfee0a
9 zmienionych plików z 178 dodań i 52 usunięć

Wyświetl plik

@ -1,7 +1,8 @@
# High priority
MVP features required for first public alpha
* start bt receive on boot
* test bt boot behavior
* 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
* let the user type texts somewhere
* include a background behind our cloud graphics, so redraws work properly
@ -13,7 +14,6 @@ MVP features required for first public alpha
* make nodeinfo card not look like ass
* at connect we might receive messages before finished downloading the nodeinfo. In that case, process those messages later
* connect to bluetooth device automatically using minimum power - start looking at phone boot
* fix BT device scanning
* call crashlytics from exceptionReporter!!! currently not logging failures caught there
* test with oldest compatible android in emulator (see below for testing with hardware)
* make playstore entry, first public alpha
@ -94,3 +94,4 @@ Don't leave device discoverable. Don't let unpaired users do things with device
* when notified phone should automatically download messages
* use https://codelabs.developers.google.com/codelabs/jetpack-compose-basics/#4 to show service state
* all chat in the app defaults to group chat
* start bt receive on boot

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -12,7 +12,7 @@
*DeviceState.receive_queue max_count:32
# FIXME, max out based on total SubPacket size And do fragmentation and reassembly (for larger payloads) at the Android layer, not the esp32 layer.
*Data.payload max_size:200
*Data.payload max_size:251
# 128 bit psk key (we don't use 256 bit yet because we want to keep our QR code small)
*ChannelSettings.psk max_size:16 fixed_length:true

Wyświetl plik

@ -301,7 +301,11 @@ message DeviceState {
Current = 11;
};
/// A version integer used to invalidate old save files when we make incompatible changes
Version version = 6;
/// We keep the last received text message (only) stored in the device flash, so we can show it on the screen. Might be null
MeshPacket rx_text_message = 7;
}
// packets from the radio to the phone will appear on the fromRadio characteristic. It will support