diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt index 52c966458b..a18cf30ce8 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ReactContext.kt @@ -2,6 +2,7 @@ package com.reactnativekeyboardcontroller.extensions import android.view.View import android.view.ViewGroup +import android.view.WindowManager import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.common.UIManagerType @@ -28,3 +29,12 @@ val ReactContext.content: ViewGroup? this.currentActivity?.window?.decorView?.rootView?.findViewById( androidx.appcompat.R.id.action_bar_root, ) + +val ReactContext.windowSoftInputMode: Int + get() = + this + .currentActivity + ?.window + ?.attributes + ?.softInputMode + ?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt index 8cf1ff5eba..007fb57675 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/extensions/View.kt @@ -4,9 +4,7 @@ import android.annotation.SuppressLint import android.graphics.Rect import android.os.Build import android.view.View -import androidx.core.graphics.Insets import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat import com.reactnativekeyboardcontroller.log.Logger /** @@ -61,41 +59,3 @@ val View.screenLocation get(): IntArray { return point } - -/** - * Safely replaces status bar insets so that when we edge-to-edge mode gets disabled/enabled - * the app content is not jumping/resizing a window. - * */ -@Suppress("DEPRECATION") -fun View.replaceStatusBarInsets( - insets: WindowInsetsCompat, - isStatusBarTranslucent: Boolean, - active: Boolean, -): WindowInsetsCompat { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - val sysBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - val navBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars()) - val ime = insets.getInsets(WindowInsetsCompat.Type.ime()) - val adjustedTop = if (isStatusBarTranslucent) 0 else sysBars.top - // pick bottom: use IME if present, otherwise nav bar bottom (respect translucency) - val bottomFromImeOrNav = if (ime.bottom > 0) ime.bottom else navBars.bottom - val adjustedInsets = - WindowInsetsCompat - .Builder(insets) - .setInsets( - WindowInsetsCompat.Type.systemBars(), - Insets.of(sysBars.left, adjustedTop, sysBars.right, if (active) sysBars.bottom else bottomFromImeOrNav), - ).build() - - return ViewCompat.onApplyWindowInsets(this, adjustedInsets) - } else { - val defaultInsets = ViewCompat.onApplyWindowInsets(this, insets) - - return defaultInsets.replaceSystemWindowInsets( - defaultInsets.systemWindowInsetLeft, - if (isStatusBarTranslucent) 0 else defaultInsets.systemWindowInsetTop, - defaultInsets.systemWindowInsetRight, - defaultInsets.systemWindowInsetBottom, - ) - } -} diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt index 489b181c06..fb27fffc22 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/modules/KeyboardControllerModuleImpl.kt @@ -3,7 +3,6 @@ package com.reactnativekeyboardcontroller.modules import android.content.Context import android.os.Build import android.view.View -import android.view.WindowManager import android.view.inputmethod.InputMethodManager import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.Promise @@ -12,6 +11,7 @@ import com.facebook.react.bridge.UiThreadUtil import com.reactnativekeyboardcontroller.extensions.dp import com.reactnativekeyboardcontroller.extensions.screenLocation import com.reactnativekeyboardcontroller.extensions.uiManager +import com.reactnativekeyboardcontroller.extensions.windowSoftInputMode import com.reactnativekeyboardcontroller.interactive.KeyboardAnimationController import com.reactnativekeyboardcontroller.traversal.FocusedInputHolder import com.reactnativekeyboardcontroller.traversal.ViewHierarchyNavigator @@ -21,7 +21,7 @@ class KeyboardControllerModuleImpl( ) { private val uiManager = mReactContext.uiManager private val controller = KeyboardAnimationController() - private val mDefaultMode: Int = getCurrentMode() + private val mDefaultMode: Int = mReactContext.windowSoftInputMode // region Module methods fun setInputMode(mode: Int) { @@ -108,19 +108,11 @@ class KeyboardControllerModuleImpl( // region Helpers private fun setSoftInputMode(mode: Int) { UiThreadUtil.runOnUiThread { - if (getCurrentMode() != mode) { + if (mReactContext.windowSoftInputMode != mode) { mReactContext.currentActivity?.window?.setSoftInputMode(mode) } } } - - private fun getCurrentMode(): Int = - mReactContext - .currentActivity - ?.window - ?.attributes - ?.softInputMode - ?: WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED // endregion // region Module constants diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt index 003890b434..504afb7a4b 100644 --- a/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt +++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt @@ -5,6 +5,7 @@ import android.content.res.Configuration import android.os.Handler import android.os.Looper import android.view.WindowManager +import android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE import android.widget.FrameLayout import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat @@ -14,14 +15,15 @@ import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.views.view.ReactViewGroup import com.reactnativekeyboardcontroller.extensions.content import com.reactnativekeyboardcontroller.extensions.removeSelf -import com.reactnativekeyboardcontroller.extensions.replaceStatusBarInsets import com.reactnativekeyboardcontroller.extensions.requestApplyInsetsWhenAttached import com.reactnativekeyboardcontroller.extensions.rootView +import com.reactnativekeyboardcontroller.extensions.windowSoftInputMode import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallback import com.reactnativekeyboardcontroller.listeners.KeyboardAnimationCallbackConfig import com.reactnativekeyboardcontroller.log.Logger import com.reactnativekeyboardcontroller.modal.ModalAttachedWatcher import java.lang.ref.WeakReference +import kotlin.math.max private val TAG = EdgeToEdgeReactViewGroup::class.qualifiedName @@ -44,7 +46,6 @@ class EdgeToEdgeReactViewGroup( private var isStatusBarTranslucent = false private var isNavigationBarTranslucent = false private var isPreservingEdgeToEdge = false - private var isEdgeToEdge = false var active: Boolean = false set(value) { field = value @@ -110,47 +111,43 @@ class EdgeToEdgeReactViewGroup( FrameLayout.LayoutParams.MATCH_PARENT, ) - val shouldApplyZeroPaddingTop = !active || this.isStatusBarTranslucent - val shouldApplyZeroPaddingBottom = !active || this.isNavigationBarTranslucent + val shouldApplyBottomPadding = + !active && reactContext.windowSoftInputMode == SOFT_INPUT_ADJUST_RESIZE && !isPreservingEdgeToEdge val navBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars()) val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) + val keyboardInsets = + if (!shouldApplyBottomPadding) 0 else insets.getInsets(WindowInsetsCompat.Type.ime()).bottom params.setMargins( navBarInsets.left, - if (shouldApplyZeroPaddingTop) { + if (this.isStatusBarTranslucent) { 0 } else { systemBarInsets.top }, navBarInsets.right, - if (shouldApplyZeroPaddingBottom) { - 0 + if (this.isNavigationBarTranslucent) { + keyboardInsets } else { - navBarInsets.bottom + max(navBarInsets.bottom, keyboardInsets) }, ) content?.layoutParams = params - v.replaceStatusBarInsets(insets, this.isStatusBarTranslucent, active) + ViewCompat.onApplyWindowInsets(v, insets) } } } fun setEdgeToEdge() { - val nextValue = active || isPreservingEdgeToEdge - - if (isEdgeToEdge != nextValue) { - isEdgeToEdge = nextValue - - reactContext.currentActivity?.let { - WindowCompat.setDecorFitsSystemWindows( - it.window, - !isEdgeToEdge, - ) - } - // unclear legacy flag if it was set earlier - reactContext.currentActivity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + reactContext.currentActivity?.let { + WindowCompat.setDecorFitsSystemWindows( + it.window, + false, + ) } + // unclear legacy flag if it was set earlier + reactContext.currentActivity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) } private fun setupKeyboardCallbacks() {