From 9bdb5853181a660410461a65012b5b1bdadadd69 Mon Sep 17 00:00:00 2001 From: necrashter Date: Sat, 4 Mar 2023 21:26:28 +0300 Subject: [PATCH] Use the new API for virtual keyboard height detection on Android, bugfix --- .../lib/src/org/godotengine/godot/Godot.java | 72 ++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index a00e3f95ab8..a55fe567e07 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -79,8 +79,12 @@ import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; import android.view.WindowManager; +import android.view.animation.AnimationUtils; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ProgressBar; @@ -91,6 +95,9 @@ import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.core.view.OnApplyWindowInsetsListener; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import com.google.android.vending.expansion.downloader.DownloadProgressInfo; @@ -370,14 +377,63 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC edittext.setView(mView); io.setEdit(edittext); - mView.getViewTreeObserver().addOnGlobalLayoutListener(() -> { - Point fullSize = new Point(); - activity.getWindowManager().getDefaultDisplay().getSize(fullSize); - Rect gameSize = new Rect(); - mView.getWindowVisibleDisplayFrame(gameSize); - final int keyboardHeight = fullSize.y - gameSize.bottom; - GodotLib.setVirtualKeyboardHeight(keyboardHeight); - }); + // Listeners for keyboard height. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // Report the height of virtual keyboard as it changes during the animation. + final View decorView = activity.getWindow().getDecorView(); + decorView.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback(WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP) { + int startBottom, endBottom; + @Override + public void onPrepare(@NonNull WindowInsetsAnimation animation) { + startBottom = decorView.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom; + } + + @NonNull + @Override + public WindowInsetsAnimation.Bounds onStart(@NonNull WindowInsetsAnimation animation, @NonNull WindowInsetsAnimation.Bounds bounds) { + endBottom = decorView.getRootWindowInsets().getInsets(WindowInsets.Type.ime()).bottom; + return bounds; + } + + @NonNull + @Override + public WindowInsets onProgress(@NonNull WindowInsets windowInsets, @NonNull List list) { + // Find the IME animation. + WindowInsetsAnimation imeAnimation = null; + for (WindowInsetsAnimation animation : list) { + if ((animation.getTypeMask() & WindowInsets.Type.ime()) != 0) { + imeAnimation = animation; + break; + } + } + // Update keyboard height based on IME animation. + if (imeAnimation != null) { + float interpolatedFraction = imeAnimation.getInterpolatedFraction(); + // Linear interpolation between start and end values. + float keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction; + GodotLib.setVirtualKeyboardHeight((int)keyboardHeight); + } + return windowInsets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimation animation) { + } + }); + } else { + // Infer the virtual keyboard height using visible area. + mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + // Don't allocate a new Rect every time the callback is called. + final Rect visibleSize = new Rect(); + + @Override + public void onGlobalLayout() { + mView.getWindowVisibleDisplayFrame(visibleSize); + final int keyboardHeight = mView.getHeight() - visibleSize.bottom; + GodotLib.setVirtualKeyboardHeight(keyboardHeight); + } + }); + } final String[] current_command_line = command_line; mView.queueEvent(() -> {