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 {