Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/android-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
e2e-test:
name: ⚙️ Automated test cases
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 90
env:
WORKING_DIRECTORY: example
concurrency:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ 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

/**
Expand Down Expand Up @@ -58,3 +61,41 @@ 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,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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.listeners.KeyboardAnimationCallback
Expand Down Expand Up @@ -130,14 +131,7 @@ class EdgeToEdgeReactViewGroup(
)
content?.layoutParams = params

val defaultInsets = ViewCompat.onApplyWindowInsets(v, insets)

defaultInsets.replaceSystemWindowInsets(
defaultInsets.systemWindowInsetLeft,
if (this.isStatusBarTranslucent) 0 else defaultInsets.systemWindowInsetTop,
defaultInsets.systemWindowInsetRight,
defaultInsets.systemWindowInsetBottom,
)
v.replaceStatusBarInsets(insets, this.isStatusBarTranslucent, active)
}
}
}
Expand Down