chore(android): update icons and platform config
parent
873daf079c
commit
c1050da852
|
|
@ -47,6 +47,10 @@ android {
|
||||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lint {
|
||||||
|
disable += setOf("IconLauncherShape")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
@ -56,7 +60,7 @@ dependencies {
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.17.0")
|
implementation("androidx.core:core-ktx:1.17.0")
|
||||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.10.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")
|
||||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,20 @@
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.ACCESS_FINE_LOCATION"
|
android:name="android.permission.ACCESS_FINE_LOCATION"
|
||||||
android:maxSdkVersion="32" />
|
android:maxSdkVersion="32" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.ACCESS_COARSE_LOCATION"
|
||||||
|
android:maxSdkVersion="32" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".NodeApp"
|
android:name=".NodeApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.ServiceInfo
|
import android.content.pm.ServiceInfo
|
||||||
import android.os.Build
|
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -85,7 +84,6 @@ class NodeForegroundService : Service() {
|
||||||
override fun onBind(intent: Intent?) = null
|
override fun onBind(intent: Intent?) = null
|
||||||
|
|
||||||
private fun ensureChannel() {
|
private fun ensureChannel() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
|
||||||
val mgr = getSystemService(NotificationManager::class.java)
|
val mgr = getSystemService(NotificationManager::class.java)
|
||||||
val channel =
|
val channel =
|
||||||
NotificationChannel(
|
NotificationChannel(
|
||||||
|
|
@ -101,12 +99,7 @@ class NodeForegroundService : Service() {
|
||||||
|
|
||||||
private fun buildNotification(title: String, text: String): Notification {
|
private fun buildNotification(title: String, text: String): Notification {
|
||||||
val stopIntent = Intent(this, NodeForegroundService::class.java).setAction(ACTION_STOP)
|
val stopIntent = Intent(this, NodeForegroundService::class.java).setAction(ACTION_STOP)
|
||||||
val flags =
|
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
||||||
} else {
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
}
|
|
||||||
val stopPending = PendingIntent.getService(this, 2, stopIntent, flags)
|
val stopPending = PendingIntent.getService(this, 2, stopIntent, flags)
|
||||||
|
|
||||||
return NotificationCompat.Builder(this, CHANNEL_ID)
|
return NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
|
@ -126,11 +119,6 @@ class NodeForegroundService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startForegroundWithTypes(notification: Notification, requiresMic: Boolean) {
|
private fun startForegroundWithTypes(notification: Notification, requiresMic: Boolean) {
|
||||||
if (Build.VERSION.SDK_INT < 29) {
|
|
||||||
startForeground(NOTIFICATION_ID, notification)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (didStartForeground && requiresMic == lastRequiresMic) {
|
if (didStartForeground && requiresMic == lastRequiresMic) {
|
||||||
updateNotification(notification)
|
updateNotification(notification)
|
||||||
return
|
return
|
||||||
|
|
@ -162,11 +150,7 @@ class NodeForegroundService : Service() {
|
||||||
|
|
||||||
fun start(context: Context) {
|
fun start(context: Context) {
|
||||||
val intent = Intent(context, NodeForegroundService::class.java)
|
val intent = Intent(context, NodeForegroundService::class.java)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
context.startForegroundService(intent)
|
||||||
context.startForegroundService(intent)
|
|
||||||
} else {
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop(context: Context) {
|
fun stop(context: Context) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
package com.steipete.clawdis.node
|
package com.steipete.clawdis.node
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import androidx.core.content.edit
|
||||||
import androidx.security.crypto.EncryptedSharedPreferences
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
import androidx.security.crypto.MasterKey
|
import androidx.security.crypto.MasterKey
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -70,39 +71,39 @@ class SecurePrefs(context: Context) {
|
||||||
|
|
||||||
fun setLastDiscoveredStableId(value: String) {
|
fun setLastDiscoveredStableId(value: String) {
|
||||||
val trimmed = value.trim()
|
val trimmed = value.trim()
|
||||||
prefs.edit().putString("bridge.lastDiscoveredStableId", trimmed).apply()
|
prefs.edit { putString("bridge.lastDiscoveredStableId", trimmed) }
|
||||||
_lastDiscoveredStableId.value = trimmed
|
_lastDiscoveredStableId.value = trimmed
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDisplayName(value: String) {
|
fun setDisplayName(value: String) {
|
||||||
val trimmed = value.trim()
|
val trimmed = value.trim()
|
||||||
prefs.edit().putString(displayNameKey, trimmed).apply()
|
prefs.edit { putString(displayNameKey, trimmed) }
|
||||||
_displayName.value = trimmed
|
_displayName.value = trimmed
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setCameraEnabled(value: Boolean) {
|
fun setCameraEnabled(value: Boolean) {
|
||||||
prefs.edit().putBoolean("camera.enabled", value).apply()
|
prefs.edit { putBoolean("camera.enabled", value) }
|
||||||
_cameraEnabled.value = value
|
_cameraEnabled.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setPreventSleep(value: Boolean) {
|
fun setPreventSleep(value: Boolean) {
|
||||||
prefs.edit().putBoolean("screen.preventSleep", value).apply()
|
prefs.edit { putBoolean("screen.preventSleep", value) }
|
||||||
_preventSleep.value = value
|
_preventSleep.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setManualEnabled(value: Boolean) {
|
fun setManualEnabled(value: Boolean) {
|
||||||
prefs.edit().putBoolean("bridge.manual.enabled", value).apply()
|
prefs.edit { putBoolean("bridge.manual.enabled", value) }
|
||||||
_manualEnabled.value = value
|
_manualEnabled.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setManualHost(value: String) {
|
fun setManualHost(value: String) {
|
||||||
val trimmed = value.trim()
|
val trimmed = value.trim()
|
||||||
prefs.edit().putString("bridge.manual.host", trimmed).apply()
|
prefs.edit { putString("bridge.manual.host", trimmed) }
|
||||||
_manualHost.value = trimmed
|
_manualHost.value = trimmed
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setManualPort(value: Int) {
|
fun setManualPort(value: Int) {
|
||||||
prefs.edit().putInt("bridge.manual.port", value).apply()
|
prefs.edit { putInt("bridge.manual.port", value) }
|
||||||
_manualPort.value = value
|
_manualPort.value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,14 +114,14 @@ class SecurePrefs(context: Context) {
|
||||||
|
|
||||||
fun saveBridgeToken(token: String) {
|
fun saveBridgeToken(token: String) {
|
||||||
val key = "bridge.token.${_instanceId.value}"
|
val key = "bridge.token.${_instanceId.value}"
|
||||||
prefs.edit().putString(key, token.trim()).apply()
|
prefs.edit { putString(key, token.trim()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadOrCreateInstanceId(): String {
|
private fun loadOrCreateInstanceId(): String {
|
||||||
val existing = prefs.getString("node.instanceId", null)?.trim()
|
val existing = prefs.getString("node.instanceId", null)?.trim()
|
||||||
if (!existing.isNullOrBlank()) return existing
|
if (!existing.isNullOrBlank()) return existing
|
||||||
val fresh = UUID.randomUUID().toString()
|
val fresh = UUID.randomUUID().toString()
|
||||||
prefs.edit().putString("node.instanceId", fresh).apply()
|
prefs.edit { putString("node.instanceId", fresh) }
|
||||||
return fresh
|
return fresh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +132,7 @@ class SecurePrefs(context: Context) {
|
||||||
val candidate = DeviceNames.bestDefaultNodeName(context).trim()
|
val candidate = DeviceNames.bestDefaultNodeName(context).trim()
|
||||||
val resolved = candidate.ifEmpty { "Android Node" }
|
val resolved = candidate.ifEmpty { "Android Node" }
|
||||||
|
|
||||||
prefs.edit().putString(displayNameKey, resolved).apply()
|
prefs.edit { putString(displayNameKey, resolved) }
|
||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,12 +140,12 @@ class SecurePrefs(context: Context) {
|
||||||
val sanitized = WakeWords.sanitize(words, defaultWakeWords)
|
val sanitized = WakeWords.sanitize(words, defaultWakeWords)
|
||||||
val encoded =
|
val encoded =
|
||||||
JsonArray(sanitized.map { JsonPrimitive(it) }).toString()
|
JsonArray(sanitized.map { JsonPrimitive(it) }).toString()
|
||||||
prefs.edit().putString("voiceWake.triggerWords", encoded).apply()
|
prefs.edit { putString("voiceWake.triggerWords", encoded) }
|
||||||
_wakeWords.value = sanitized
|
_wakeWords.value = sanitized
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setVoiceWakeMode(mode: VoiceWakeMode) {
|
fun setVoiceWakeMode(mode: VoiceWakeMode) {
|
||||||
prefs.edit().putString(voiceWakeModeKey, mode.rawValue).apply()
|
prefs.edit { putString(voiceWakeModeKey, mode.rawValue) }
|
||||||
_voiceWakeMode.value = mode
|
_voiceWakeMode.value = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,7 +155,7 @@ class SecurePrefs(context: Context) {
|
||||||
|
|
||||||
// Default ON (foreground) when unset.
|
// Default ON (foreground) when unset.
|
||||||
if (raw.isNullOrBlank()) {
|
if (raw.isNullOrBlank()) {
|
||||||
prefs.edit().putString(voiceWakeModeKey, resolved.rawValue).apply()
|
prefs.edit { putString(voiceWakeModeKey, resolved.rawValue) }
|
||||||
}
|
}
|
||||||
|
|
||||||
return resolved
|
return resolved
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import android.net.DnsResolver
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.nsd.NsdManager
|
import android.net.nsd.NsdManager
|
||||||
import android.net.nsd.NsdServiceInfo
|
import android.net.nsd.NsdServiceInfo
|
||||||
import android.os.Build
|
|
||||||
import android.os.CancellationSignal
|
import android.os.CancellationSignal
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
@ -181,7 +180,6 @@ class BridgeDiscovery(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun txt(info: NsdServiceInfo, key: String): String? {
|
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
|
val bytes = info.attributes[key] ?: return null
|
||||||
return try {
|
return try {
|
||||||
String(bytes, Charsets.UTF_8).trim().ifEmpty { null }
|
String(bytes, Charsets.UTF_8).trim().ifEmpty { null }
|
||||||
|
|
@ -401,7 +399,7 @@ class BridgeDiscovery(
|
||||||
dns.rawQuery(
|
dns.rawQuery(
|
||||||
network,
|
network,
|
||||||
wireQuery,
|
wireQuery,
|
||||||
0,
|
DnsResolver.FLAG_EMPTY,
|
||||||
dnsExecutor,
|
dnsExecutor,
|
||||||
signal,
|
signal,
|
||||||
object : DnsResolver.Callback<ByteArray> {
|
object : DnsResolver.Callback<ByteArray> {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.steipete.clawdis.node.node
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
|
@ -18,6 +19,7 @@ import androidx.camera.video.VideoCapture
|
||||||
import androidx.camera.video.VideoRecordEvent
|
import androidx.camera.video.VideoRecordEvent
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.ContextCompat.checkSelfPermission
|
import androidx.core.content.ContextCompat.checkSelfPermission
|
||||||
|
import androidx.core.graphics.scale
|
||||||
import com.steipete.clawdis.node.PermissionRequester
|
import com.steipete.clawdis.node.PermissionRequester
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
|
@ -92,7 +94,7 @@ class CameraCaptureManager(private val context: Context) {
|
||||||
(decoded.height.toDouble() * (maxWidth.toDouble() / decoded.width.toDouble()))
|
(decoded.height.toDouble() * (maxWidth.toDouble() / decoded.width.toDouble()))
|
||||||
.toInt()
|
.toInt()
|
||||||
.coerceAtLeast(1)
|
.coerceAtLeast(1)
|
||||||
Bitmap.createScaledBitmap(decoded, maxWidth, h, true)
|
decoded.scale(maxWidth, h)
|
||||||
} else {
|
} else {
|
||||||
decoded
|
decoded
|
||||||
}
|
}
|
||||||
|
|
@ -108,6 +110,7 @@ class CameraCaptureManager(private val context: Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
suspend fun clip(paramsJson: String?): Payload =
|
suspend fun clip(paramsJson: String?): Payload =
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
ensureCameraPermission()
|
ensureCameraPermission()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package com.steipete.clawdis.node.node
|
package com.steipete.clawdis.node.node
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.os.Build
|
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import androidx.core.graphics.createBitmap
|
||||||
|
import androidx.core.graphics.scale
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -80,7 +81,7 @@ class CanvasController {
|
||||||
val scaled =
|
val scaled =
|
||||||
if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) {
|
if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) {
|
||||||
val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1)
|
val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1)
|
||||||
Bitmap.createScaledBitmap(bmp, maxWidth, h, true)
|
bmp.scale(maxWidth, h)
|
||||||
} else {
|
} else {
|
||||||
bmp
|
bmp
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +98,7 @@ class CanvasController {
|
||||||
val scaled =
|
val scaled =
|
||||||
if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) {
|
if (maxWidth != null && maxWidth > 0 && bmp.width > maxWidth) {
|
||||||
val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1)
|
val h = (bmp.height.toDouble() * (maxWidth.toDouble() / bmp.width.toDouble())).toInt().coerceAtLeast(1)
|
||||||
Bitmap.createScaledBitmap(bmp, maxWidth, h, true)
|
bmp.scale(maxWidth, h)
|
||||||
} else {
|
} else {
|
||||||
bmp
|
bmp
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +117,7 @@ class CanvasController {
|
||||||
suspendCancellableCoroutine { cont ->
|
suspendCancellableCoroutine { cont ->
|
||||||
val width = width.coerceAtLeast(1)
|
val width = width.coerceAtLeast(1)
|
||||||
val height = height.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
|
// WebView isn't supported by PixelCopy.request(...) directly; draw() is the most reliable
|
||||||
// cross-version snapshot for this lightweight "canvas" use-case.
|
// cross-version snapshot for this lightweight "canvas" use-case.
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background" />
|
<background android:drawable="@color/ic_launcher_background" />
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|
||||||
|
|
@ -2,5 +2,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background" />
|
<background android:drawable="@color/ic_launcher_background" />
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@mipmap/ic_launcher_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources>
|
||||||
<style name="Theme.ClawdisNode" parent="Theme.Material3.DayNight.NoActionBar">
|
<style name="Theme.ClawdisNode" parent="Theme.Material3.DayNight.NoActionBar">
|
||||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||||
<item name="android:windowLightStatusBar" tools:targetApi="m">false</item>
|
<item name="android:windowLightStatusBar">false</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<full-backup-content>
|
||||||
|
<include domain="file" path="." />
|
||||||
|
</full-backup-content>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<include domain="file" path="." />
|
||||||
|
</cloud-backup>
|
||||||
|
<device-transfer>
|
||||||
|
<include domain="file" path="." />
|
||||||
|
</device-transfer>
|
||||||
|
</data-extraction-rules>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<network-security-config>
|
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!-- This app is primarily used on a trusted tailnet; allow cleartext for IP-based endpoints too. -->
|
<!-- This app is primarily used on a trusted tailnet; allow cleartext for IP-based endpoints too. -->
|
||||||
<base-config cleartextTrafficPermitted="true" />
|
<base-config cleartextTrafficPermitted="true" tools:ignore="InsecureBaseConfiguration" />
|
||||||
<!-- Allow HTTP for tailnet/local dev endpoints (e.g. canvas/background web). -->
|
<!-- Allow HTTP for tailnet/local dev endpoints (e.g. canvas/background web). -->
|
||||||
<domain-config cleartextTrafficPermitted="true">
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
<domain includeSubdomains="true">clawdis.internal</domain>
|
<domain includeSubdomains="true">clawdis.internal</domain>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue