chore: remove deprecated mesh_service_example module (#5055)

This commit is contained in:
James Rich 2026-04-14 22:10:23 -05:00 committed by GitHub
parent a2763bdfeb
commit 401f59489a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
63 changed files with 5 additions and 2370 deletions

View file

@ -70,8 +70,7 @@ jobs:
}
allowed_extra_roots = {'baselineprofile'}
excluded_roots = {'mesh_service_example'}
expected_roots = (module_roots | allowed_extra_roots) - excluded_roots
expected_roots = module_roots | allowed_extra_roots
filter_paths = {
path.split('/')[0]

View file

@ -39,7 +39,6 @@ Module directory, namespacing conventions, environment setup, and troubleshootin
| `feature/wifi-provision` | KMP WiFi provisioning via BLE (Nymea protocol). Uses `core:ble` Kable abstractions. |
| `feature/firmware` | Fully KMP firmware update system: Unified OTA (BLE + WiFi), native Nordic Secure DFU protocol (pure KMP), USB/UF2 updates, and `FirmwareRetriever` with manifest-based resolution. Desktop is a first-class target. |
| `desktop/` | Compose Desktop application. Thin host shell relying on feature modules for shared UI. Full Koin DI graph, TCP, Serial/USB, and BLE transports. Versioning via `config.properties` + `GitVersionValueSource`. |
| `mesh_service_example/` | **DEPRECATED.** Legacy sample app; not yet removed. See `core/api/README.md` for the current integration guide. |
## Namespacing
- **Standard:** Use the `org.meshtastic.*` namespace for all code.

View file

@ -48,7 +48,7 @@ CI is defined in `.github/workflows/reusable-check.yml` and structured as four p
2. **`test-shards`** — A 3-shard matrix that runs unit tests in parallel (depends on `lint-check`):
- `shard-core`: `allTests` for all `core:*` KMP modules.
- `shard-feature`: `allTests` for all `feature:*` KMP modules.
- `shard-app`: Explicit test tasks for pure-Android/JVM modules (`app`, `desktop`, `core:barcode`, `mesh_service_example`).
- `shard-app`: Explicit test tasks for pure-Android/JVM modules (`app`, `desktop`, `core:barcode`).
Each shard generates Kover XML coverage and uploads test results + coverage to Codecov with per-shard flags.
Downstream jobs use `fetch-depth: 1` and receive `VERSION_CODE` from lint-check via env var, enabling shallow clones.
3. **`android-check`** — Builds APKs for all flavors (depends on `lint-check`).

View file

@ -57,10 +57,6 @@ component_management:
name: Desktop
paths:
- desktop/**
- component_id: example
name: Example
paths:
- mesh_service_example/**
ignore:
- "**/build/**"

View file

@ -133,7 +133,7 @@ class ServiceBroadcasts(private val context: Context, private val serviceReposit
explicitBroadcast(Intent(ACTION_MESH_DISCONNECTED))
}
// Restore legacy action for other consumers (e.g. mesh_service_example)
// Restore legacy action for other consumers (e.g. ATAK plugins)
val legacyIntent =
Intent(ACTION_CONNECTION_CHANGED).apply {
putExtra(EXTRA_CONNECTED, stateStr)

View file

@ -121,8 +121,8 @@ kotlin {
```
**What the plugin provides automatically:**
- `commonMain`: `compose-multiplatform-material3`, `compose-multiplatform-materialIconsExtended`, `jetbrains-lifecycle-viewmodel-compose`, `koin-compose-viewmodel`, `kermit`
- `androidMain`: `androidx-compose-bom` (platform), `accompanist-permissions`, `androidx-activity-compose`, `androidx-compose-material3`, `androidx-compose-material-iconsExtended`, `androidx-compose-ui-text`, `androidx-compose-ui-tooling-preview`
- `commonMain`: `compose-multiplatform-material3`, `jetbrains-lifecycle-viewmodel-compose`, `jetbrains-lifecycle-runtime-compose`, `koin-compose-viewmodel`, `kermit`
- `androidMain`: `androidx-compose-bom` (platform), `accompanist-permissions`, `androidx-activity-compose`, `androidx-compose-material3`, `androidx-compose-ui-text`, `androidx-compose-ui-tooling-preview`
- `commonTest`: `core:testing`
**Why:** Eliminates ~15 duplicate dependency declarations per feature module (modelled after Now in Android's `AndroidFeatureImplConventionPlugin`).

View file

@ -122,7 +122,6 @@ androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version
androidx-work-testing = { module = "androidx.work:work-testing", version = "2.11.2" }
# AndroidX Compose (explicit versions — BOM removed; CMP is the sole version authority)
androidx-compose-material-iconsExtended = { module = "androidx.compose.material:material-icons-extended", version.ref = "androidx-compose-material" } # Only used by deprecated mesh_service_example — remove when that module is deleted
androidx-compose-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "compose-multiplatform" }
androidx-compose-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "compose-multiplatform" } # Required by Robolectric Compose tests (registers ComponentActivity)

View file

@ -1,20 +0,0 @@
# mesh_service_example
> **DEPRECATED — scheduled for removal in a future release.**
>
> This module is no longer maintained and will be deleted once the new public API documentation is
> available. Do not add new code here. Do not use it as a template for new integrations.
>
> For integrating with the Meshtastic service from your own app, refer to the `:core:api` module
> README at [`core/api/README.md`](../core/api/README.md).
## What this was
`mesh_service_example` was a sample Android application demonstrating how to bind to the
`IMeshService` AIDL interface and exchange data with the Meshtastic radio service. It is kept in
the repository only to avoid breaking the CI assemble task (`mesh_service_example:assembleDebug`)
and the JitPack publication that consumers may reference, until those are formally retired.
## License
See the root `LICENSE` file.

View file

@ -1,54 +0,0 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import com.android.build.api.dsl.ApplicationExtension
import org.meshtastic.buildlogic.FlavorDimension
import org.meshtastic.buildlogic.MeshtasticFlavor
plugins {
alias(libs.plugins.meshtastic.android.application)
alias(libs.plugins.meshtastic.android.application.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
}
configure<ApplicationExtension> {
namespace = "com.meshtastic.android.meshserviceexample"
defaultConfig {
// Force this app to use the Google variant of any modules it's using that apply AndroidLibraryConventionPlugin
missingDimensionStrategy(FlavorDimension.marketplace.name, MeshtasticFlavor.google.name)
}
testOptions { unitTests.isReturnDefaultValues = true }
}
dependencies {
implementation(projects.core.api)
implementation(projects.core.model)
implementation(projects.core.proto)
implementation(libs.androidx.activity.compose)
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
implementation(libs.jetbrains.lifecycle.runtime)
implementation(libs.compose.multiplatform.material3)
implementation(libs.androidx.compose.material.iconsExtended)
implementation(libs.material)
testImplementation(libs.junit)
testRuntimeOnly(libs.junit.vintage.engine)
testImplementation(libs.kotlinx.coroutines.test)
}

View file

@ -1,5 +0,0 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues/>
</SmellBaseline>

View file

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="com.geeksville.mesh.permission.BIND_MESH_SERVICE" />
<queries>
<package android:name="com.geeksville.mesh" />
<package android:name="com.geeksville.mesh.google.debug" />
<package android:name="com.geeksville.mesh.fdroid.debug" />
</queries>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MeshServiceExample"
tools:targetApi="31"
tools:replace="android:allowBackup">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -1,187 +0,0 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("DEPRECATION")
package com.meshtastic.android.meshserviceexample
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import org.meshtastic.core.api.MeshtasticIntent
import org.meshtastic.core.service.IMeshService
private const val TAG: String = "MeshServiceExample"
/**
* MainActivity for the MeshServiceExample application.
*
* **DEPRECATED.** This entire module (`mesh_service_example`) is scheduled for removal in a future release. Do not use
* it as a template for new integrations. See `:core:api` README for the current public API surface.
*/
@Deprecated(
message =
"mesh_service_example is deprecated and will be removed in a future release. " +
"See core/api/README.md for integration guidance.",
)
class MainActivity : ComponentActivity() {
private var meshService: IMeshService? = null
private var isMeshServiceBound = false
private val viewModel: MeshServiceViewModel by viewModels()
private val serviceConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
meshService = IMeshService.Stub.asInterface(service)
Log.i(TAG, "Connected to MeshService")
isMeshServiceBound = true
viewModel.onServiceConnected(meshService)
}
override fun onServiceDisconnected(name: ComponentName?) {
meshService = null
isMeshServiceBound = false
viewModel.onServiceDisconnected()
}
}
private val meshtasticReceiver =
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "BroadcastReceiver onReceive: ${intent?.action}")
intent?.let { viewModel.handleIncomingIntent(it) }
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
bindMeshService()
val intentFilter =
IntentFilter().apply {
addAction(MeshtasticIntent.ACTION_NODE_CHANGE)
addAction(MeshtasticIntent.ACTION_CONNECTION_CHANGED)
addAction(MeshtasticIntent.ACTION_MESH_CONNECTED)
addAction(MeshtasticIntent.ACTION_MESH_DISCONNECTED)
addAction(MeshtasticIntent.ACTION_MESSAGE_STATUS)
addAction(MeshtasticIntent.ACTION_RECEIVED_TEXT_MESSAGE_APP)
addAction(MeshtasticIntent.ACTION_RECEIVED_POSITION_APP)
addAction(MeshtasticIntent.ACTION_RECEIVED_TELEMETRY_APP)
addAction(MeshtasticIntent.ACTION_RECEIVED_NODEINFO_APP)
addAction(MeshtasticIntent.ACTION_RECEIVED_ATAK_PLUGIN)
addAction(MeshtasticIntent.ACTION_RECEIVED_ATAK_FORWARDER)
addAction(MeshtasticIntent.ACTION_RECEIVED_DETECTION_SENSOR_APP)
addAction(MeshtasticIntent.ACTION_RECEIVED_PRIVATE_APP)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(meshtasticReceiver, intentFilter, RECEIVER_EXPORTED)
} else {
@Suppress("UnspecifiedRegisterReceiverFlag")
registerReceiver(meshtasticReceiver, intentFilter)
}
setContent { ExampleTheme { MainScreen(viewModel) } }
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(meshtasticReceiver)
unbindMeshService()
}
private fun bindMeshService() {
try {
Log.i(TAG, "Attempting to bind to Mesh Service...")
val intent = Intent("com.geeksville.mesh.Service")
val resolveInfo =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.queryIntentServices(intent, PackageManager.ResolveInfoFlags.of(0))
} else {
@Suppress("DEPRECATION")
packageManager.queryIntentServices(intent, 0)
}
if (resolveInfo.isNotEmpty()) {
val serviceInfo = resolveInfo[0].serviceInfo
intent.setClassName(serviceInfo.packageName, serviceInfo.name)
Log.i(TAG, "Found service in package: ${serviceInfo.packageName}")
} else {
Log.w(TAG, "No service found for action com.geeksville.mesh.Service. Falling back to default.")
intent.setClassName("com.geeksville.mesh", "org.meshtastic.core.service.MeshService")
}
val success = bindService(intent, serviceConnection, BIND_AUTO_CREATE)
if (!success) {
Log.e(TAG, "bindService returned false")
}
} catch (e: SecurityException) {
Log.e(TAG, "SecurityException while binding: ${e.message}")
}
}
private fun unbindMeshService() {
if (isMeshServiceBound) {
try {
unbindService(serviceConnection)
} catch (e: IllegalArgumentException) {
Log.w(TAG, "MeshService not registered or already unbound: ${e.message}")
}
isMeshServiceBound = false
meshService = null
}
}
}
@Composable
fun ExampleTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
val colorScheme =
when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> darkColorScheme()
else -> lightColorScheme()
}
MaterialTheme(colorScheme = colorScheme, content = content)
}

