From 932094cc9db691dc65381b0bf0224905b80c108f Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 6 Jul 2025 10:50:35 -0500 Subject: [PATCH 1/3] Update to Android 34 SDK --- android-application/build.gradle.kts | 4 ++-- .../src/main/AndroidManifest.xml | 6 ++++- .../ack/android/capture/CaptureActivity.kt | 16 +++++++++---- .../service/BackgroundCaptureService.kt | 4 +++- .../android/symbol/AndroidSymbolFactory.kt | 2 +- aprs-android/build.gradle.kts | 2 +- .../ack/data/drivers/AfskDriver.kt | 18 +++++++++++--- .../ack/data/drivers/InternetDriver.kt | 14 +++++++++-- .../ack/data/drivers/TncDriver.kt | 24 +++++++++++++++++-- 9 files changed, 73 insertions(+), 17 deletions(-) diff --git a/android-application/build.gradle.kts b/android-application/build.gradle.kts index 55f22a4e..3fec3d40 100644 --- a/android-application/build.gradle.kts +++ b/android-application/build.gradle.kts @@ -15,11 +15,11 @@ if (useGoogleServices) { } android { - compileSdk = 34 + compileSdk = 35 namespace = "com.inkapplications.ack.android" defaultConfig { minSdk = 21 - targetSdk = 34 + targetSdk = 35 multiDexEnabled = true buildConfigField("boolean", "USE_GOOGLE_SERVICES", useGoogleServices.toString()) buildConfigField("String", "COMMIT", optionalStringProperty("commit").buildQuote()) diff --git a/android-application/src/main/AndroidManifest.xml b/android-application/src/main/AndroidManifest.xml index 12fdefbd..5717fedb 100644 --- a/android-application/src/main/AndroidManifest.xml +++ b/android-application/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ + + + @@ -33,7 +36,8 @@ - + + { + startConnectTncActivity(backgroundCaptureServiceIntent) + } + DriverSelection.Audio -> { + startForegroundService(backgroundCaptureAudioServiceIntent) + } + else -> { + startForegroundService(backgroundCaptureServiceIntent) + } } } } diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt index 3b913465..fe04f560 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/capture/service/BackgroundCaptureService.kt @@ -14,7 +14,7 @@ import javax.inject.Inject * Service that runs in the background to collect and transmit packets. */ @AndroidEntryPoint -class BackgroundCaptureService: Service() { +open class BackgroundCaptureService: Service() { private lateinit var runScope: CoroutineScope @Inject @@ -51,3 +51,5 @@ class BackgroundCaptureService: Service() { super.onDestroy() } } + +class BackgroundCaptureServiceAudio: BackgroundCaptureService() diff --git a/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt b/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt index 60de487d..76a5a0eb 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/symbol/AndroidSymbolFactory.kt @@ -37,7 +37,7 @@ class AndroidSymbolFactory @Inject constructor( } private fun Bitmap.withOverlay(other: Bitmap): Bitmap { - val bmOverlay = Bitmap.createBitmap(width, height, config) + val bmOverlay = Bitmap.createBitmap(width, height, config ?: Bitmap.Config.ARGB_8888) val canvas = Canvas(bmOverlay) canvas.drawBitmap(this, Matrix(), null) canvas.drawBitmap(other, 0f, 0f, null) diff --git a/aprs-android/build.gradle.kts b/aprs-android/build.gradle.kts index 59e952ef..f20697d3 100644 --- a/aprs-android/build.gradle.kts +++ b/aprs-android/build.gradle.kts @@ -15,7 +15,7 @@ sqldelight { android { namespace = "com.inkapplications.ack.data" - compileSdk = 33 + compileSdk = 34 ndkVersion = "21.3.6528147" defaultConfig { diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt index 3780b28c..cba97789 100644 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt +++ b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/AfskDriver.kt @@ -35,12 +35,24 @@ class AfskDriver internal constructor( } override val incoming = MutableSharedFlow() override val receivePermissions: Set = when { -// Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU - Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> setOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.POST_NOTIFICATIONS) + Build.VERSION.SDK_INT >= 34 -> setOf( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.FOREGROUND_SERVICE_MICROPHONE, + // TODO: This could be simplified/removed if we create separate services for transmit and receive. + // Leaving for now, since all the other drivers require it anyway. + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + Manifest.permission.POST_NOTIFICATIONS, + ) + Build.VERSION.SDK_INT >= 33 -> setOf( + Manifest.permission.RECORD_AUDIO, + Manifest.permission.POST_NOTIFICATIONS, + ) else -> setOf(Manifest.permission.RECORD_AUDIO) } override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> setOf(Manifest.permission.POST_NOTIFICATIONS) + Build.VERSION.SDK_INT >= 33 -> setOf( + Manifest.permission.POST_NOTIFICATIONS + ) else -> emptySet() } override val volume = audioProcessor.volume diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt index 4afb0b3f..579a6857 100644 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt +++ b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/InternetDriver.kt @@ -32,11 +32,21 @@ class InternetDriver internal constructor( override val connectionState: Flow = clientConnectionState override val incoming = MutableSharedFlow() override val receivePermissions: Set = when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> setOf(Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.ACCESS_FINE_LOCATION) + Build.VERSION.SDK_INT >= 34 -> setOf( + Manifest.permission.POST_NOTIFICATIONS, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + ) + Build.VERSION.SDK_INT >= 33 -> setOf( + Manifest.permission.POST_NOTIFICATIONS, + Manifest.permission.ACCESS_FINE_LOCATION, + ) else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) } override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> setOf(Manifest.permission.POST_NOTIFICATIONS) + Build.VERSION.SDK_INT >= 33 -> setOf( + Manifest.permission.POST_NOTIFICATIONS, + ) else -> emptySet() } private val transmitQueue = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) diff --git a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt index 585296c7..83836ca8 100644 --- a/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt +++ b/aprs-android/src/main/java/com/inkapplications/ack/data/drivers/TncDriver.kt @@ -49,11 +49,31 @@ class TncDriver internal constructor( } } override val receivePermissions: Set = when { - Build.VERSION.SDK_INT > Build.VERSION_CODES.S -> setOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN) + Build.VERSION.SDK_INT >= 34 -> setOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN, + ) + Build.VERSION.SDK_INT > 31 -> setOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN, + ) else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) } override val transmitPermissions: Set = when { - Build.VERSION.SDK_INT > Build.VERSION_CODES.S -> setOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN) + Build.VERSION.SDK_INT >= 34 -> setOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.FOREGROUND_SERVICE_LOCATION, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN + ) + Build.VERSION.SDK_INT > 31 -> setOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN + ) else -> setOf(Manifest.permission.ACCESS_FINE_LOCATION) } private val outputStream = MutableStateFlow(null) From 6bc80b594ed338ff92770c499b0f082b700f10d7 Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 6 Jul 2025 11:35:05 -0500 Subject: [PATCH 2/3] Quick fix for background location requirements It seems we need background permissions for the foreground service to run on newer versions, even when the app itself is still in the foreground. Would like a more elegant solution and dialog here, but this gets the point across for now. --- .../ack/android/capture/CaptureActivity.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt index fe39eb84..cba216e5 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt @@ -2,7 +2,12 @@ package com.inkapplications.ack.android.capture import android.Manifest import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.provider.Settings import androidx.activity.compose.setContent +import androidx.appcompat.app.AlertDialog import androidx.compose.runtime.collectAsState import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope @@ -125,6 +130,26 @@ class CaptureActivity: ExtendedActivity(), CaptureNavController, LogIndexControl override fun onConnectClick() { Kimchi.trackEvent("capture_connect") + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + val hasBackgroundLocation = checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED + + if (!hasBackgroundLocation) { + AlertDialog.Builder(this) + .setTitle("Background Location Permission Required") + .setMessage("To capture data in the background, this app needs access to your location even when the app is closed.\n\nPlease grant \"Allow all the time\" location permission in the application settings.") + .setPositiveButton("Open Settings") { _, _ -> + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", packageName, null) + } + startActivity(intent) + } + .setNegativeButton("Cancel", null) + .show() + return + } + } + lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.CREATED) { permissionGate.withPermissions(*captureEvents.getDriverConnectPermissions().toTypedArray()) { From 5083764c126b6abc2f684a130fcb2d586ba98b03 Mon Sep 17 00:00:00 2001 From: Renee Vandervelde Date: Sun, 6 Jul 2025 12:31:11 -0500 Subject: [PATCH 3/3] Handle window insets manually --- .../ack/android/capture/CaptureActivity.kt | 1 + .../ack/android/capture/CaptureScreen.kt | 6 ++- .../android/log/details/LogDetailsScreen.kt | 46 +++++++++++++------ .../ack/android/map/MapScreen.kt | 11 +++-- .../android/onboard/UsageAgreementPrompt.kt | 7 ++- .../ack/android/settings/SettingsScreen.kt | 8 +++- .../android/settings/license/LicensePrompt.kt | 7 ++- .../ack/android/station/StationScreen.kt | 46 +++++++++++++------ .../ack/android/tnc/ConnectTncScreen.kt | 4 ++ 9 files changed, 97 insertions(+), 39 deletions(-) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt index cba216e5..264572ae 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureActivity.kt @@ -9,6 +9,7 @@ import android.provider.Settings import androidx.activity.compose.setContent import androidx.appcompat.app.AlertDialog import androidx.compose.runtime.collectAsState +import androidx.core.view.WindowCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle diff --git a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt index 4a3939c9..5962bd38 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/capture/CaptureScreen.kt @@ -62,6 +62,7 @@ fun CaptureScreen( ) { Column { Scaffold( + modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars), bottomBar = { CaptureBottomBar(navController) }, floatingActionButton = { CaptureSettingsFab(settingsSheetState) }, isFloatingActionButtonDocked = true, @@ -197,7 +198,10 @@ private fun CaptureSettingsSheet( controlPanelState: ControlPanelState, captureController: CaptureNavController, settingsSheetState: BottomSheetScaffoldState, -) = Column(horizontalAlignment = Alignment.CenterHorizontally) { +) = Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars), +) { val scope = rememberCoroutineScope() BackHandler(enabled = settingsSheetState.bottomSheetState.isExpanded) { scope.launch { settingsSheetState.bottomSheetState.collapse() } diff --git a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt index e73af9a4..3bcf3304 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/log/details/LogDetailsScreen.kt @@ -55,13 +55,21 @@ private fun Details( interactive = false, modifier = Modifier.aspectRatio(16f / 9f), ) - IconButton( - onClick = controller::onBackPressed + Box( + modifier = Modifier + .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) ) { - Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) + IconButton( + onClick = controller::onBackPressed + ) { + Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) + } } } - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = AckTheme.spacing.gutter)) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(top = AckTheme.spacing.gutter) + ) { Text( viewState.name, style = AckTheme.typography.h1, @@ -78,11 +86,15 @@ private fun Details( } } else { Box( - Modifier.padding( - start = AckTheme.spacing.gutter, - top = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ) + Modifier + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + ) + .padding( + start = AckTheme.spacing.gutter, + top = AckTheme.spacing.gutter, + end = AckTheme.spacing.gutter, + ) ) { NavigationRow( title = { @@ -104,12 +116,16 @@ private fun Details( } } Column( - modifier = Modifier.padding( - top = AckTheme.spacing.content, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.gutter, - ), + modifier = Modifier + .padding( + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ) + .padding( + top = AckTheme.spacing.content, + start = AckTheme.spacing.gutter, + end = AckTheme.spacing.gutter, + bottom = AckTheme.spacing.gutter, + ), ) { IconRow( icon = viewState.receiveIcon, diff --git a/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt index e0ca4804..edde0b9b 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/map/MapScreen.kt @@ -1,9 +1,6 @@ package com.inkapplications.ack.android.map -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.material.FloatingActionButton import androidx.compose.material.Icon import androidx.compose.material.contentColorFor @@ -40,7 +37,11 @@ fun MapScreen( ) val logState = state.selectedItem if (state.selectedItemVisible && logState != null) { - Row (modifier = Modifier.padding(top = AckTheme.spacing.gutter)) { + Row ( + modifier = Modifier + .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) + .padding(top = AckTheme.spacing.gutter) + ) { AprsLogItem( log = logState, onClick = onLogItemClick, diff --git a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt index 0d631e52..dccef758 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/onboard/UsageAgreementPrompt.kt @@ -18,7 +18,12 @@ fun UsageAgreementPrompt( controller: UserAgreementController, ) { Column( - modifier = Modifier.padding(AckTheme.spacing.gutter) + modifier = Modifier + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ) + .padding(AckTheme.spacing.gutter) .fillMaxHeight() .verticalScroll(rememberScrollState()), ) { diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt index 8539dbf5..4e3bcf7c 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/settings/SettingsScreen.kt @@ -27,7 +27,13 @@ fun SettingsScreen( controller: SettingsController, ) = AckScreen { Column( - modifier = Modifier.verticalScroll(rememberScrollState()), + modifier = Modifier + .fillMaxSize() + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ) + .verticalScroll(rememberScrollState()), ) { NavigationRow( title = stringResource(R.string.settings_title), diff --git a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt index 130f3427..cb1c3b8a 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/settings/license/LicensePrompt.kt @@ -20,7 +20,12 @@ fun LicensePromptScreen( onContinue: (LicensePromptFieldValues) -> Unit, ) = AckScreen { Column ( - modifier = Modifier.padding(AckTheme.spacing.gutter), + modifier = Modifier + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ) + .padding(AckTheme.spacing.gutter), ) { Text( "License Info", diff --git a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt index 72c37b14..69fac28b 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/station/StationScreen.kt @@ -50,13 +50,21 @@ private fun StationDetails( interactive = false, modifier = Modifier.aspectRatio(16f / 9f), ) - IconButton( - onClick = controller::onBackPressed + Box( + modifier = Modifier + .padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()) ) { - Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) + IconButton( + onClick = controller::onBackPressed + ) { + Icon(Icons.Default.ArrowBack, stringResource(R.string.navigate_up)) + } } } - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = AckTheme.spacing.gutter)) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(top = AckTheme.spacing.gutter) + ) { Text( viewState.insight.name, style = AckTheme.typography.h1, @@ -69,11 +77,15 @@ private fun StationDetails( } } else { Box( - Modifier.padding( - start = AckTheme.spacing.gutter, - top = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - ) + Modifier + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + ) + .padding( + start = AckTheme.spacing.gutter, + top = AckTheme.spacing.gutter, + end = AckTheme.spacing.gutter, + ) ) { NavigationRow( title = { @@ -91,12 +103,16 @@ private fun StationDetails( } } Column( - modifier = Modifier.padding( - top = AckTheme.spacing.content, - start = AckTheme.spacing.gutter, - end = AckTheme.spacing.gutter, - bottom = AckTheme.spacing.gutter, - ), + modifier = Modifier + .padding( + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ) + .padding( + top = AckTheme.spacing.content, + start = AckTheme.spacing.gutter, + end = AckTheme.spacing.gutter, + bottom = AckTheme.spacing.gutter, + ), ) { if (viewState.insight.temperature != null) { IconRow(Icons.Default.WbSunny, viewState.insight.temperature) diff --git a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt index e774c7bf..cbd5acc7 100644 --- a/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt +++ b/android-application/src/main/java/com/inkapplications/ack/android/tnc/ConnectTncScreen.kt @@ -33,6 +33,10 @@ fun DeviceList( is ConnectTncState.Discovering.Empty -> { Box( modifier = Modifier.fillMaxSize() + .padding( + top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding(), + bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() + ), ) { DeviceHeader(controller::onCloseClick) Column(