You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On at least one real device (details below), SystemBars's "passthrough" keyboard-resize path (shouldPassthroughInsets = webViewMajorVersion >= 140 && hasViewportCover, in SystemBars.java) resizes the WebView by a value that's consistently ~130px short of the keyboard's real on-screen top edge, leaving a flat unpainted strip between the page content and the keyboard.
More importantly: this isn't fixable from app code today. I traced it all the way through and confirmed that in passthrough mode, View.setPadding() on the DecorView (what SystemBars.applyInsets() calls) has zero effect on the WebView's actual rendered size — window.innerHeight never changes no matter what padding value is applied. I also tried rewriting the ime() portion of the WindowInsetsCompat returned from the OnApplyWindowInsetsListener/WindowInsetsAnimationCompat.Callback — also zero effect. Chromium appears to resize the WebView through a separate internal channel that isn't influenced by anything SystemBars (or any app code reachable via public Capacitor/AndroidX APIs) returns or sets.
Android System WebView: 152.0.7977.87 (well past the WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144 gate in SystemBars.java, so the code assumes this version reports IME insets correctly — on this device it doesn't, for the resize, even though the reported inset value itself is actually correct — see below)
Keyboard.resizeOnFullScreen: not set (omitted per the plugin's own warning)
insetsHandling: default (css)
Steps to reproduce
Any Capacitor Android app with the default viewport meta tag (viewport-fit=cover) and an <input>/focusable field.
Focus the field to open the soft keyboard.
Compare where the page content visually ends vs. where the keyboard visually starts.
Expected
The WebView content area should end exactly where the keyboard begins (or vice versa when it closes).
Actual
A ~130px gap (physical pixels, this device) appears between the content and the keyboard, filled with a flat, unpainted color — not the page background, not the keyboard's own background, a third "nothing was drawn here yet" color.
Root-cause investigation (with numbers)
I have real-device measurements, not guesses:
adb shell dumpsys window windows → the IME window's real touchable region: SkRegion((0,1569,1080,2270)) — keyboard top edge is physically at y=1569.
The WebView's own reported frame (via chrome://inspect / CDP json/list, "screenY":104,"height":1335) → WebView ends at y=1439 (104+1335).
Gap: 130px, matching this device's navigation-bar height almost exactly (navBarHeight: 130 also shows up in unrelated Gboard logcat lines on this device, for what that's worth — possibly coincidental, possibly not).
I patched SystemBars.java (via pnpm patch) to log both the raw insets.getInsets(WindowInsetsCompat.Type.ime()).bottom from the callback parameter and a fresh ViewCompat.getRootWindowInsets(v).getInsets(...) re-query. Once the keyboard is fully settled, both report the correct value (831px, which is exactly 2400-1569). So the inset math this plugin does is not wrong — Android is handing it the right number.
Despite that correct number being computed and passed to v.setPadding(0,0,0,831), and despite rewriting the ime() type of the returned WindowInsetsCompat to carry that same corrected Insets, window.innerHeight (checked live via CDP Runtime.evaluate) stayed at the exact same wrong value throughout — the same one it had before any of these patches, with resizeOnFullScreen/safe-area conflicts/etc. all ruled out first.
The one thing that did change the WebView's actual resize amount: stripping viewport-fit=cover from the meta viewport tag, which flips shouldPassthroughInsets to false and moves SystemBars into the other branch (v.setPadding(systemBarsInsets.left, top, right, keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom), explicit Insets.of(0,0,0,0) for systemBars/cutout, env(safe-area-inset-*) no longer populated, custom-property injection via injectSafeAreaCSS becomes the only source of truth). In that branch, the manual setPadding() call does control the WebView's visible size correctly.
So: in passthrough mode, the resize is entirely internal to Chromium/WebView and not influenceable through WindowInsetsCompat/View.setPadding() from application/plugin code — at least not through any API surface I could find. Whatever Chromium's own internal handling is doing for viewport-fit=cover + IME on this WebView build, it's arriving at a different (and wrong, on this device) number than what WindowInsetsCompat.Type.ime() reports to the app.
What I'd ask for
If this is a known Chromium bug with an upstream tracking issue, a pointer would be very helpful — I couldn't find one specific to this "reported inset ≠ actual resize" mismatch (as opposed to the reported-inset-value-itself-being-wrong bugs like 40699457/457682720 already referenced in this file).
A config escape hatch to force the non-passthrough (manual setPadding) branch on Android, without losing the env(safe-area-inset-*)/native-CSS-env behavior for status bar and cutout (i.e., decoupling the IME-resize strategy from the systemBars/cutout strategy, since today shouldPassthroughInsets controls both together) would let apps work around this per-device without having to fully drop viewport-fit=cover (and re-plumb every env(safe-area-inset-*) usage to var(--safe-area-inset-*) instead, which is what I ended up doing).
At minimum, documenting that View.setPadding()/returned-inset-rewriting has no effect in passthrough mode would save the next person a few hours of patching and measuring to (re)discover this.
Happy to share the pnpm patch diffs I used for the logging/measurement if useful, and the exact CDP script I used to watch window.innerHeight live if that helps someone else's investigation.
Description
On at least one real device (details below),
SystemBars's "passthrough" keyboard-resize path (shouldPassthroughInsets = webViewMajorVersion >= 140 && hasViewportCover, inSystemBars.java) resizes the WebView by a value that's consistently ~130px short of the keyboard's real on-screen top edge, leaving a flat unpainted strip between the page content and the keyboard.More importantly: this isn't fixable from app code today. I traced it all the way through and confirmed that in passthrough mode,
View.setPadding()on the DecorView (whatSystemBars.applyInsets()calls) has zero effect on the WebView's actual rendered size —window.innerHeightnever changes no matter what padding value is applied. I also tried rewriting theime()portion of theWindowInsetsCompatreturned from theOnApplyWindowInsetsListener/WindowInsetsAnimationCompat.Callback— also zero effect. Chromium appears to resize the WebView through a separate internal channel that isn't influenced by anythingSystemBars(or any app code reachable via public Capacitor/AndroidX APIs) returns or sets.Environment
@capacitor/core/@capacitor/android: 8.5.2 (also reproduced on 8.5.0, before upgrading in an attempt to pick up fix: resolve issues with safe area / systembars plugin #8535)M2101K9AG), Android 13, MIUI152.0.7977.87(well past theWEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144gate inSystemBars.java, so the code assumes this version reports IME insets correctly — on this device it doesn't, for the resize, even though the reported inset value itself is actually correct — see below)Keyboard.resizeOnFullScreen: not set (omitted per the plugin's own warning)insetsHandling: default (css)Steps to reproduce
viewport-fit=cover) and an<input>/focusable field.Expected
The WebView content area should end exactly where the keyboard begins (or vice versa when it closes).
Actual
A ~130px gap (physical pixels, this device) appears between the content and the keyboard, filled with a flat, unpainted color — not the page background, not the keyboard's own background, a third "nothing was drawn here yet" color.
Root-cause investigation (with numbers)
I have real-device measurements, not guesses:
adb shell dumpsys window windows→ the IME window's real touchable region:SkRegion((0,1569,1080,2270))— keyboard top edge is physically at y=1569.chrome://inspect/ CDPjson/list,"screenY":104,"height":1335) → WebView ends at y=1439 (104+1335).navBarHeight: 130also shows up in unrelated Gboard logcat lines on this device, for what that's worth — possibly coincidental, possibly not).SystemBars.java(viapnpm patch) to log both the rawinsets.getInsets(WindowInsetsCompat.Type.ime()).bottomfrom the callback parameter and a freshViewCompat.getRootWindowInsets(v).getInsets(...)re-query. Once the keyboard is fully settled, both report the correct value (831px, which is exactly2400-1569). So the inset math this plugin does is not wrong — Android is handing it the right number.v.setPadding(0,0,0,831), and despite rewriting theime()type of the returnedWindowInsetsCompatto carry that same correctedInsets,window.innerHeight(checked live via CDPRuntime.evaluate) stayed at the exact same wrong value throughout — the same one it had before any of these patches, withresizeOnFullScreen/safe-areaconflicts/etc. all ruled out first.viewport-fit=coverfrom the meta viewport tag, which flipsshouldPassthroughInsetstofalseand movesSystemBarsinto the other branch (v.setPadding(systemBarsInsets.left, top, right, keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom), explicitInsets.of(0,0,0,0)for systemBars/cutout,env(safe-area-inset-*)no longer populated, custom-property injection viainjectSafeAreaCSSbecomes the only source of truth). In that branch, the manualsetPadding()call does control the WebView's visible size correctly.So: in passthrough mode, the resize is entirely internal to Chromium/WebView and not influenceable through
WindowInsetsCompat/View.setPadding()from application/plugin code — at least not through any API surface I could find. Whatever Chromium's own internal handling is doing forviewport-fit=cover+ IME on this WebView build, it's arriving at a different (and wrong, on this device) number than whatWindowInsetsCompat.Type.ime()reports to the app.What I'd ask for
40699457/457682720already referenced in this file).setPadding) branch on Android, without losing theenv(safe-area-inset-*)/native-CSS-env behavior for status bar and cutout (i.e., decoupling the IME-resize strategy from the systemBars/cutout strategy, since todayshouldPassthroughInsetscontrols both together) would let apps work around this per-device without having to fully dropviewport-fit=cover(and re-plumb everyenv(safe-area-inset-*)usage tovar(--safe-area-inset-*)instead, which is what I ended up doing).View.setPadding()/returned-inset-rewriting has no effect in passthrough mode would save the next person a few hours of patching and measuring to (re)discover this.Happy to share the
pnpm patchdiffs I used for the logging/measurement if useful, and the exact CDP script I used to watchwindow.innerHeightlive if that helps someone else's investigation.