allow sending broadcasts and cope with missing mesh services

pull/8/head
geeksville 2020-02-17 15:39:49 -08:00
rodzic e738b7692f
commit 165df2c4de
8 zmienionych plików z 73 dodań i 30 usunięć

Wyświetl plik

@ -28,6 +28,8 @@ interface IMeshService {
Send an opaque packet to a specified node name
typ is defined in mesh.proto Data.Type. For now juse use 0 to mean opaque bytes.
destId can be null to indicate "broadcast message"
*/
void sendData(String destId, in byte[] payload, int typ);

Wyświetl plik

@ -80,6 +80,9 @@ eventually:
make a custom theme: https://github.com/material-components/material-components-android/tree/master/material-theme-builder
*/
val utf8 = Charset.forName("UTF-8")
class MainActivity : AppCompatActivity(), Logging,
ActivityCompat.OnRequestPermissionsResultCallback {
@ -90,8 +93,6 @@ class MainActivity : AppCompatActivity(), Logging,
}
private val utf8 = Charset.forName("UTF-8")
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
@ -154,12 +155,12 @@ class MainActivity : AppCompatActivity(), Logging,
private fun setOwner() {
// Note: we are careful to not set a new unique ID
val name = UIState.ownerName.value
meshService!!.setOwner(null, name, getInitials(name))
UIState.meshService!!.setOwner(null, name, getInitials(name))
}
private fun sendTestPackets() {
exceptionReporter {
val m = meshService!!
val m = UIState.meshService!!
// Do some test operations
val testPayload = "hello world".toByteArray()
@ -270,7 +271,7 @@ class MainActivity : AppCompatActivity(), Logging,
/// Read the config bytes from the radio so we can show them in our GUI, the radio's copy is ground truth
private fun readRadioConfig() {
val bytes = meshService!!.radioConfig
val bytes = UIState.meshService!!.radioConfig
val config = MeshProtos.RadioConfig.parseFrom(bytes)
UIState.radioConfig.value = config
@ -340,14 +341,13 @@ class MainActivity : AppCompatActivity(), Logging,
}
}
private var meshService: IMeshService? = null
private var isBound = false
private var serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) =
exceptionReporter {
val m = IMeshService.Stub.asInterface(service)
meshService = m
UIState.meshService = m
// We don't start listening for packets until after we are connected to the service
registerMeshReceiver()
@ -367,14 +367,14 @@ class MainActivity : AppCompatActivity(), Logging,
override fun onServiceDisconnected(name: ComponentName) {
warn("The mesh service has disconnected")
unregisterMeshReceiver()
meshService = null
UIState.meshService = null
}
}
private fun bindMeshService() {
debug("Binding to mesh service!")
// we bind using the well known name, to make sure 3rd party apps could also
logAssert(meshService == null)
logAssert(UIState.meshService == null)
val intent = MeshService.startService(this)
if (intent != null) {
@ -391,7 +391,7 @@ class MainActivity : AppCompatActivity(), Logging,
debug("Unbinding from mesh service!")
if (isBound)
unbindService(serviceConnection)
meshService = null
UIState.meshService = null
}
override fun onPause() {

Wyświetl plik

@ -89,21 +89,22 @@ data class NodeInfo(
}
/// @return distance in meters to some other node (or null if unknown)
fun distance(o: NodeInfo?): Double? {
fun distance(o: NodeInfo?): Int? {
val p = position
val op = o?.position
return if (p != null && op != null)
p.distance(op)
p.distance(op).toInt()
else
null
}
/// @return a nice human readable string for the distance, or null for unknown
fun distanceStr(o: NodeInfo?) = distance(o)?.let { dist ->
if (dist < 1000)
"%.0f m".format(dist)
else
"%.1f km".format(dist / 1000)
when {
dist == 0 -> null // same point
dist < 1000 -> "%.0f m".format(dist)
else -> "%.1f km".format(dist / 1000.0)
}
}
override fun writeToParcel(parcel: Parcel, flags: Int) {

Wyświetl plik

@ -6,8 +6,15 @@ import java.util.*
/**
* the model object for a text message
*
* if errorMessage is set then we had a problem sending this message
*/
data class TextMessage(val from: String, val text: String, val date: Date = Date())
data class TextMessage(
val from: String,
val text: String,
val date: Date = Date(),
val errorMessage: String? = null
)
object MessagesState : Logging {

Wyświetl plik

@ -2,6 +2,7 @@ package com.geeksville.mesh.model
import android.util.Base64
import androidx.compose.mutableStateOf
import com.geeksville.mesh.IMeshService
import com.geeksville.mesh.MeshProtos
/// FIXME - figure out how to merge this staate with the AppStatus Model
@ -10,6 +11,7 @@ object UIState {
/// Kinda ugly - created in the activity but used from Compose - figure out if there is a cleaner way GIXME
// lateinit var googleSignInClient: GoogleSignInClient
var meshService: IMeshService? = null
/// Are we connected to our radio device
val isConnected = mutableStateOf(false)

Wyświetl plik

@ -418,12 +418,21 @@ class MeshService : Service(), Logging {
to = idNum
}
/// Generate a new mesh packet builder with our node as the sender, and the specified recipient
private fun newMeshPacketTo(id: String) = newMeshPacketTo(toNodeNum(id))
/**
* Generate a new mesh packet builder with our node as the sender, and the specified recipient
*
* If id is null we assume a broadcast message
*/
private fun newMeshPacketTo(id: String?) =
newMeshPacketTo(if (id != null) toNodeNum(id) else NODENUM_BROADCAST)
// Helper to make it easy to build a subpacket in the proper protobufs
/**
* Helper to make it easy to build a subpacket in the proper protobufs
*
* If destId is null we assume a broadcast message
*/
private fun buildMeshPacket(
destId: String,
destId: String?,
initFn: MeshProtos.SubPacket.Builder.() -> Unit
): MeshPacket = newMeshPacketTo(destId).apply {
payload = MeshProtos.SubPacket.newBuilder().also {
@ -687,9 +696,9 @@ class MeshService : Service(), Logging {
connectedRadio.writeOwner(user.toByteArray())
}
override fun sendData(destId: String, payloadIn: ByteArray, typ: Int) =
override fun sendData(destId: String?, payloadIn: ByteArray, typ: Int) =
toRemoteExceptions {
info("sendData $destId <- ${payloadIn.size} bytes")
info("sendData dest=$destId <- ${payloadIn.size} bytes")
// encapsulate our payload in the proper protobufs and fire it off
val packet = buildMeshPacket(destId) {

Wyświetl plik

@ -20,10 +20,13 @@ import androidx.ui.material.surface.Surface
import androidx.ui.text.TextStyle
import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.model.MessagesState
import com.geeksville.mesh.model.MessagesState.messages
import com.geeksville.mesh.model.NodeDB
import com.geeksville.mesh.model.TextMessage
import com.geeksville.mesh.model.UIState
import com.geeksville.mesh.utf8
import java.text.SimpleDateFormat
@ -58,11 +61,11 @@ fun MessageCard(msg: TextMessage, modifier: Modifier = Modifier.None) {
style = MaterialTheme.typography().caption
)
}
}
Text(
text = msg.text
)
if (msg.errorMessage != null)
Text(text = msg.errorMessage, style = TextStyle(color = palette.error))
else
Text(text = msg.text)
}
}
}
@ -109,10 +112,25 @@ fun MessagesContent() {
imeAction = ImeAction.Send,
onImeActionPerformed = {
MessagesState.info("did IME action")
val str = message.value
var error: String? = null
val service = UIState.meshService
if (service != null)
service.sendData(
null,
str.toByteArray(utf8),
MeshProtos.Data.Type.CLEAR_TEXT_VALUE
)
else
error = "Error: No Mesh service"
MessagesState.addMessage(
TextMessage(
"fixme",
message.value
NodeDB.myId.value,
str,
errorMessage = error
)
)
},

Wyświetl plik

@ -5,8 +5,10 @@ import androidx.ui.core.Modifier
import androidx.ui.core.Text
import androidx.ui.layout.Column
import androidx.ui.layout.LayoutGravity
import androidx.ui.layout.LayoutWidth
import androidx.ui.material.MaterialTheme
import androidx.ui.tooling.preview.Preview
import androidx.ui.unit.dp
import com.geeksville.mesh.NodeInfo
import com.geeksville.mesh.R
import com.geeksville.mesh.model.NodeDB
@ -14,10 +16,12 @@ import com.geeksville.mesh.model.NodeDB
/**
* Show the user icon for a particular user with distance from the operator and a small pointer
* indicating their direction
*
* This component is fixed width to simplify layouts.
*/
@Composable
fun UserIcon(user: NodeInfo? = null, modifier: Modifier = Modifier.None) {
Column(modifier = modifier) {
Column(modifier = modifier + LayoutWidth(60.dp)) {
VectorImage(
id = R.drawable.ic_twotone_person_24,
tint = palette.onSecondary,