Quick start
Install platform-tools, turn on USB debugging, plug the phone in:
# Linux / macOS / Git Bash / WSL
git clone https://github.com/IRDcode/hyperos-keyboard-gap-fix.git
cd hyperos-keyboard-gap-fix && chmod +x fix-keyboard-gap.sh
./fix-keyboard-gap.sh # read-only: are you even affected?
./fix-keyboard-gap.sh apply
./fix-keyboard-gap.sh verify
# Windows PowerShell
.\fix-keyboard-gap.ps1
.\fix-keyboard-gap.ps1 -Action apply
.\fix-keyboard-gap.ps1 -Action verify
Or just the one line, if you already know what you are doing:
adb shell pm uninstall --user 0 com.android.systemui.gesture.line.overlay
Then finish on the phone — do not skip this. HyperOS drops to 3-button navigation the moment the overlay goes away. Open Settings → Home screen → System navigation, pick Gestures again, and switch Hide full screen indicator ON. Gestures come back; the gap does not.
No reboot needed. If one particular keyboard still shows the gap, force-stop that app once so it re-measures its window.
Is this your bug?
- Black bar or strip under the keyboard, appeared after the HyperOS 3 update
- Keyboard floats instead of sitting flush at the bottom edge
- An extra row containing only a ⌄ arrow under Gboard or SwiftKey
- Turning Hide full screen indicator off and on changes nothing
- Switching keyboards, clearing keyboard data and changing themes all change nothing
- Persian: نوار مشکی زیر کیبورد، فاصلهی اضافهی پایین صفحه، فلش پایین زیر کیبورد
Not this: a gap above the keyboard (that's the app's layout), or the navigation pill itself (that's Hide full screen indicator).
What causes it
HyperOS ships a runtime resource overlay, com.android.systemui.gesture.line.overlay, from /product/overlay/GestureLineOverlay.apk. It targets the android framework package at priority 2147483647 — it outranks every AOSP navigation-bar overlay on the device. Read live from a Xiaomi 13T on HyperOS 3 (Android 16, API 36):
| framework resource | with overlay | without |
|---|---|---|
bool/config_imeDrawsImeNavBar | true | false |
integer/config_navBarInteractionMode | 2 | 0 |
dimen/navigation_bar_frame_height | 48dp | 47.2dp |
dimen/navigation_bar_height | 16dp | 47.2dp |
dimen/config_backGestureInset | 30dp | 0dp |
config_imeDrawsImeNavBar = true is the whole bug. It instructs every input method to draw its own navigation-bar row inside the keyboard window and reserve height for it. You can watch the row exist, then stop existing:
# before
mNavigationBarController={mImeDrawsImeNavBar=true
mNavigationBarFrame=NavigationBarFrame{... 0,0-1220,144} ...}
# after
mNavigationBarController={mImeDrawsImeNavBar=false
mNavigationBarFrame=null ...}
144 physical pixels at density 3.0 is 48dp of keyboard you were paying for and could not touch.
Why gestures still work afterwards
Xiaomi's gesture engine is not the AOSP one. It runs off global force_fsg_nav_bar and global hide_gesture_line, both independent of navigation_mode. On a fixed 13T, secure navigation_mode reads 0 — nominally 3-button — while swipes work perfectly, because MIUI's own fsgesture is handling them.
Why the settings toggle never helped
Hide full screen indicator hides the white pill. It does not touch config_imeDrawsImeNavBar, so the keyboard still builds the row and still reserves the inset. Pill gone, gap intact — which is exactly what everybody reports.
Safety
- Nothing is deleted.
pm uninstall --user 0flips install state for one Android user; the APK stays byte-identical on read-only/product/overlay. - Bootloader stays locked,
verifiedbootstatestaysgreen, no partition is written. - Play Integrity / SafetyNet unaffected — no signature, property or partition change.
- Reversible, tested end-to-end on a real device.
The only real cost: a factory reset or a full OTA can restore the overlay, and you run apply again.
Verified
| device | rom | android | result |
|---|---|---|---|
| Xiaomi 13T | HyperOS OS3.0.5.0 | 16 / API 36 | affected → fixed, gestures intact |
| POCO X3 Pro | MIUI V13.0.5.0 | 12 / API 31 | not-affected → refused to write |
The X3 Pro is the deliberate negative case: MIUI 13 has no config_imeDrawsImeNavBar at all, so the script says so instead of writing to it. Both devices were used to confirm revert restores the exact prior state.
Questions
Does this need root?
No. Plain adb shell at uid 2000. No unlocked bootloader, no Magisk, no custom recovery.
Will my banking app notice?
No. Nothing is deleted and no partition, signature or system property changes. Bootloader stays locked, verified boot stays green.
Do I lose gesture navigation?
No — but you must re-pick Gestures once in Settings, because HyperOS falls back to 3-button when the overlay disappears.
Do I need to reboot?
No. And the fix survives reboots, because per-user install state is persistent.
Do I need "USB debugging (Security settings)"?
Not on the builds tested here — plain USB debugging was enough. If your ROM refuses with a SecurityException, the script tells you to enable it. That switch needs a signed-in Xiaomi account and in some regions a 24-hour wait plus an active SIM.
Second space or work profile?
The fix is per user. Pass --user 999 (check adb shell pm list users) for the other space.
Samsung, OnePlus, Pixel?
No. This overlay is Xiaomi-specific; the script reports not-applicable and does nothing.
Check it yourself
Don't take any of this on trust — read the device:
# which overlay wins for the resource that causes the gap
adb shell cmd overlay lookup --verbose android \
android:bool/config_imeDrawsImeNavBar
# is space being reserved at the bottom right now
adb shell dumpsys window displays | grep navigationBars
# is the keyboard drawing its own nav row
adb shell dumpsys input_method | grep -i imeDrawsNavBar
Device reports are the most useful contribution, especially HyperOS 3 builds where the verdict comes out wrong, or China / carrier ROMs that refuse the uninstall. Open a device report.