From 19bb4f6bad73d556d760b994a3f4dfbd7622bfd1 Mon Sep 17 00:00:00 2001 From: weishu Date: Tue, 18 Aug 2026 21:37:50 +0800 Subject: [PATCH] fix(android): stop the AppCompat legacy IME resize doubling the keyboard inset With the default soft-input mode the AppCompat subdecor also resizes the window for the IME, stacking a keyboard-sized gap on top of imePadding (device-observed on the chat composer). SOFT_INPUT_ADJUST_NOTHING on API 30+ leaves Compose as the single keyboard-inset owner; 26-29 keep adjustResize because the ime() inset backport depends on it. --- .../main/kotlin/app/hapi/companion/MainActivity.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/android/app/src/main/kotlin/app/hapi/companion/MainActivity.kt b/android/app/src/main/kotlin/app/hapi/companion/MainActivity.kt index 4ca8b73f..cf4e5f46 100644 --- a/android/app/src/main/kotlin/app/hapi/companion/MainActivity.kt +++ b/android/app/src/main/kotlin/app/hapi/companion/MainActivity.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.view.WindowManager import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity @@ -53,6 +54,17 @@ class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() + if (Build.VERSION.SDK_INT >= 30) { + // Compose's imePadding is the single keyboard-inset owner. With the + // default adjust mode, the AppCompat subdecor ALSO resizes the + // window for the IME (device-observed: a keyboard-sized gap above + // the keyboard). ADJUST_NOTHING kills the legacy resize; IME + // insets are always delivered on 30+ regardless of soft-input + // mode. On 26–29 the ime() backport requires adjustResize, so + // those keep the default (and tolerate the legacy behavior). + @Suppress("DEPRECATION") + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) + } if (savedInstanceState == null) { // Only a fresh launch consumes the launching intent — after a // config change / process restore the same (already-consumed)