Android: Move QtEditText to QtWindow
Every QtWindow has its own QtEditText. QtInputDelegate uses QtEditText from the QtWindow which has the focus. QtEditText is a View class which handles the creation of the input connection, and encapsulates other various keyboard input related functionalities. Previously we have only had one, which requests focus when the software keyboard is opened. However, with the introduction of child windows, it does not make sense for all the windows to operate through this one instance. Furthermore, since it always needs to have focus to be able to open the software keyboard, this leads to a bit surprising behavior in the focus chain if we want to make each window focusable, not just the top level one. Having each window have its own QtEditText makes sure when a window gets focus, the focus doesn't leave outside of the matching view's own scope, making it easier to handle. This should also make it easier to clean up keyboard input related events tied to a window when that window is removed. Task-number: QTBUG-118139 Change-Id: Idd1a9407bc0c48660f2885d3bda28e46d42c08a0 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit f4050cc5ea7490ba3b8b2bb0a174559d7e72a27e) Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
This commit is contained in:
parent
02ab923adf
commit
1712c4eeca
@ -274,8 +274,13 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
public void openContextMenu(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
m_layout.postDelayed(() -> {
|
||||
m_layout.setLayoutParams(m_inputDelegate.getQtEditText(), new QtLayout.LayoutParams(w, h, x, y), false);
|
||||
PopupMenu popup = new PopupMenu(m_activity, m_inputDelegate.getQtEditText());
|
||||
final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
|
||||
if (focusedEditText == null) {
|
||||
Log.w(QtTAG, "No focused view when trying to open context menu");
|
||||
return;
|
||||
}
|
||||
m_layout.setLayoutParams(focusedEditText, new QtLayout.LayoutParams(w, h, x, y), false);
|
||||
PopupMenu popup = new PopupMenu(m_activity, focusedEditText);
|
||||
QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
|
||||
popup.setOnMenuItemClickListener(menuItem ->
|
||||
m_activity.onContextItemSelected(menuItem));
|
||||
@ -325,6 +330,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
m_topLevelWindows.put(window.getId(), window);
|
||||
if (!m_splashScreenSticky)
|
||||
hideSplashScreen();
|
||||
m_inputDelegate.setFocusedView(window.getQtEditText());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,6 @@ abstract class QtActivityDelegateBase
|
||||
setUpLayout();
|
||||
}
|
||||
|
||||
|
||||
public void hideSplashScreen()
|
||||
{
|
||||
hideSplashScreen(0);
|
||||
|
@ -39,7 +39,7 @@ class QtInputDelegate {
|
||||
public static native void handleLocationChanged(int id, int x, int y);
|
||||
// handle methods
|
||||
|
||||
private final QtEditText m_editText;
|
||||
private QtEditText m_currentEditText = null;
|
||||
private final InputMethodManager m_imm;
|
||||
|
||||
private boolean m_keyboardIsVisible = false;
|
||||
@ -108,13 +108,13 @@ class QtInputDelegate {
|
||||
}
|
||||
|
||||
private final KeyboardVisibilityListener m_keyboardVisibilityListener;
|
||||
private final QtInputConnectionListener m_inputConnectionListener;
|
||||
|
||||
QtInputDelegate(Activity activity, KeyboardVisibilityListener listener)
|
||||
{
|
||||
this.m_keyboardVisibilityListener = listener;
|
||||
m_editText = new QtEditText(activity);
|
||||
m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
QtInputConnectionListener inputConnectionListener = new QtInputConnectionListener() {
|
||||
m_inputConnectionListener = new QtInputConnectionListener() {
|
||||
@Override
|
||||
public void onSetClosing(boolean closing) {
|
||||
if (!closing)
|
||||
@ -131,7 +131,6 @@ class QtInputDelegate {
|
||||
hideSoftwareKeyboard();
|
||||
}
|
||||
};
|
||||
m_editText.setQtInputConnectionListener(inputConnectionListener);
|
||||
}
|
||||
|
||||
public boolean isKeyboardVisible()
|
||||
@ -151,9 +150,9 @@ class QtInputDelegate {
|
||||
m_softInputMode = inputMode;
|
||||
}
|
||||
|
||||
QtEditText getQtEditText()
|
||||
QtEditText getCurrentQtEditText()
|
||||
{
|
||||
return m_editText;
|
||||
return m_currentEditText;
|
||||
}
|
||||
|
||||
void setEditPopupMenu(EditPopupMenu editPopupMenu)
|
||||
@ -187,34 +186,38 @@ class QtInputDelegate {
|
||||
@UsedFromNativeCode
|
||||
public void resetSoftwareKeyboard()
|
||||
{
|
||||
if (m_imm == null)
|
||||
if (m_imm == null || m_currentEditText == null)
|
||||
return;
|
||||
m_editText.postDelayed(() -> {
|
||||
m_imm.restartInput(m_editText);
|
||||
m_editText.m_optionsChanged = false;
|
||||
m_currentEditText.postDelayed(() -> {
|
||||
m_imm.restartInput(m_currentEditText);
|
||||
m_currentEditText.m_optionsChanged = false;
|
||||
}, 5);
|
||||
}
|
||||
|
||||
void setFocusedView(QtEditText currentEditText)
|
||||
{
|
||||
m_currentEditText = currentEditText;
|
||||
// TODO rather set the listener when creating the edit text
|
||||
if (m_currentEditText != null)
|
||||
m_currentEditText.setQtInputConnectionListener(m_inputConnectionListener);
|
||||
}
|
||||
|
||||
public void showSoftwareKeyboard(Activity activity, QtLayout layout,
|
||||
final int x, final int y, final int width, final int height,
|
||||
final int inputHints, final int enterKeyType)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
if (m_imm == null)
|
||||
if (m_imm == null || m_currentEditText == null)
|
||||
return;
|
||||
|
||||
if (updateSoftInputMode(activity, height))
|
||||
return;
|
||||
|
||||
setEditTextOptions(enterKeyType, inputHints);
|
||||
m_currentEditText.requestFocus();
|
||||
|
||||
// TODO: The editText is added to the QtLayout, but is it ever removed?
|
||||
QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(width, height, x, y);
|
||||
layout.setLayoutParams(m_editText, layoutParams, false);
|
||||
m_editText.requestFocus();
|
||||
|
||||
m_editText.postDelayed(() -> {
|
||||
m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) {
|
||||
m_currentEditText.postDelayed(() -> {
|
||||
m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
switch (resultCode) {
|
||||
@ -235,9 +238,9 @@ class QtInputDelegate {
|
||||
}
|
||||
}
|
||||
});
|
||||
if (m_editText.m_optionsChanged) {
|
||||
m_imm.restartInput(m_editText);
|
||||
m_editText.m_optionsChanged = false;
|
||||
if (m_currentEditText.m_optionsChanged) {
|
||||
m_imm.restartInput(m_currentEditText);
|
||||
m_currentEditText.m_optionsChanged = false;
|
||||
}
|
||||
}, 15);
|
||||
});
|
||||
@ -304,9 +307,9 @@ class QtInputDelegate {
|
||||
if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0)
|
||||
imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
|
||||
m_editText.setInitialCapsMode(initialCapsMode);
|
||||
m_editText.setImeOptions(imeOptions);
|
||||
m_editText.setInputType(inputType);
|
||||
m_currentEditText.setInitialCapsMode(initialCapsMode);
|
||||
m_currentEditText.setImeOptions(imeOptions);
|
||||
m_currentEditText.setInputType(inputType);
|
||||
}
|
||||
|
||||
private boolean isDisablePredictiveTextWorkaround(int inputHints)
|
||||
@ -418,10 +421,10 @@ class QtInputDelegate {
|
||||
{
|
||||
m_isKeyboardHidingAnimationOngoing = true;
|
||||
QtNative.runAction(() -> {
|
||||
if (m_imm == null)
|
||||
if (m_imm == null || m_currentEditText == null)
|
||||
return;
|
||||
|
||||
m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0,
|
||||
m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0,
|
||||
new ResultReceiver(new Handler()) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
@ -448,7 +451,7 @@ class QtInputDelegate {
|
||||
if (m_imm == null)
|
||||
return;
|
||||
|
||||
m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
private HashMap<Integer, QtWindow> m_childWindows = new HashMap<Integer, QtWindow>();
|
||||
private QtWindow m_parentWindow;
|
||||
private GestureDetector m_gestureDetector;
|
||||
private final QtEditText m_editText;
|
||||
|
||||
private static native void setSurface(int windowId, Surface surface);
|
||||
|
||||
@ -28,6 +29,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
{
|
||||
super(context);
|
||||
setId(View.generateViewId());
|
||||
m_editText = new QtEditText(context);
|
||||
setParent(parentWindow);
|
||||
|
||||
QtNative.runAction(() -> {
|
||||
@ -41,6 +43,13 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO this is a temporary workaround to be able to set the input delegate current edit text,
|
||||
// the next two patches make this redundant
|
||||
QtEditText getQtEditText()
|
||||
{
|
||||
return m_editText;
|
||||
}
|
||||
|
||||
void setVisible(boolean visible) {
|
||||
QtNative.runAction(() -> {
|
||||
if (visible)
|
||||
@ -106,6 +115,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
// The surface container of this window will be added as the first of the stack.
|
||||
// All other views are stacked based on the order they are created.
|
||||
addView(m_surfaceContainer, 0);
|
||||
addView(m_editText, new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user