Skip to content

fix(android): reset WebView height when keyboard hides without animation#60

Open
hiebj wants to merge 2 commits intoionic-team:mainfrom
hiebj:fix/android-resize-on-app-switch
Open

fix(android): reset WebView height when keyboard hides without animation#60
hiebj wants to merge 2 commits intoionic-team:mainfrom
hiebj:fix/android-resize-on-app-switch

Conversation

@hiebj
Copy link
Copy Markdown

@hiebj hiebj commented Mar 20, 2026

Description

Two fixes for Keyboard.java:

1. Reset WebView height when keyboard hides without animation (commit 1)

The setOnApplyWindowInsetsListener only calls possiblyResizeChildOfContent(true) when the keyboard is showing, but never calls possiblyResizeChildOfContent(false) to reset. This means the WebView height reset relies entirely on WindowInsetsAnimationCompat.Callback.onStart(), which requires an animation to fire.

This fix passes the actual showingKeyboard state to possiblyResizeChildOfContent() so the insets listener handles both show and hide, matching the behavior already present in onStart().

The change is safe because possiblyResizeChildOfContent is idempotent — it checks usableHeightPrevious != usableHeightNow before doing any work, so redundant calls during normal keyboard animations are no-ops.

2. Guard against null WindowInsets during teardown (commit 2)

ViewCompat.getRootWindowInsets() can return null when the root view is being detached (e.g. during activity destruction). All three call sites in the insets listener and animation callbacks now null-check before calling isVisible(), preventing a NullPointerException.

Context

Fixes #30, fixes #51

When switching from an app with the keyboard open (e.g. Messages) back to a Capacitor app, the WebView remains resized as if the keyboard were open. The keyboard area appears greyed out even though no keyboard is visible.

Root cause: During app switching, Android dismisses the keyboard without an animation. The setOnApplyWindowInsetsListener fires and detects showingKeyboard = true (briefly, from the previous app's IME state), calling possiblyResizeChildOfContent(true) to shrink the WebView. The keyboard then closes instantly (no focused input in the destination app), but because there's no animation, WindowInsetsAnimationCompat.Callback.onStart() never fires, and possiblyResizeChildOfContent(false) is never called to reset the height.

This was introduced in #40, which added the setOnApplyWindowInsetsListener but only handled the show path.

Also related to #8 (same symptom reported on iOS with swipe gestures).

Type of changes

  • Fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Refactor (cosmetic changes)
  • Breaking change (change that would cause existing functionality to not work as expected)

Platforms affected

  • Android
  • iOS
  • Web

Tests

Tested on Android emulator (Pixel 9, API 35):

  1. Open a Capacitor app with resizeOnFullScreen: true
  2. Switch to Messages, type something (keyboard visible)
  3. Switch back to the Capacitor app
  4. Before fix: WebView stays shrunk, grey area at bottom where keyboard was
  5. After fix: WebView correctly fills the full screen

Also verified normal keyboard behavior:

  • Tap an input → keyboard opens → WebView resizes correctly
  • Dismiss keyboard → WebView restores to full height
  • Switch between inputs → resize adjusts properly

Repro app from #30: https://github.com/irshadshalu/capacitor-keyboard-bug-sample

The setOnApplyWindowInsetsListener only called possiblyResizeChildOfContent(true)
when the keyboard was showing, but never called possiblyResizeChildOfContent(false)
to reset. This meant the WebView height reset relied entirely on
WindowInsetsAnimationCompat.Callback.onStart(), which requires an animation.

When switching from an app with the keyboard open back to a Capacitor app, Android
dismisses the keyboard without an animation. The insets listener detected the
keyboard as visible (briefly, from the previous app's IME state) and shrunk the
WebView, but the subsequent keyboard dismissal never triggered a reset because
no animation fired.

This fix passes the actual showingKeyboard state to possiblyResizeChildOfContent()
so the insets listener handles both show and hide, matching the behavior already
present in the animation callback's onStart().

Fixes ionic-team#30
ViewCompat.getRootWindowInsets() can return null when the root view is
being detached (e.g. during activity destruction). All three call sites
in the insets listener and animation callbacks now null-check before
calling isVisible(), preventing a NullPointerException.

Fixes ionic-team#51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant