From 69db38742fc62e30976c28a60783ed05e6d2d6f5 Mon Sep 17 00:00:00 2001 From: PouleyKetchoupp Date: Fri, 24 Jul 2020 17:59:57 +0200 Subject: [PATCH] Virtual keyboard size adjustment fixes 1. Disable virtual keyboard focus adjustment on Android The default adjustment setting was causing the view to pan down in order to adjust the focus on the text content. We don't need any focus adjustment since we're using a fixed size window for our application. Documentation: https://developer.android.com/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_ADJUST_NOTHING 2. Fix virtual keyboard height regression Disabling virtual keyboard focus adjustement caused get_keyboard_height to always return 0 because it was calculated when the view is resized. In order to fix it, a PopupWindow is now created on top of the main view and is set for focus adjustments so the keyboard size can be calculated based on this popup without affecting the main view. --- .../lib/src/org/godotengine/godot/Godot.java | 40 ++++++++++++++++--- .../godot/input/GodotEditText.java | 10 ++++- 2 files changed, 43 insertions(+), 7 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 0760d3130d7..b31c18944c2 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -69,6 +69,7 @@ import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings.Secure; import android.view.Display; +import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Surface; @@ -80,6 +81,7 @@ import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; +import android.widget.PopupWindow; import android.widget.ProgressBar; import android.widget.TextView; @@ -248,6 +250,8 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe public GodotView mView; private boolean godot_initialized = false; + private PopupWindow mKeyboardWindow; + private SensorManager mSensorManager; private Sensor mAccelerometer; private Sensor mGravity; @@ -316,24 +320,36 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); setContentView(layout); + // Create a popup window with an invisible layout for the virtual keyboard, + // so the view can be resized to get the vk height without resizing the main godot view. + final FrameLayout keyboardLayout = new FrameLayout(this); + keyboardLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + keyboardLayout.setVisibility(View.INVISIBLE); + mKeyboardWindow = new PopupWindow(keyboardLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + mKeyboardWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + mKeyboardWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + mKeyboardWindow.setFocusable(true); // for the text edit to work + mKeyboardWindow.setTouchable(false); // inputs need to go through + // GodotEditText layout GodotEditText edittext = new GodotEditText(this); - edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - // ...add to FrameLayout - layout.addView(edittext); + edittext.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + edittext.setKeyboardView(keyboardLayout); + // ...add to keyboard layout + keyboardLayout.addView(edittext); mView = new GodotView(this, xrMode, use_gl3, use_32_bits, use_debug_opengl); layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); edittext.setView(mView); io.setEdit(edittext); - mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + keyboardLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Point fullSize = new Point(); getWindowManager().getDefaultDisplay().getSize(fullSize); Rect gameSize = new Rect(); - mView.getWindowVisibleDisplayFrame(gameSize); + mKeyboardWindow.getContentView().getWindowVisibleDisplayFrame(gameSize); final int keyboardHeight = fullSize.y - gameSize.bottom; GodotLib.setVirtualKeyboardHeight(keyboardHeight); @@ -571,6 +587,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe super.onCreate(icicle); Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); mClipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE); pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this); @@ -709,8 +726,21 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe initializeGodot(); } + @Override + protected void onStart() { + super.onStart(); + + mView.post(new Runnable() { + @Override + public void run() { + mKeyboardWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY, 0, 0); + } + }); + } + @Override protected void onDestroy() { + mKeyboardWindow.dismiss(); for (int i = 0; i < singleton_count; i++) { singletons[i].onMainDestroy(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java index fe2847f04f3..497e1d7556f 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java @@ -38,6 +38,7 @@ import android.os.Message; import android.text.InputFilter; import android.util.AttributeSet; import android.view.KeyEvent; +import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -55,6 +56,7 @@ public class GodotEditText extends EditText { // Fields // =========================================================== private GodotView mView; + private View mKeyboardView; private GodotTextInputWrapper mInputWrapper; private EditHandler sHandler = new EditHandler(this); private String mOriginText; @@ -117,7 +119,7 @@ public class GodotEditText extends EditText { edit.mInputWrapper.setOriginText(text); edit.addTextChangedListener(edit.mInputWrapper); - final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(edit, 0); } } break; @@ -126,7 +128,7 @@ public class GodotEditText extends EditText { GodotEditText edit = (GodotEditText)msg.obj; edit.removeTextChangedListener(mInputWrapper); - final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); edit.mView.requestFocus(); } break; @@ -150,6 +152,10 @@ public class GodotEditText extends EditText { view.requestFocus(); } + public void setKeyboardView(final View keyboardView) { + this.mKeyboardView = keyboardView; + } + // =========================================================== // Methods for/from SuperClass/Interfaces // ===========================================================