View file

@ -1,585 +0,0 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("TooManyFunctions")
package com.meshtastic.android.meshserviceexample
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.Message
import androidx.compose.material.icons.automirrored.rounded.Send
import androidx.compose.material.icons.rounded.AccountCircle
import androidx.compose.material.icons.rounded.BatteryUnknown
import androidx.compose.material.icons.rounded.ExpandLess
import androidx.compose.material.icons.rounded.ExpandMore
import androidx.compose.material.icons.rounded.GpsFixed
import androidx.compose.material.icons.rounded.GpsOff
import androidx.compose.material.icons.rounded.Hub
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.MyLocation
import androidx.compose.material.icons.rounded.PersonSearch
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.RestartAlt
import androidx.compose.material.icons.rounded.Route
import androidx.compose.material.icons.rounded.Router
import androidx.compose.material.icons.rounded.SignalCellularAlt
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
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(
text: String,
supportingText: String? = null,
leadingIcon: ImageVector? = null,
trailingIcon: ImageVector? = null,
) {
androidx.compose.material3.ListItem(
headlineContent = { Text(text) },
supportingContent = supportingText?.let { { Text(it) } },
leadingContent = leadingIcon?.let { { Icon(it, contentDescription = null) } },
trailingContent = trailingIcon?.let { { Icon(it, contentDescription = null) } },
)
}
@Composable
fun TitledCard(title: String, content: @Composable () -> Unit) {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = title,
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(bottom = 12.dp),
)
content()
}
}
}
@Composable
fun SectionHeader(title: String, expanded: Boolean, onExpandClick: () -> Unit, modifier: Modifier = Modifier) {
Card(
modifier = modifier.fillMaxWidth().clickable { onExpandClick() },
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)),
) {
Row(
modifier = Modifier.fillMaxWidth().padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = title, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary)
Icon(
imageVector = if (expanded) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore,
contentDescription = if (expanded) "Collapse" else "Expand",
tint = MaterialTheme.colorScheme.primary,
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(viewModel: MeshServiceViewModel) {
val isConnected by viewModel.serviceConnectionStatus.collectAsState()
val connectionState by viewModel.connectionState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
modifier = Modifier.fillMaxSize(),
snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = {
TopAppBar(
title = { TopBarTitle(isConnected, connectionState) },
actions = {
IconButton(
onClick = {
viewModel.requestNodes()
scope.launch { snackbarHostState.showSnackbar("Refreshing nodes...") }
},
) {
Icon(Icons.Rounded.Refresh, contentDescription = "Refresh Nodes")
}
},
colors =
TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surface,
titleContentColor = MaterialTheme.colorScheme.onSurface,
),
)
},
) { innerPadding ->
MainContent(viewModel, innerPadding, snackbarHostState)
}
}
@Composable
private fun TopBarTitle(isConnected: Boolean, connectionState: String) {
Column {
Text(
text = "Mesh Service Example",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleLarge,
)
Row(verticalAlignment = Alignment.CenterVertically) {
val statusColor =
if (isConnected) {
Color.Green
} else {
MaterialTheme.colorScheme.error
}
Box(modifier = Modifier.size(8.dp).clip(CircleShape).background(statusColor))
Spacer(modifier = Modifier.width(8.dp))
Text(
text = if (isConnected) "Connected ($connectionState)" else "Disconnected",
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
}
@Composable
@Suppress("LongMethod")
private fun MainContent(
viewModel: MeshServiceViewModel,
innerPadding: PaddingValues,
snackbarHostState: SnackbarHostState,
) {
val myNodeInfo by viewModel.myNodeInfo.collectAsState()
val myId by viewModel.myId.collectAsState()
val nodes by viewModel.nodes.collectAsState()
val lastMessage by viewModel.message.collectAsState()
val packetLog by viewModel.packetLog.collectAsState()
var nodesExpanded by remember { mutableStateOf(false) }
var logExpanded by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
LazyColumn(
modifier = Modifier.padding(innerPadding).fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
item { MyInfoSection(myId, myNodeInfo) }
item { TitledCard(title = "Messaging") { MessagingSection(viewModel, lastMessage) } }
item { TitledCard(title = "Test Special PortNums") { SpecialAppSection(viewModel) } }
item {
SectionHeader(
title = "Mesh Nodes (${nodes.size})",
expanded = nodesExpanded,
onExpandClick = { nodesExpanded = !nodesExpanded },
)
}
if (nodesExpanded) {
if (nodes.isEmpty()) {
item { EmptyNodeState() }
} else {
items(nodes) { node ->
Card(modifier = Modifier.fillMaxWidth()) {
val nodeLabel = node.user?.longName ?: node.user?.id ?: "Unknown Node"
NodeItem(node) { action ->
scope.launch {
when (action) {
"traceroute" -> {
viewModel.requestTraceroute(node.num)
snackbarHostState.showSnackbar("Traceroute requested for $nodeLabel")
}
"telemetry" -> {
viewModel.requestTelemetry(node.num)
snackbarHostState.showSnackbar("Telemetry requested for $nodeLabel")
}
"neighbors" -> {
viewModel.requestNeighborInfo(node.num)
snackbarHostState.showSnackbar("Neighbor info requested for $nodeLabel")
}
"position" -> {
viewModel.requestPosition(node.num)
snackbarHostState.showSnackbar("Position requested for $nodeLabel")
}
"userinfo" -> {
viewModel.requestUserInfo(node.num)
snackbarHostState.showSnackbar("User info requested for $nodeLabel")
}
"connstatus" -> {
viewModel.requestDeviceConnectionStatus(node.num)
snackbarHostState.showSnackbar("Connection status requested for $nodeLabel")
}
}
}
}
}
}
}
}
item {
SectionHeader(title = "Packet Log", expanded = logExpanded, onExpandClick = { logExpanded = !logExpanded })
}
if (logExpanded) {
item {
Card(modifier = Modifier.fillMaxWidth()) {
Box(modifier = Modifier.padding(16.dp)) { PacketLogContent(packetLog) }
}
}
}
item { ActionButtons(viewModel, snackbarHostState) }
item { Spacer(modifier = Modifier.height(16.dp)) }
}
}
@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())) {
if (log.isEmpty()) {
Text(
text = "No packets yet.",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(vertical = 8.dp),
)
} else {
log.forEach { entry ->
Text(
text = entry,
style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace,
modifier = Modifier.padding(vertical = 2.dp),
)
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.2f))
}
}
}
}
@Composable
private fun MyInfoSection(myId: String?, myNodeInfo: org.meshtastic.core.model.MyNodeInfo?) {
TitledCard(title = "My Node Information") {
ListItem(
text = "Long ID",
supportingText = myId ?: "N/A",
leadingIcon = Icons.Rounded.AccountCircle,
trailingIcon = null,
)
ListItem(
text = "Firmware",
supportingText = myNodeInfo?.firmwareString ?: "N/A",
leadingIcon = Icons.Rounded.Info,
trailingIcon = null,
)
}
}
@Composable
private fun EmptyNodeState() {
Text(
text = "No mesh nodes discovered yet.",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.fillMaxWidth().padding(vertical = 32.dp),
textAlign = TextAlign.Center,
)
}
@Composable
fun MessagingSection(viewModel: MeshServiceViewModel, lastMessage: String) {
var textToSend by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
if (lastMessage.isNotEmpty()) {
Card(
modifier = Modifier.fillMaxWidth(),
colors =
CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f),
),
) {
ListItem(
text = "Last Received",
supportingText = lastMessage,
leadingIcon = Icons.AutoMirrored.Rounded.Message,
trailingIcon = null,
)
}
Spacer(modifier = Modifier.height(12.dp))
}
Row(verticalAlignment = Alignment.CenterVertically) {
OutlinedTextField(
value = textToSend,
onValueChange = { textToSend = it },
modifier = Modifier.weight(1f),
label = { Text("Send broadcast message") },
shape = MaterialTheme.shapes.large,
)
Spacer(modifier = Modifier.width(8.dp))
Button(
onClick = {
if (textToSend.isNotBlank()) {
viewModel.sendMessage(textToSend)
textToSend = ""
}
},
modifier = Modifier.size(56.dp),
shape = MaterialTheme.shapes.large,
contentPadding = PaddingValues(0.dp),
) {
Icon(imageVector = Icons.AutoMirrored.Rounded.Send, contentDescription = "Send")
}
}
}
}
@Composable
fun NodeItem(node: NodeInfo, onAction: (String) -> Unit) {
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
NodeItemHeader(node)
Spacer(modifier = Modifier.height(8.dp))
NodeItemActions(node.isOnline, onAction)
}
}
@Composable
private fun NodeItemHeader(node: NodeInfo) {
Row(verticalAlignment = Alignment.CenterVertically) {
Box(contentAlignment = Alignment.BottomEnd) {
Icon(
imageVector = Icons.Rounded.AccountCircle,
contentDescription = null,
modifier = Modifier.size(48.dp),
tint = MaterialTheme.colorScheme.outline,
)
if (node.isOnline) {
Box(
modifier =
Modifier.size(14.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surface)
.padding(2.dp)
.clip(CircleShape)
.background(Color.Green),
)
}
}
Spacer(modifier = Modifier.width(16.dp))
Column(modifier = Modifier.weight(1f)) {
Text(
text = node.user?.longName ?: "Unknown Node",
style = MaterialTheme.typography.titleMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = "ID: ${node.user?.id ?: "N/A"}",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@Composable
private fun NodeItemActions(isOnline: Boolean, onAction: (String) -> Unit) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(onClick = { onAction("traceroute") }, modifier = Modifier.size(40.dp)) {
Icon(Icons.Rounded.Route, "Traceroute", Modifier.size(20.dp), MaterialTheme.colorScheme.primary)
}
IconButton(onClick = { onAction("telemetry") }, modifier = Modifier.size(40.dp)) {
Icon(
@Suppress("DEPRECATION") // AutoMirrored variant not available in current icons version
Icons.Rounded.BatteryUnknown,
"Telemetry",
Modifier.size(20.dp),
MaterialTheme.colorScheme.secondary,
)
}
IconButton(onClick = { onAction("position") }, modifier = Modifier.size(40.dp)) {
Icon(Icons.Rounded.MyLocation, "Position", Modifier.size(20.dp), MaterialTheme.colorScheme.tertiary)
}
IconButton(onClick = { onAction("neighbors") }, modifier = Modifier.size(40.dp)) {
Icon(Icons.Rounded.Hub, "Neighbors", Modifier.size(20.dp), MaterialTheme.colorScheme.tertiary)
}
IconButton(onClick = { onAction("userinfo") }, modifier = Modifier.size(40.dp)) {
Icon(Icons.Rounded.PersonSearch, "User Info", Modifier.size(20.dp), MaterialTheme.colorScheme.outline)
}
IconButton(onClick = { onAction("connstatus") }, modifier = Modifier.size(40.dp)) {
Icon(
Icons.Rounded.SignalCellularAlt,
"Conn Status",
Modifier.size(20.dp),
MaterialTheme.colorScheme.outline,
)
}
if (isOnline) {
Icon(
imageVector = Icons.Rounded.Router,
contentDescription = "Online",
tint = androidx.compose.ui.graphics.Color.Green.copy(alpha = 0.5f),
modifier = Modifier.padding(start = 8.dp).size(20.dp),
)
}
}
}
@Composable
private fun ActionButtons(viewModel: MeshServiceViewModel, snackbarHostState: SnackbarHostState) {
val scope = rememberCoroutineScope()
TitledCard(title = "Device Controls") {
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
GpsButtons(viewModel, snackbarHostState)
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
viewModel.rebootLocalDevice()
scope.launch { snackbarHostState.showSnackbar("Reboot Requested") }
},
shape = MaterialTheme.shapes.medium,
colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer,
),
) {
Icon(imageVector = Icons.Rounded.RestartAlt, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text("Reboot Radio")
}
}
}
}
@Composable
private fun GpsButtons(viewModel: MeshServiceViewModel, snackbarHostState: SnackbarHostState) {
val scope = rememberCoroutineScope()
val colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(
modifier = Modifier.weight(1f),
onClick = {
viewModel.startProvideLocation()
scope.launch { snackbarHostState.showSnackbar("GPS Sharing Started") }
},
shape = MaterialTheme.shapes.medium,
colors = colors,
) {
Icon(imageVector = Icons.Rounded.GpsFixed, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text("Start GPS", style = MaterialTheme.typography.labelLarge)
}
Button(
modifier = Modifier.weight(1f),
onClick = {
viewModel.stopProvideLocation()
scope.launch { snackbarHostState.showSnackbar("GPS Sharing Stopped") }
},
shape = MaterialTheme.shapes.medium,
colors = colors,
) {
Icon(imageVector = Icons.Rounded.GpsOff, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text("Stop GPS", style = MaterialTheme.typography.labelLarge)
}
}
}

View file

@ -1,363 +0,0 @@
/*
* Copyright (c) 2025-2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("DEPRECATION") // IMeshService is deprecated but still required for AIDL binding
package com.meshtastic.android.meshserviceexample
import android.content.Intent
import android.os.Build
import android.os.Parcelable
import android.os.RemoteException
import android.util.Log
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import okio.ByteString.Companion.toByteString
import org.meshtastic.core.common.util.nowMillis
import org.meshtastic.core.common.util.toDate
import org.meshtastic.core.common.util.toInstant
import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MessageStatus
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.core.model.Position
import org.meshtastic.core.service.IMeshService
import org.meshtastic.proto.PortNum
import java.text.SimpleDateFormat
import java.util.Locale
import kotlin.random.Random
private const val TAG = "MeshServiceViewModel"
/** ViewModel for MeshServiceExample. Handles interaction with IMeshService AIDL and manages UI state. */
@Suppress("TooManyFunctions")
class MeshServiceViewModel : ViewModel() {
private var meshService: IMeshService? = null
private val _myNodeInfo = MutableStateFlow<MyNodeInfo?>(null)
val myNodeInfo: StateFlow<MyNodeInfo?> = _myNodeInfo.asStateFlow()
private val _myId = MutableStateFlow<String?>(null)
val myId: StateFlow<String?> = _myId.asStateFlow()
private val _nodes = MutableStateFlow<List<NodeInfo>>(emptyList())
val nodes: StateFlow<List<NodeInfo>> = _nodes.asStateFlow()
private val _serviceConnectionStatus = MutableStateFlow(false)
val serviceConnectionStatus: StateFlow<Boolean> = _serviceConnectionStatus.asStateFlow()
private val _message = MutableStateFlow("")
val message: StateFlow<String> = _message.asStateFlow()
private val _connectionState = MutableStateFlow("UNKNOWN")
val connectionState: StateFlow<String> = _connectionState.asStateFlow()
private val _packetLog = MutableStateFlow<List<String>>(emptyList())
val packetLog: StateFlow<List<String>> = _packetLog.asStateFlow()
fun onServiceConnected(service: IMeshService?) {
meshService = service
_serviceConnectionStatus.value = true
updateAllData()
addToLog("Service Connected")
}
fun onServiceDisconnected() {
meshService = null
_serviceConnectionStatus.value = false
addToLog("Service Disconnected")
}
private fun updateAllData() {
requestMyNodeInfo()
requestNodes()
updateConnectionState()
updateMyId()
}
fun updateMyId() {
meshService?.let {
try {
_myId.value = it.myId
} catch (e: RemoteException) {
Log.e(TAG, "Failed to get MyId", e)
}
}
}
fun updateConnectionState() {
meshService?.let {
try {
val state = it.connectionState() ?: "UNKNOWN"
_connectionState.value = state
addToLog("Connection State: $state")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to get connection state", e)
}
}
}
fun sendMessage(text: String) {
meshService?.let { service ->
try {
val packet =
DataPacket(
to = DataPacket.ID_BROADCAST,
bytes = text.encodeToByteArray().toByteString(),
dataType = PortNum.TEXT_MESSAGE_APP.value,
from = DataPacket.ID_LOCAL,
time = nowMillis,
id = service.packetId,
status = MessageStatus.UNKNOWN,
hopLimit = 3,
channel = 0,
wantAck = true,
)
service.send(packet)
Log.d(TAG, "Message sent successfully, assigned ID: ${packet.id}")
addToLog("Sent: $text (ID: ${packet.id})")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to send message", e)
addToLog("Failed to send message: ${e.message}")
}
} ?: 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 = nowMillis,
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 {
_myNodeInfo.value = it.myNodeInfo
} catch (e: RemoteException) {
Log.e(TAG, "Failed to get MyNodeInfo", e)
}
}
}
fun requestNodes() {
meshService?.let {
try {
_nodes.value = it.nodes ?: emptyList()
} catch (e: RemoteException) {
Log.e(TAG, "Failed to get nodes", e)
}
}
}
fun startProvideLocation() {
try {
meshService?.startProvideLocation()
addToLog("Started GPS sharing")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to start providing location", e)
}
}
fun stopProvideLocation() {
try {
meshService?.stopProvideLocation()
addToLog("Stopped GPS sharing")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to stop providing location", e)
}
}
fun requestTraceroute(nodeNum: Int) {
meshService?.let {
try {
it.requestTraceroute(Random.nextInt(), nodeNum)
Log.i(TAG, "Traceroute requested for node $nodeNum")
addToLog("Requested Traceroute for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request traceroute", e)
}
}
}
fun requestTelemetry(nodeNum: Int) {
meshService?.let {
try {
it.requestTelemetry(Random.nextInt(), nodeNum, 1)
Log.i(TAG, "Telemetry requested for node $nodeNum")
addToLog("Requested Telemetry for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request telemetry", e)
}
}
}
fun requestNeighborInfo(nodeNum: Int) {
meshService?.let {
try {
it.requestNeighborInfo(Random.nextInt(), nodeNum)
Log.i(TAG, "Neighbor info requested for node $nodeNum")
addToLog("Requested Neighbors for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request neighbor info", e)
}
}
}
fun requestPosition(nodeNum: Int) {
meshService?.let {
try {
it.requestPosition(nodeNum, Position(0.0, 0.0, 0))
Log.i(TAG, "Position requested for node $nodeNum")
addToLog("Requested Position for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request position", e)
}
}
}
fun requestUserInfo(nodeNum: Int) {
meshService?.let {
try {
it.requestUserInfo(nodeNum)
Log.i(TAG, "User info requested for node $nodeNum")
addToLog("Requested User Info for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request user info", e)
}
}
}
fun requestDeviceConnectionStatus(nodeNum: Int) {
meshService?.let {
try {
it.getDeviceConnectionStatus(Random.nextInt(), nodeNum)
Log.i(TAG, "Device connection status requested for node $nodeNum")
addToLog("Requested Connection Status for $nodeNum")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request device connection status", e)
}
}
}
fun rebootLocalDevice() {
meshService?.let {
try {
it.requestReboot(Random.nextInt(), 0)
Log.w(TAG, "Local reboot requested!")
addToLog("Requested Local Reboot")
} catch (e: RemoteException) {
Log.e(TAG, "Failed to request reboot", e)
}
}
}
fun handleIncomingIntent(intent: Intent) {
val action = intent.action ?: return
Log.d(TAG, "Received broadcast: $action")
when (action) {
"com.geeksville.mesh.NODE_CHANGE" -> handleNodeChange(intent)
"com.geeksville.mesh.CONNECTION_CHANGED",
"com.geeksville.mesh.MESH_CONNECTED",
"com.geeksville.mesh.MESH_DISCONNECTED",
-> updateConnectionState()
"com.geeksville.mesh.MESSAGE_STATUS" -> handleMessageStatus(intent)
else ->
if (action.startsWith("com.geeksville.mesh.RECEIVED.")) {
handleReceivedPacket(action, intent)
}
}
}
private fun handleNodeChange(intent: Intent) {
val nodeInfo = intent.getParcelableCompat("com.geeksville.mesh.NodeInfo", NodeInfo::class.java)
nodeInfo?.let { ni ->
Log.d(TAG, "Node updated: ${ni.num}")
_nodes.value =
_nodes.value.toMutableList().apply {
val index = indexOfFirst { it.num == ni.num }
if (index != -1) set(index, ni) else add(ni)
}
}
}
private fun handleMessageStatus(intent: Intent) {
val id = intent.getIntExtra("com.geeksville.mesh.PacketId", 0)
val status = intent.getParcelableCompat("com.geeksville.mesh.Status", MessageStatus::class.java)
Log.d(TAG, "Message Status for ID $id: $status")
addToLog("Msg Status ID $id: $status")
}
private fun handleReceivedPacket(action: String, intent: Intent) {
val packet = intent.getParcelableCompat("com.geeksville.mesh.Payload", DataPacket::class.java)
if (packet == null) {
Log.e(TAG, "Received packet extra was NULL for action: $action")
addToLog("Error: Packet payload was null for $action")
return
}
Log.d(TAG, "Packet received: $packet")
if (packet.dataType == PortNum.TEXT_MESSAGE_APP.value) {
val receivedText = packet.bytes?.utf8() ?: ""
_message.value = "From ${packet.from}: $receivedText"
addToLog("Received Text from ${packet.from}: $receivedText")
} else {
val type = action.substringAfterLast(".")
addToLog("Received $type from ${packet.from}. Check Logcat for details.")
}
}
private fun addToLog(entry: String) {
val date = nowMillis.toInstant().toDate()
val timestamp = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(date)
val logEntry = "[$timestamp] $entry"
Log.d(TAG, "Log: $logEntry")
@Suppress("MagicNumber")
_packetLog.value = (listOf(logEntry) + _packetLog.value).take(50)
}
private fun <T : Parcelable> Intent.getParcelableCompat(key: String, clazz: Class<T>): T? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableExtra(key, clazz)
} else {
@Suppress("DEPRECATION")
getParcelableExtra(key)
}
}

