feat: Queue special app PortNums when disconnected (#4495)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-02-07 11:13:41 -06:00 committed by GitHub
parent 55f09fc6bb
commit 6ec2ed76ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 184 additions and 1 deletions

View file

@ -92,6 +92,10 @@ class MainActivity : ComponentActivity() {
addAction("com.geeksville.mesh.RECEIVED.POSITION_APP")
addAction("com.geeksville.mesh.RECEIVED.TELEMETRY_APP")
addAction("com.geeksville.mesh.RECEIVED.NODEINFO_APP")
addAction("com.geeksville.mesh.RECEIVED.ATAK_PLUGIN")
addAction("com.geeksville.mesh.RECEIVED.ATAK_FORWARDER")
addAction("com.geeksville.mesh.RECEIVED.DETECTION_SENSOR_APP")
addAction("com.geeksville.mesh.RECEIVED.PRIVATE_APP")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

View file

@ -90,6 +90,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.proto.PortNum
@Composable
fun ListItem(
@ -229,6 +230,7 @@ private fun MainContent(
) {
item { MyInfoSection(myId, myNodeInfo) }
item { TitledCard(title = "Messaging") { MessagingSection(viewModel, lastMessage) } }
item { TitledCard(title = "Test Special PortNums") { SpecialAppSection(viewModel) } }
item {
SectionHeader(
@ -297,6 +299,28 @@ private fun MainContent(
}
}
@Composable
fun SpecialAppSection(viewModel: MeshServiceViewModel) {
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { viewModel.sendSpecialPacket(PortNum.ATAK_PLUGIN) }, modifier = Modifier.weight(1f)) {
Text("Send ATAK")
}
Button(
onClick = { viewModel.sendSpecialPacket(PortNum.DETECTION_SENSOR_APP) },
modifier = Modifier.weight(1f),
) {
Text("Send Sensor")
}
}
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { viewModel.sendSpecialPacket(PortNum.PRIVATE_APP) }, modifier = Modifier.weight(1f)) {
Text("Send Private")
}
}
}
}
@Composable
private fun PacketLogContent(log: List<String>) {
Column(modifier = Modifier.fillMaxWidth().heightIn(max = 300.dp).verticalScroll(rememberScrollState())) {

View file

@ -135,6 +135,31 @@ class MeshServiceViewModel : ViewModel() {
} ?: Log.w(TAG, "MeshService is not bound, cannot send message")
}
fun sendSpecialPacket(portNum: PortNum) {
meshService?.let { service ->
try {
val packet =
DataPacket(
to = DataPacket.ID_BROADCAST,
bytes = "Special Payload for ${portNum.name}".encodeToByteArray().toByteString(),
dataType = portNum.value,
from = DataPacket.ID_LOCAL,
time = System.currentTimeMillis(),
id = service.packetId,
status = MessageStatus.UNKNOWN,
hopLimit = 3,
channel = 0,
wantAck = true,
)
service.send(packet)
addToLog("Sent ${portNum.name} Packet (ID: ${packet.id})")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to send special packet", e)
addToLog("Failed to send ${portNum.name} packet: ${e.message}")
}
}
}
fun requestMyNodeInfo() {
meshService?.let {
try {