kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
bt scan kinda works
rodzic
d4cf41c98a
commit
53e25967db
3
TODO.md
3
TODO.md
|
@ -2,7 +2,7 @@
|
||||||
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
|
* 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
|
* show bt scan progress centered and towards the bottom of the screen
|
||||||
* get rid of green bar at top
|
* get rid of green bar at top
|
||||||
* change titlebar based off which screen we are showing
|
* change titlebar based off which screen we are showing
|
||||||
|
@ -105,3 +105,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
|
* use https://codelabs.developers.google.com/codelabs/jetpack-compose-basics/#4 to show service state
|
||||||
* all chat in the app defaults to group chat
|
* all chat in the app defaults to group chat
|
||||||
* start bt receive on boot
|
* start bt receive on boot
|
||||||
|
* warn user to bt pair
|
|
@ -135,9 +135,26 @@ class RadioInterfaceService : Service(), Logging {
|
||||||
|
|
||||||
private const val DEVADDR_KEY = "devAddr"
|
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
|
/// Return the device we are configured to use, or null for none
|
||||||
fun getBondedDeviceAddress(context: Context) =
|
fun getBondedDeviceAddress(context: Context): String? {
|
||||||
getPrefs(context).getString(DEVADDR_KEY, null)
|
|
||||||
|
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 (!allPaired.contains(addr))
|
||||||
|
null
|
||||||
|
else
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
|
||||||
fun setBondedDeviceAddress(context: Context, addr: String?) =
|
fun setBondedDeviceAddress(context: Context, addr: String?) =
|
||||||
getPrefs(context).edit(commit = true) {
|
getPrefs(context).edit(commit = true) {
|
||||||
|
@ -148,10 +165,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()
|
// Both of these are created in onCreate()
|
||||||
private var safe: SafeBluetooth? = null
|
private var safe: SafeBluetooth? = null
|
||||||
|
@ -270,7 +283,7 @@ class RadioInterfaceService : Service(), Logging {
|
||||||
else {
|
else {
|
||||||
// Note: this call does no comms, it just creates the device object (even if the
|
// Note: this call does no comms, it just creates the device object (even if the
|
||||||
// device is off/not connected)
|
// device is off/not connected)
|
||||||
val device = bluetoothAdapter?.getRemoteDevice(address)
|
val device = getBluetoothAdapter(this)?.getRemoteDevice(address)
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
info("Creating radio interface service. device=$address")
|
info("Creating radio interface service. device=$address")
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.geeksville.mesh.ui
|
package com.geeksville.mesh.ui
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice
|
||||||
import android.bluetooth.BluetoothManager
|
import android.bluetooth.BluetoothManager
|
||||||
import android.bluetooth.le.ScanCallback
|
import android.bluetooth.le.ScanCallback
|
||||||
import android.bluetooth.le.ScanFilter
|
import android.bluetooth.le.ScanFilter
|
||||||
|
@ -12,6 +13,8 @@ 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.CircularProgressIndicator
|
||||||
|
import androidx.ui.material.EmphasisLevels
|
||||||
|
import androidx.ui.material.ProvideEmphasis
|
||||||
import androidx.ui.material.RadioGroup
|
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
|
||||||
|
@ -27,7 +30,7 @@ object ScanState {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Model
|
@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
|
val isSelected get() = macAddress == ScanState.selectedMacAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +48,7 @@ fun BTScanScreen() {
|
||||||
ScanState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
|
ScanState.selectedMacAddr = RadioInterfaceService.getBondedDeviceAddress(context)
|
||||||
|
|
||||||
fun changeSelection(newAddr: String) {
|
fun changeSelection(newAddr: String) {
|
||||||
|
BTLog.info("Changing BT device to $newAddr")
|
||||||
ScanState.selectedMacAddr = newAddr
|
ScanState.selectedMacAddr = newAddr
|
||||||
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
|
RadioInterfaceService.setBondedDeviceAddress(context, newAddr)
|
||||||
}
|
}
|
||||||
|
@ -55,8 +59,8 @@ fun BTScanScreen() {
|
||||||
BTLog.warn("No bluetooth adapter. Running under emulation?")
|
BTLog.warn("No bluetooth adapter. Running under emulation?")
|
||||||
|
|
||||||
val testnodes = listOf(
|
val testnodes = listOf(
|
||||||
BTScanEntry("Meshtastic_ab12", "xx"),
|
BTScanEntry("Meshtastic_ab12", "xx", false),
|
||||||
BTScanEntry("Meshtastic_32ac", "xb")
|
BTScanEntry("Meshtastic_32ac", "xb", true)
|
||||||
)
|
)
|
||||||
|
|
||||||
devices.putAll(testnodes.map { it.macAddress to it })
|
devices.putAll(testnodes.map { it.macAddress to it })
|
||||||
|
@ -81,13 +85,20 @@ fun BTScanScreen() {
|
||||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||||
|
|
||||||
val addr = result.device.address
|
val addr = result.device.address
|
||||||
BTLog.debug("onScanResult ${addr}")
|
// prevent logspam because weill get get lots of redundant scan results
|
||||||
devices[addr] =
|
if (!devices.contains(addr)) {
|
||||||
BTScanEntry(result.device.name, 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 nothing was selected, by default select the first thing we see
|
||||||
if (ScanState.selectedMacAddr == null)
|
if (ScanState.selectedMacAddr == null && entry.bonded)
|
||||||
changeSelection(addr)
|
changeSelection(addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,36 +127,47 @@ fun BTScanScreen() {
|
||||||
if (ScanState.errorText != null) {
|
if (ScanState.errorText != null) {
|
||||||
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanState.errorText}")
|
Text("An unexpected error was encountered. Please file a bug on our github: ${ScanState.errorText}")
|
||||||
} else {
|
} else {
|
||||||
if (devices.isEmpty())
|
if (devices.isEmpty()) {
|
||||||
Text("Looking for Meshtastic devices... (zero found)")
|
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) }
|
val paired = devices.values.filter { allPaired.contains(it.macAddress) }
|
||||||
if (paired.size < devices.size) {
|
if (paired.size < devices.size) {
|
||||||
Text(
|
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."
|
"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 {
|
RadioGroup {
|
||||||
Column {
|
Column {
|
||||||
paired.forEach {
|
devices.values.forEach {
|
||||||
// disabled pending https://issuetracker.google.com/issues/149528535
|
// disabled pending https://issuetracker.google.com/issues/149528535
|
||||||
//ProvideEmphasis(emphasis = if (allPaired.contains(it.macAddress)) EmphasisLevels().medium else EmphasisLevels().disabled) {
|
ProvideEmphasis(emphasis = if (it.bonded) EmphasisLevels().high else EmphasisLevels().disabled) {
|
||||||
RadioGroupTextItem(
|
RadioGroupTextItem(
|
||||||
selected = (it.isSelected),
|
selected = (it.isSelected),
|
||||||
onSelect = { changeSelection(it.macAddress) },
|
onSelect = {
|
||||||
text = it.name
|
// 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue