bt scan kinda works

1.2-legacy
geeksville 2020-02-13 19:54:05 -08:00
rodzic d4cf41c98a
commit 4f75601786
4 zmienionych plików z 73 dodań i 39 usunięć

Wyświetl plik

@ -2,11 +2,13 @@
MVP features required for first public alpha
* if no radio is selected, launch app on the radio select screen
* warn user to bt pair
* when we select a new radio, restart the service
* 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
* treat macaddrs as the unique id, not the app layer user id
* on onStop somehow stop the BT scan (to prevent burning battery)
* add alphatest screen at boot
* prompt user to turnon bluetooth and bind
* test bt boot behavior
@ -105,3 +107,4 @@ Don't leave device discoverable. Don't let unpaired users do things with device
* 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
* warn user to bt pair

Wyświetl plik

@ -168,12 +168,7 @@ class MainActivity : AppCompatActivity(), Logging,
} else {
Toast.makeText(this, "Error - this app requires bluetooth", Toast.LENGTH_LONG).show()
}
/* 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, null)
requestPermission()
}

Wyświetl plik

@ -85,7 +85,7 @@ A variable keepAllPackets, if set to true will suppress this behavior and instea
*/
class RadioInterfaceService : Service(), Logging {
companion object {
companion object : Logging {
/**
* The RECEIVED_FROMRADIO
* Payload will be the raw bytes which were contained within a MeshProtos.FromRadio protobuf
@ -135,9 +135,27 @@ class RadioInterfaceService : Service(), Logging {
private const val DEVADDR_KEY = "devAddr"
/// Get our bluetooth adapter (should always succeed except on emulator
private fun getBluetoothAdapter(context: Context): BluetoothAdapter? {
val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
return bluetoothManager.adapter
}
/// Return the device we are configured to use, or null for none
fun getBondedDeviceAddress(context: Context) =
getPrefs(context).getString(DEVADDR_KEY, null)
fun getBondedDeviceAddress(context: Context): String? {
val allPaired =
getBluetoothAdapter(context)?.bondedDevices.orEmpty().map { it.address }.toSet()
// If the user has unpaired our device, treat things as if we don't have one
val addr = getPrefs(context).getString(DEVADDR_KEY, null)
return if (addr != null && !allPaired.contains(addr)) {
warn("Ignoring stale bond to $addr")
null
} else
addr
}
fun setBondedDeviceAddress(context: Context, addr: String?) =
getPrefs(context).edit(commit = true) {
@ -148,10 +166,6 @@ class RadioInterfaceService : Service(), Logging {
}
}
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
// Both of these are created in onCreate()
private var safe: SafeBluetooth? = null
@ -270,7 +284,7 @@ class RadioInterfaceService : Service(), Logging {
else {
// Note: this call does no comms, it just creates the device object (even if the
// device is off/not connected)
val device = bluetoothAdapter?.getRemoteDevice(address)
val device = getBluetoothAdapter(this)?.getRemoteDevice(address)
if (device != null) {
info("Creating radio interface service. device=$address")

Wyświetl plik

@ -1,5 +1,6 @@
package com.geeksville.mesh.ui
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
@ -12,6 +13,8 @@ import androidx.ui.core.ContextAmbient
import androidx.ui.core.Text
import androidx.ui.layout.Column
import androidx.ui.material.CircularProgressIndicator
import androidx.ui.material.EmphasisLevels
import androidx.ui.material.ProvideEmphasis
import androidx.ui.material.RadioGroup
import androidx.ui.tooling.preview.Preview
import com.geeksville.android.Logging
@ -27,7 +30,7 @@ object ScanState {
}
@Model
data class BTScanEntry(val name: String, val macAddress: String) {
data class BTScanEntry(val name: String, val macAddress: String, val bonded: Boolean) {
val isSelected get() = macAddress == ScanState.selectedMacAddr
}
@ -45,6 +48,7 @@ fun BTScanScreen() {
ScanState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
fun changeSelection(newAddr: String) {
BTLog.info("Changing BT device to $newAddr")
ScanState.selectedMacAddr = newAddr
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
}
@ -55,8 +59,8 @@ fun BTScanScreen() {
BTLog.warn("No bluetooth adapter. Running under emulation?")
val testnodes = listOf(
BTScanEntry("Meshtastic_ab12", "xx"),
BTScanEntry("Meshtastic_32ac", "xb")
BTScanEntry("Meshtastic_ab12", "xx", false),
BTScanEntry("Meshtastic_32ac", "xb", true)
)
devices.putAll(testnodes.map { it.macAddress to it })
@ -81,13 +85,20 @@ fun BTScanScreen() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val addr = result.device.address
BTLog.debug("onScanResult ${addr}")
devices[addr] =
BTScanEntry(result.device.name, addr)
// 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)
changeSelection(addr)
// If nothing was selected, by default select the first thing we see
if (ScanState.selectedMacAddr == null && entry.bonded)
changeSelection(addr)
}
}
}
@ -116,36 +127,47 @@ fun BTScanScreen() {
if (ScanState.errorText != null) {
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanState.errorText}")
} else {
if (devices.isEmpty())
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
CircularProgressIndicator() // Show that we are searching still
} else {
// val allPaired = bluetoothAdapter?.bondedDevices.orEmpty().map { it.address }.toSet()
/* 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 {
devices.values.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
)
//}
ProvideEmphasis(emphasis = if (it.bonded) EmphasisLevels().high else EmphasisLevels().disabled) {
RadioGroupTextItem(
selected = (it.isSelected),
onSelect = {
// If the device is paired, let user select it, otherwise start the pairing flow
if (it.bonded)
changeSelection(it.macAddress)
else {
BTLog.info("Starting bonding for $it")
// We ignore missing BT adapters, because it lets us run on the emulator
bluetoothAdapter?.getRemoteDevice(it.macAddress)
?.createBond()
}
},
text = it.name
)
}
}
}
}
}
CircularProgressIndicator() // Show that we are searching still
}
}
}