From 26cd4ad8eeef6c14390cc3dde01342100fe03aa4 Mon Sep 17 00:00:00 2001 From: goweii Date: Wed, 18 Mar 2026 12:43:07 +0800 Subject: [PATCH 1/5] Android: lower minSdk to 26 and add theme color fallbacks --- apps/android/app/build.gradle.kts | 2 +- .../java/ai/openclaw/app/ui/OpenClawTheme.kt | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/android/app/build.gradle.kts b/apps/android/app/build.gradle.kts index 46afccbc3bf..dac12627841 100644 --- a/apps/android/app/build.gradle.kts +++ b/apps/android/app/build.gradle.kts @@ -63,7 +63,7 @@ android { defaultConfig { applicationId = "ai.openclaw.app" - minSdk = 31 + minSdk = 26 targetSdk = 36 versionCode = 2026031400 versionName = "2026.3.14" diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt index cfcceb4f3da..1bdb43541fc 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt @@ -1,19 +1,25 @@ package ai.openclaw.app.ui +import android.content.Context +import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme 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.runtime.CompositionLocalProvider import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.core.content.ContextCompat @Composable fun OpenClawTheme(content: @Composable () -> Unit) { val context = LocalContext.current val isDark = isSystemInDarkTheme() - val colorScheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + val colorScheme = colorScheme(context, isDark) val mobileColors = if (isDark) darkMobileColors() else lightMobileColors() CompositionLocalProvider(LocalMobileColors provides mobileColors) { @@ -21,6 +27,19 @@ fun OpenClawTheme(content: @Composable () -> Unit) { } } +private fun colorScheme(context: Context, isDark: Boolean): ColorScheme { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return when { + isDark -> dynamicDarkColorScheme(context) + else -> dynamicLightColorScheme(context) + } + } + return when { + isDark -> darkColorScheme() + else -> lightColorScheme() + } +} + @Composable fun overlayContainerColor(): Color { val scheme = MaterialTheme.colorScheme From 1799ca930a947fcd148f3ca4172733f7af320d0a Mon Sep 17 00:00:00 2001 From: goweii Date: Wed, 18 Mar 2026 13:14:49 +0800 Subject: [PATCH 2/5] Android: clean up theme imports --- .../app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt b/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt index 1bdb43541fc..9b1d0b151c5 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/ui/OpenClawTheme.kt @@ -6,14 +6,13 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext -import androidx.core.content.ContextCompat @Composable fun OpenClawTheme(content: @Composable () -> Unit) { From 4499924b049982513beae7f8c64a7913db407325 Mon Sep 17 00:00:00 2001 From: goweii Date: Wed, 18 Mar 2026 19:27:49 +0800 Subject: [PATCH 3/5] Android: fix startForeground compatibility for older SDKs --- .../main/java/ai/openclaw/app/NodeForegroundService.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt b/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt index 4c7ccdd56e5..4ff53f05ca9 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt @@ -8,6 +8,7 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.pm.ServiceInfo +import android.os.Build import androidx.core.app.NotificationCompat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -137,8 +138,13 @@ class NodeForegroundService : Service() { updateNotification(notification) return } - startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) - didStartForeground = true + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) + } else { + @Suppress("DEPRECATION") + startForeground(NOTIFICATION_ID, notification) + } + didStartForeground = true } companion object { From 3ae2a837deda1561b0ed7b752490be817a806e4b Mon Sep 17 00:00:00 2001 From: goweii Date: Wed, 18 Mar 2026 20:03:17 +0800 Subject: [PATCH 4/5] Android: gate DnsResolver usage behind API level checks --- .../openclaw/app/gateway/GatewayDiscovery.kt | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayDiscovery.kt b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayDiscovery.kt index f83af46cc65..a0e2628c66e 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayDiscovery.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayDiscovery.kt @@ -6,8 +6,10 @@ import android.net.DnsResolver import android.net.NetworkCapabilities import android.net.nsd.NsdManager import android.net.nsd.NsdServiceInfo +import android.os.Build import android.os.CancellationSignal import android.util.Log +import androidx.annotation.RequiresApi import java.io.IOException import java.net.InetSocketAddress import java.nio.ByteBuffer @@ -50,7 +52,7 @@ class GatewayDiscovery( ) { private val nsd = context.getSystemService(NsdManager::class.java) private val connectivity = context.getSystemService(ConnectivityManager::class.java) - private val dns = DnsResolver.getInstance() + private val dns = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) DnsResolver.getInstance() else null private val serviceType = "_openclaw-gw._tcp." private val wideAreaDomain = System.getenv("OPENCLAW_WIDE_AREA_DOMAIN") private val logTag = "OpenClaw/GatewayDiscovery" @@ -321,8 +323,11 @@ class GatewayDiscovery( return null } - val system = queryViaSystemDns(query) - if (records(system, Section.ANSWER).any { it.type == type }) return system + val system = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val system = queryViaSystemDns(query) + if (records(system, Section.ANSWER).any { it.type == type }) return system + system + } else null val direct = createDirectResolver() ?: return system return try { @@ -333,6 +338,7 @@ class GatewayDiscovery( } } + @RequiresApi(Build.VERSION_CODES.Q) private suspend fun queryViaSystemDns(query: Message): Message? { val network = preferredDnsNetwork() val bytes = @@ -439,11 +445,12 @@ class GatewayDiscovery( } } - private suspend fun rawQuery(network: android.net.Network?, wireQuery: ByteArray): ByteArray = - suspendCancellableCoroutine { cont -> + @RequiresApi(Build.VERSION_CODES.Q) + private suspend fun rawQuery(network: android.net.Network?, wireQuery: ByteArray): ByteArray { + val dns = this.dns ?: throw IOException("DnsResolver not available on this platform") + return suspendCancellableCoroutine { cont -> val signal = CancellationSignal() cont.invokeOnCancellation { signal.cancel() } - dns.rawQuery( network, wireQuery, @@ -461,6 +468,7 @@ class GatewayDiscovery( }, ) } + } private fun txtValue(records: List, key: String): String? { val prefix = "$key=" From 8387c2de0025ce490172714f9d14d347746b8796 Mon Sep 17 00:00:00 2001 From: goweii Date: Wed, 18 Mar 2026 20:04:00 +0800 Subject: [PATCH 5/5] Android: fix indentation in NodeForegroundService --- .../app/src/main/java/ai/openclaw/app/NodeForegroundService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt b/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt index 4ff53f05ca9..fae58f2965c 100644 --- a/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt +++ b/apps/android/app/src/main/java/ai/openclaw/app/NodeForegroundService.kt @@ -144,7 +144,7 @@ class NodeForegroundService : Service() { @Suppress("DEPRECATION") startForeground(NOTIFICATION_ID, notification) } - didStartForeground = true + didStartForeground = true } companion object {