diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 1cc4d587743..b9aca5afdf7 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -2059,6 +2059,7 @@
Returns the on-screen keyboard's height in pixels. Returns 0 if there is no keyboard or if it is currently hidden.
+ [b]Note:[/b] On Android 7 and 8, the keyboard height may return 0 the first time the keyboard is opened in non-immersive mode. This behavior does not occur in immersive mode.
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index e99aaa4a8d9..1c5dedf03e2 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -37,6 +37,7 @@
android:excludeFromRecents="false"
android:exported="true"
android:screenOrientation="landscape"
+ android:windowSoftInputMode="adjustResize"
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
android:resizeableActivity="false"
tools:ignore="UnusedAttribute" >
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index 8e020e5fffa..876ac4a1f41 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -38,6 +38,7 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
+import android.graphics.Rect
import android.hardware.Sensor
import android.hardware.SensorManager
import android.os.*
@@ -357,16 +358,29 @@ class Godot private constructor(val context: Context) {
if (enabled) {
ViewCompat.setOnApplyWindowInsetsListener(rootView, null)
rootView.setPadding(0, 0, 0, 0)
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
+ }
} else {
if (rootView.rootWindowInsets != null) {
- val windowInsets = WindowInsetsCompat.toWindowInsetsCompat(rootView.rootWindowInsets)
- val insets = windowInsets.getInsets(getInsetType())
- rootView.setPadding(insets.left, insets.top, insets.right, insets.bottom)
+ if (!useImmersive.get() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)) {
+ val windowInsets = WindowInsetsCompat.toWindowInsetsCompat(rootView.rootWindowInsets)
+ val insets = windowInsets.getInsets(getInsetType())
+ rootView.setPadding(insets.left, insets.top, insets.right, insets.bottom)
+ }
}
ViewCompat.setOnApplyWindowInsetsListener(rootView) { v: View, insets: WindowInsetsCompat ->
- val windowInsets = insets.getInsets(getInsetType())
- v.setPadding(windowInsets.left, windowInsets.top, windowInsets.right, windowInsets.bottom)
+ v.post {
+ if (useImmersive.get() && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ // Fixes issue where padding remained visible in immersive mode on some devices.
+ v.setPadding(0, 0, 0, 0)
+ } else {
+ val windowInsets = insets.getInsets(getInsetType())
+ v.setPadding(windowInsets.left, windowInsets.top, windowInsets.right, windowInsets.bottom)
+ }
+ }
WindowInsetsCompat.CONSUMED
}
}
@@ -531,12 +545,18 @@ class Godot private constructor(val context: Context) {
startBottom = ViewCompat.getRootWindowInsets(topView)?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
}
- override fun onStart(animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat): WindowInsetsAnimationCompat.BoundsCompat {
+ override fun onStart(
+ animation: WindowInsetsAnimationCompat,
+ bounds: WindowInsetsAnimationCompat.BoundsCompat
+ ): WindowInsetsAnimationCompat.BoundsCompat {
endBottom = ViewCompat.getRootWindowInsets(topView)?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
return bounds
}
- override fun onProgress(windowInsets: WindowInsetsCompat, animationsList: List): WindowInsetsCompat {
+ override fun onProgress(
+ windowInsets: WindowInsetsCompat,
+ animationsList: List
+ ): WindowInsetsCompat {
// Find the IME animation.
var imeAnimation: WindowInsetsAnimationCompat? = null
for (animation in animationsList) {
@@ -551,12 +571,20 @@ class Godot private constructor(val context: Context) {
val interpolatedFraction = imeAnimation.interpolatedFraction
// Linear interpolation between start and end values.
val keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction
- GodotLib.setVirtualKeyboardHeight(keyboardHeight.toInt())
+ val finalHeight = maxOf(keyboardHeight.toInt() - topView.rootView.paddingBottom, 0)
+ GodotLib.setVirtualKeyboardHeight(finalHeight)
}
return windowInsets
}
- override fun onEnd(animation: WindowInsetsAnimationCompat) {}
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {
+ // Fixes issue on Android 7 and 8 where immersive mode gets auto disabled after the keyboard is hidden.
+ if (useImmersive.get() && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
+ runOnHostThread {
+ enableImmersiveMode(true, true)
+ }
+ }
+ }
})
renderView?.queueOnRenderThread {