diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b1fdde668..e5d62f95e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -108,6 +108,10 @@
android:localeConfig="@xml/locales_config"
android:networkSecurityConfig="@xml/network_security_config">
+
+
+
diff --git a/app/src/test/java/com/geeksville/mesh/repository/radio/TCPInterfaceTest.kt b/app/src/test/java/com/geeksville/mesh/repository/radio/TCPInterfaceTest.kt
index 57f749fa9..3725ffe36 100644
--- a/app/src/test/java/com/geeksville/mesh/repository/radio/TCPInterfaceTest.kt
+++ b/app/src/test/java/com/geeksville/mesh/repository/radio/TCPInterfaceTest.kt
@@ -55,6 +55,27 @@ class TCPInterfaceTest {
assertArrayEquals("Heartbeat bytes should match", expectedHeartbeat, tcpInterface.capturedBytes)
}
- // Since startConnect is private, we'd normally need reflection or to make a internal method.
- // For now, testing keepAlive is a good first step for stability.
+ @Test
+ fun `sendBytes does not crash when outStream is null`() = runTest {
+ val address = "192.168.1.1:4403"
+ val tcpInterface =
+ object : TCPInterface(service, dispatchers, address) {
+ override fun connect() {}
+ }
+
+ // This should not throw UninitializedPropertyAccessException
+ tcpInterface.sendBytes(byteArrayOf(1, 2, 3))
+ }
+
+ @Test
+ fun `flushBytes does not crash when outStream is null`() = runTest {
+ val address = "192.168.1.1:4403"
+ val tcpInterface =
+ object : TCPInterface(service, dispatchers, address) {
+ override fun connect() {}
+ }
+
+ // This should not throw UninitializedPropertyAccessException
+ tcpInterface.flushBytes()
+ }
}
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt
index 326486c34..2b790c00d 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/AboutScreen.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025 Meshtastic LLC
+ * 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
@@ -14,7 +14,6 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
package org.meshtastic.feature.settings
import androidx.compose.foundation.layout.fillMaxSize
@@ -22,9 +21,11 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
+import co.touchlab.kermit.Logger
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.ui.compose.m3.LibrariesContainer
import com.mikepenz.aboutlibraries.util.withContext
@@ -49,16 +50,26 @@ fun AboutScreen(onNavigateUp: () -> Unit) {
},
) { paddingValues ->
val context = LocalContext.current
- val libraries = Libs.Builder().withContext(context).build()
- LibrariesContainer(
- showAuthor = true,
- showVersion = true,
- showDescription = true,
- showLicenseBadges = true,
- showFundingBadges = true,
- modifier = Modifier.fillMaxSize().padding(paddingValues),
- libraries = libraries,
- )
+ val libraries = remember {
+ try {
+ Libs.Builder().withContext(context).build()
+ } catch (e: IllegalStateException) {
+ Logger.w("${e.message}")
+ null
+ }
+ }
+
+ if (libraries != null) {
+ LibrariesContainer(
+ showAuthor = true,
+ showVersion = true,
+ showDescription = true,
+ showLicenseBadges = true,
+ showFundingBadges = true,
+ modifier = Modifier.fillMaxSize().padding(paddingValues),
+ libraries = libraries,
+ )
+ }
}
}