View file

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View file

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Изпратете съобщение за здравей</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Beispiel MeshService</string>
<string name="send_hello_message">Hallo Nachricht senden</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Ejemplo de servicio de red</string>
<string name="send_hello_message">Enviar Mensaje Hola</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceNäidis</string>
<string name="send_hello_message">Saada Tere sõnum</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExamplebled</string>
<string name="send_hello_message">Lähetä tervehdysviesti</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Exemple de service de maillage</string>
<string name="send_hello_message">Envoyer un message dannonce</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Hello Üzenet Küldés</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Invia Messaggio di Saluto</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">ExemploServiçoMesh</string>
<string name="send_hello_message">Enviar Mensagem de Olá</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Отправить приветственное сообщение</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Mesh-service exempel</string>
<string name="send_hello_message">Skicka Hej-meddelande</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Надіслати привітальне повідомлення</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
<string name="send_hello_message">Send Hello Message</string>
</resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">Mesh 服務範例</string>
<string name="send_hello_message">發送打招呼訊息</string>
</resources>

View file

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2025 Meshtastic LLC
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">MeshServiceExample</string>
</resources>

View file

@ -1,9 +0,0 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.MeshServiceExample" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
<style name="Theme.MeshServiceExample" parent="Base.Theme.MeshServiceExample" />
</resources>

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View file

@ -47,7 +47,6 @@ include(
":feature:firmware",
":feature:wifi-provision",
":feature:widget",
":mesh_service_example",
":desktop",
)
rootProject.name = "MeshtasticAndroid"