From c1050da852135b333318892562fa75c533292126 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 20 Dec 2025 23:30:35 +0100 Subject: [PATCH] chore(android): update icons and platform config --- apps/android/app/build.gradle.kts | 6 ++++- apps/android/app/src/main/AndroidManifest.xml | 8 ++++++ .../clawdis/node/NodeForegroundService.kt | 20 ++------------ .../com/steipete/clawdis/node/SecurePrefs.kt | 27 ++++++++++--------- .../clawdis/node/bridge/BridgeDiscovery.kt | 4 +-- .../clawdis/node/node/CameraCaptureManager.kt | 5 +++- .../clawdis/node/node/CanvasController.kt | 9 ++++--- .../ic_launcher.xml | 2 +- .../ic_launcher_round.xml | 2 +- .../app/src/main/res/values/themes.xml | 5 ++-- .../app/src/main/res/xml/backup_rules.xml | 4 +++ .../main/res/xml/data_extraction_rules.xml | 9 +++++++ .../main/res/xml/network_security_config.xml | 4 +-- 13 files changed, 58 insertions(+), 47 deletions(-) rename apps/android/app/src/main/res/{mipmap-anydpi-v26 => mipmap-anydpi}/ic_launcher.xml (79%) rename apps/android/app/src/main/res/{mipmap-anydpi-v26 => mipmap-anydpi}/ic_launcher_round.xml (79%) create mode 100644 apps/android/app/src/main/res/xml/backup_rules.xml create mode 100644 apps/android/app/src/main/res/xml/data_extraction_rules.xml diff --git a/apps/android/app/build.gradle.kts b/apps/android/app/build.gradle.kts index ae9ac6eb1..832c90b72 100644 --- a/apps/android/app/build.gradle.kts +++ b/apps/android/app/build.gradle.kts @@ -47,6 +47,10 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + + lint { + disable += setOf("IconLauncherShape") + } } dependencies { @@ -56,7 +60,7 @@ dependencies { implementation("androidx.core:core-ktx:1.17.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.0") - implementation("androidx.activity:activity-compose:1.12.1") + implementation("androidx.activity:activity-compose:1.12.2") implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") diff --git a/apps/android/app/src/main/AndroidManifest.xml b/apps/android/app/src/main/AndroidManifest.xml index e8547b4eb..93794dd08 100644 --- a/apps/android/app/src/main/AndroidManifest.xml +++ b/apps/android/app/src/main/AndroidManifest.xml @@ -12,12 +12,20 @@ + + = Build.VERSION_CODES.M) { - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } + val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE val stopPending = PendingIntent.getService(this, 2, stopIntent, flags) return NotificationCompat.Builder(this, CHANNEL_ID) @@ -126,11 +119,6 @@ class NodeForegroundService : Service() { } private fun startForegroundWithTypes(notification: Notification, requiresMic: Boolean) { - if (Build.VERSION.SDK_INT < 29) { - startForeground(NOTIFICATION_ID, notification) - return - } - if (didStartForeground && requiresMic == lastRequiresMic) { updateNotification(notification) return @@ -162,11 +150,7 @@ class NodeForegroundService : Service() { fun start(context: Context) { val intent = Intent(context, NodeForegroundService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } + context.startForegroundService(intent) } fun stop(context: Context) { diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/SecurePrefs.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/SecurePrefs.kt index 51545095f..a0be15e13 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/SecurePrefs.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/SecurePrefs.kt @@ -3,6 +3,7 @@ package com.steipete.clawdis.node import android.content.Context +import androidx.core.content.edit import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKey import kotlinx.coroutines.flow.MutableStateFlow @@ -70,39 +71,39 @@ class SecurePrefs(context: Context) { fun setLastDiscoveredStableId(value: String) { val trimmed = value.trim() - prefs.edit().putString("bridge.lastDiscoveredStableId", trimmed).apply() + prefs.edit { putString("bridge.lastDiscoveredStableId", trimmed) } _lastDiscoveredStableId.value = trimmed } fun setDisplayName(value: String) { val trimmed = value.trim() - prefs.edit().putString(displayNameKey, trimmed).apply() + prefs.edit { putString(displayNameKey, trimmed) } _displayName.value = trimmed } fun setCameraEnabled(value: Boolean) { - prefs.edit().putBoolean("camera.enabled", value).apply() + prefs.edit { putBoolean("camera.enabled", value) } _cameraEnabled.value = value } fun setPreventSleep(value: Boolean) { - prefs.edit().putBoolean("screen.preventSleep", value).apply() + prefs.edit { putBoolean("screen.preventSleep", value) } _preventSleep.value = value } fun setManualEnabled(value: Boolean) { - prefs.edit().putBoolean("bridge.manual.enabled", value).apply() + prefs.edit { putBoolean("bridge.manual.enabled", value) } _manualEnabled.value = value } fun setManualHost(value: String) { val trimmed = value.trim() - prefs.edit().putString("bridge.manual.host", trimmed).apply() + prefs.edit { putString("bridge.manual.host", trimmed) } _manualHost.value = trimmed } fun setManualPort(value: Int) { - prefs.edit().putInt("bridge.manual.port", value).apply() + prefs.edit { putInt("bridge.manual.port", value) } _manualPort.value = value } @@ -113,14 +114,14 @@ class SecurePrefs(context: Context) { fun saveBridgeToken(token: String) { val key = "bridge.token.${_instanceId.value}" - prefs.edit().putString(key, token.trim()).apply() + prefs.edit { putString(key, token.trim()) } } private fun loadOrCreateInstanceId(): String { val existing = prefs.getString("node.instanceId", null)?.trim() if (!existing.isNullOrBlank()) return existing val fresh = UUID.randomUUID().toString() - prefs.edit().putString("node.instanceId", fresh).apply() + prefs.edit { putString("node.instanceId", fresh) } return fresh } @@ -131,7 +132,7 @@ class SecurePrefs(context: Context) { val candidate = DeviceNames.bestDefaultNodeName(context).trim() val resolved = candidate.ifEmpty { "Android Node" } - prefs.edit().putString(displayNameKey, resolved).apply() + prefs.edit { putString(displayNameKey, resolved) } return resolved } @@ -139,12 +140,12 @@ class SecurePrefs(context: Context) { val sanitized = WakeWords.sanitize(words, defaultWakeWords) val encoded = JsonArray(sanitized.map { JsonPrimitive(it) }).toString() - prefs.edit().putString("voiceWake.triggerWords", encoded).apply() + prefs.edit { putString("voiceWake.triggerWords", encoded) } _wakeWords.value = sanitized } fun setVoiceWakeMode(mode: VoiceWakeMode) { - prefs.edit().putString(voiceWakeModeKey, mode.rawValue).apply() + prefs.edit { putString(voiceWakeModeKey, mode.rawValue) } _voiceWakeMode.value = mode } @@ -154,7 +155,7 @@ class SecurePrefs(context: Context) { // Default ON (foreground) when unset. if (raw.isNullOrBlank()) { - prefs.edit().putString(voiceWakeModeKey, resolved.rawValue).apply() + prefs.edit { putString(voiceWakeModeKey, resolved.rawValue) } } return resolved diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeDiscovery.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeDiscovery.kt index ca9c5ef39..a0e8032bc 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeDiscovery.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/bridge/BridgeDiscovery.kt @@ -6,7 +6,6 @@ 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 java.io.IOException @@ -181,7 +180,6 @@ class BridgeDiscovery( } private fun txt(info: NsdServiceInfo, key: String): String? { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return null val bytes = info.attributes[key] ?: return null return try { String(bytes, Charsets.UTF_8).trim().ifEmpty { null } @@ -401,7 +399,7 @@ class BridgeDiscovery( dns.rawQuery( network, wireQuery, - 0, + DnsResolver.FLAG_EMPTY, dnsExecutor, signal, object : DnsResolver.Callback { diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CameraCaptureManager.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CameraCaptureManager.kt index b3a11b2bf..4f1501340 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CameraCaptureManager.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CameraCaptureManager.kt @@ -2,6 +2,7 @@ package com.steipete.clawdis.node.node import android.Manifest import android.content.Context +import android.annotation.SuppressLint import android.graphics.Bitmap import android.graphics.BitmapFactory import android.util.Base64 @@ -18,6 +19,7 @@ import androidx.camera.video.VideoCapture import androidx.camera.video.VideoRecordEvent import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.checkSelfPermission +import androidx.core.graphics.scale import com.steipete.clawdis.node.PermissionRequester import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine @@ -92,7 +94,7 @@ class CameraCaptureManager(private val context: Context) { (decoded.height.toDouble() * (maxWidth.toDouble() / decoded.width.toDouble())) .toInt() .coerceAtLeast(1) - Bitmap.createScaledBitmap(decoded, maxWidth, h, true) + decoded.scale(maxWidth, h) } else { decoded } @@ -108,6 +110,7 @@ class CameraCaptureManager(private val context: Context) { ) } + @SuppressLint("MissingPermission") suspend fun clip(paramsJson: String?): Payload = withContext(Dispatchers.Main) { ensureCameraPermission() diff --git a/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CanvasController.kt b/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CanvasController.kt index b0f4d4b25..5c3e90d69 100644 --- a/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CanvasController.kt +++ b/apps/android/app/src/main/java/com/steipete/clawdis/node/node/CanvasController.kt @@ -1,10 +1,11 @@ package com.steipete.clawdis.node.node import android.graphics.Bitmap -import android.os.Build import android.graphics.Canvas import android.os.Looper import android.webkit.WebView +import androidx.core.graphics.createBitmap +import androidx.core.graphics.scale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext @@ -80,7 +81,7 @@ class CanvasController { val scaled = if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) { val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1) - Bitmap.createScaledBitmap(bmp, maxWidth, h, true) + bmp.scale(maxWidth, h) } else { bmp } @@ -97,7 +98,7 @@ class CanvasController { val scaled = if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) { val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1) - Bitmap.createScaledBitmap(bmp, maxWidth, h, true) + bmp.scale(maxWidth, h) } else { bmp } @@ -116,7 +117,7 @@ class CanvasController { suspendCancellableCoroutine { cont -> val width = width.coerceAtLeast(1) val height = height.coerceAtLeast(1) - val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val bitmap = createBitmap(width, height, Bitmap.Config.ARGB_8888) // WebView isn't supported by PixelCopy.request(...) directly; draw() is the most reliable // cross-version snapshot for this lightweight "canvas" use-case. diff --git a/apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/apps/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml similarity index 79% rename from apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml rename to apps/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml index a65c12916..6f379984a 100644 --- a/apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/apps/android/app/src/main/res/mipmap-anydpi/ic_launcher.xml @@ -2,5 +2,5 @@ + - diff --git a/apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/apps/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml similarity index 79% rename from apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to apps/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml index a65c12916..6f379984a 100644 --- a/apps/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/apps/android/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml @@ -2,5 +2,5 @@ + - diff --git a/apps/android/app/src/main/res/values/themes.xml b/apps/android/app/src/main/res/values/themes.xml index 86d2e2f3b..881dbe537 100644 --- a/apps/android/app/src/main/res/values/themes.xml +++ b/apps/android/app/src/main/res/values/themes.xml @@ -1,8 +1,7 @@ - + - diff --git a/apps/android/app/src/main/res/xml/backup_rules.xml b/apps/android/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..21e592ca4 --- /dev/null +++ b/apps/android/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,4 @@ + + + + diff --git a/apps/android/app/src/main/res/xml/data_extraction_rules.xml b/apps/android/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 000000000..46e58c54e --- /dev/null +++ b/apps/android/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/android/app/src/main/res/xml/network_security_config.xml b/apps/android/app/src/main/res/xml/network_security_config.xml index 68016a00b..136225f61 100644 --- a/apps/android/app/src/main/res/xml/network_security_config.xml +++ b/apps/android/app/src/main/res/xml/network_security_config.xml @@ -1,7 +1,7 @@ - + - + clawdis.internal