From fb6a4c96b8dcc0d5c12a87a47d0ad863388b4132 Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Wed, 21 Jan 2026 10:21:10 -0600 Subject: [PATCH] fix: crashes (#4281) Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> --- app/src/main/AndroidManifest.xml | 4 +++ .../mesh/repository/radio/TCPInterface.kt | 24 +++++++++++-- app/src/main/res/raw/keep.xml | 3 ++ .../mesh/repository/radio/TCPInterfaceTest.kt | 25 +++++++++++-- .../feature/settings/AboutScreen.kt | 35 ++++++++++++------- 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/raw/keep.xml 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, + ) + } } }