Skip to content

KeyboardProvider overrides system insets on Android potentially affecting native views #1013

@leonardorib

Description

@leonardorib

Describe the bug
When the KeyboardProvider is rendered and statusBarTranslucent is true, which is always the case for edge-to-edge, the top system inset is overriden, which can impact Android native views relying on it.

Code snippet
See the repo for reproducing

Repo for reproducing
https://github.com/leonardorib/keyboardcontroller-insets-issue-repro

I added a README in there with some context and a video.

To Reproduce
Steps to reproduce the behavior:

  1. On Android, make sure you are on edge-to-edge (e.g install react-native-edge-to-edge) or has statusBarTranslucent always true.
  2. Render a native android view that relies on the top system inset from the statusbar
  3. Render the KeyboardProvider
  4. The top inset is now 0

Expected behavior
Native views that rely on system insets should ideally still be able to rely on those values.

Smartphone (please complete the following information):

  • Desktop OS: macOS 15.5
  • Device: Samsung Galaxy M14 (physical device) and Pixel 8 emulator
  • OS: 14 and 15
  • RN version: 0.79.5
  • RN architecture: new
  • JS engine: Hermes
  • Library version: 1.17.5

Additional context
I came across this issue when integrating with RevenueCat paywalls. The idea is: you create a Paywall in their dashboard, calls presentPaywallor renders the PurchasesUI.Paywall component and the paywall you built will be rendered in the app.

I noticed that the paywall close button was colliding with the statusbar on Android. It was not being able to account for the statusbar size. At first I thought it was an issue with their SDK, but after I removed the KeyboardProvider from react-native-keyboard-controller the issue was solved.

After some investigation I noticed that react-native-keyboard-controller replaces the system window insets on Android:

defaultInsets.replaceSystemWindowInsets(
defaultInsets.systemWindowInsetLeft,
if (this.isStatusBarTranslucent) 0 else defaultInsets.systemWindowInsetTop,
defaultInsets.systemWindowInsetRight,
defaultInsets.systemWindowInsetBottom,
)

When I replaced if (this.isStatusBarTranslucent) 0 else defaultInsets.systemWindowInsetTop with simply defaultInsets.systemWindowInsetTop, therefore keeping it all as default, I didn't get the issue anymore.

How Revenuecat Paywall relies on it

I noticed they are relying on it for example here:

https://github.com/RevenueCat/purchases-android/blob/daa30fdb874145878e40ffea154351da4dcbc4ea/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/CloseButton.kt#L23-L29

https://github.com/RevenueCat/purchases-android/blob/daa30fdb874145878e40ffea154351da4dcbc4ea/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/InsetSpacers.kt#L13-L19

Notes

I am not sure how much is that system insets replacement really needed for the library purposes, which is why I didn't open a PR removing it.

Screenshots

From my repo with the reproducer:

keyboard-controller-insets-issue-demo.webm

Metadata

Metadata

Assignees

Labels

🐛 bugSomething isn't working🔥 AttentionAn issue, that requires attention (disturbs many users/has many reactions)🤖 androidAndroid specific

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions