From ceee5f714d0f15effc4be50431374478cdd028e5 Mon Sep 17 00:00:00 2001 From: jeffrey-signal Date: Wed, 3 Jun 2026 07:25:06 -0400 Subject: [PATCH] Adjust RegV5 window insets so screens draw under system bars and handle display cutouts. --- .../registration/src/main/AndroidManifest.xml | 3 +- .../registration/sample/MainActivity.kt | 8 +-- .../registration/src/main/AndroidManifest.xml | 3 +- .../registration/RegistrationActivity.kt | 50 +++++++------------ .../screens/RegistrationScaffold.kt | 39 ++++++++++++--- .../screens/captcha/CaptchaScreen.kt | 4 ++ .../VerificationCodeScreen.kt | 7 ++- 7 files changed, 65 insertions(+), 49 deletions(-) diff --git a/demo/registration/src/main/AndroidManifest.xml b/demo/registration/src/main/AndroidManifest.xml index c2600d8731..ff24a08edb 100644 --- a/demo/registration/src/main/AndroidManifest.xml +++ b/demo/registration/src/main/AndroidManifest.xml @@ -22,7 +22,8 @@ + android:exported="true" + android:windowSoftInputMode="adjustResize"> diff --git a/demo/registration/src/main/java/org/signal/registration/sample/MainActivity.kt b/demo/registration/src/main/java/org/signal/registration/sample/MainActivity.kt index f85d57b18b..2fb6a67ac0 100644 --- a/demo/registration/src/main/java/org/signal/registration/sample/MainActivity.kt +++ b/demo/registration/src/main/java/org/signal/registration/sample/MainActivity.kt @@ -88,8 +88,8 @@ sealed interface SampleRoute : NavKey { */ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) enableEdgeToEdge() + super.onCreate(savedInstanceState) setContent { SignalTheme { @@ -108,11 +108,7 @@ class MainActivity : ComponentActivity() { fun AppScreen(registrationDependencies: RegistrationDependencies) { val backStack = rememberNavBackStack(SampleRoute.Main) - Box( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding(WindowInsets.safeDrawing) - ) { + Box(modifier = Modifier.fillMaxSize()) { SampleNavHost( backStack = backStack, registrationDependencies = registrationDependencies, diff --git a/feature/registration/src/main/AndroidManifest.xml b/feature/registration/src/main/AndroidManifest.xml index c4ff6886ba..1dd8f49b19 100644 --- a/feature/registration/src/main/AndroidManifest.xml +++ b/feature/registration/src/main/AndroidManifest.xml @@ -13,7 +13,8 @@ + android:theme="@android:style/Theme.Material.NoActionBar" + android:windowSoftInputMode="adjustResize" /> diff --git a/feature/registration/src/main/java/org/signal/registration/RegistrationActivity.kt b/feature/registration/src/main/java/org/signal/registration/RegistrationActivity.kt index b68c66ea71..cc1047166e 100644 --- a/feature/registration/src/main/java/org/signal/registration/RegistrationActivity.kt +++ b/feature/registration/src/main/java/org/signal/registration/RegistrationActivity.kt @@ -7,11 +7,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContract -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.Surface import androidx.compose.ui.Modifier import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -25,6 +21,13 @@ import org.signal.core.ui.compose.theme.SignalTheme */ class RegistrationActivity : ComponentActivity() { + companion object { + @JvmStatic + fun createIntent(context: Context): Intent { + return Intent(context, RegistrationActivity::class.java) + } + } + private val repository: RegistrationRepository by lazy { RegistrationRepository( context = this.application, @@ -36,44 +39,25 @@ class RegistrationActivity : ComponentActivity() { @OptIn(ExperimentalPermissionsApi::class) override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) enableEdgeToEdge() + super.onCreate(savedInstanceState) setContent { SignalTheme(incognitoKeyboardEnabled = false) { - Surface { - Box( - modifier = Modifier - .fillMaxSize() - .windowInsetsPadding(WindowInsets.safeDrawing) - ) { - RegistrationNavHost( - registrationRepository = repository, - modifier = Modifier.fillMaxSize(), - onRegistrationComplete = { - setResult(RESULT_OK) - finish() - } - ) - } + Surface(modifier = Modifier.fillMaxSize()) { + RegistrationNavHost( + registrationRepository = repository, + modifier = Modifier.fillMaxSize(), + onRegistrationComplete = { + setResult(RESULT_OK) + finish() + } + ) } } } } - companion object { - /** - * Creates an intent to launch the RegistrationActivity. - * - * @param context The context used to create the intent. - * @return An intent that can be used to start the RegistrationActivity. - */ - @JvmStatic - fun createIntent(context: Context): Intent { - return Intent(context, RegistrationActivity::class.java) - } - } - /** * Activity result contract for launching the registration flow. * diff --git a/feature/registration/src/main/java/org/signal/registration/screens/RegistrationScaffold.kt b/feature/registration/src/main/java/org/signal/registration/screens/RegistrationScaffold.kt index c6fecf4778..100ff46c83 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/RegistrationScaffold.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/RegistrationScaffold.kt @@ -7,14 +7,21 @@ package org.signal.registration.screens import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Surface @@ -160,9 +167,14 @@ object RegistrationScaffold { ) { Surface( modifier = modifier.fillMaxWidth(), - shadowElevation = if (isElevated) 8.dp else 0.dp, - content = content - ) + shadowElevation = if (isElevated) 8.dp else 0.dp + ) { + Box( + modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars) + ) { + content() + } + } } } @@ -176,7 +188,12 @@ fun RegistrationScaffold( topBar: (@Composable () -> Unit)? = null, footer: (@Composable () -> Unit)? = null ) { - SubcomposeLayout(modifier = modifier.imePadding()) { constraints -> + SubcomposeLayout( + modifier = modifier + .then(if (topBar == null) Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top)) else Modifier) + .then(if (footer == null) Modifier.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Bottom)) else Modifier) + .imePadding() + ) { constraints -> val footerPlaceables = footer?.let { subcompose("footer", it).map { m -> m.measure(constraints.copy(minWidth = 0, minHeight = 0)) } } ?: emptyList() @@ -215,7 +232,15 @@ fun OnePaneRegistrationScaffold( modifier = modifier.fillMaxSize(), topBar = topBar, footer = footer, - content = { content(params.panePadding(hasHeader = topBar != null)) } + content = { + Box( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)) + ) { + content(params.panePadding(hasHeader = topBar != null)) + } + } ) } @@ -238,7 +263,9 @@ fun TwoPaneRegistrationScaffold( content = { Row( horizontalArrangement = Arrangement.SpaceAround, - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)) ) { firstPane(params.firstPanePadding(hasHeader = topBar != null)) secondPane(params.secondPanePadding(hasHeader = topBar != null)) diff --git a/feature/registration/src/main/java/org/signal/registration/screens/captcha/CaptchaScreen.kt b/feature/registration/src/main/java/org/signal/registration/screens/captcha/CaptchaScreen.kt index 7f0aa551b6..9765f75bbc 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/captcha/CaptchaScreen.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/captcha/CaptchaScreen.kt @@ -11,10 +11,13 @@ import android.webkit.WebView import android.webkit.WebViewClient import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -48,6 +51,7 @@ fun CaptchaScreen( Column( modifier = modifier .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing) ) { Box( modifier = Modifier diff --git a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt index 258a5f0dd3..7c9d3fda1b 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -176,7 +177,8 @@ private fun OnePaneLayout( OnePaneRegistrationScaffold( modifier = Modifier .fillMaxSize() - .padding(innerPadding), + .padding(innerPadding) + .consumeWindowInsets(innerPadding), params = params, content = { paddingValues -> Column( @@ -237,7 +239,8 @@ private fun TwoPaneLayout( TwoPaneRegistrationScaffold( modifier = Modifier .fillMaxSize() - .padding(innerPadding), + .padding(innerPadding) + .consumeWindowInsets(innerPadding), params = params, firstPane = { paddingValues -> Column(