Android: Move EditPopupMenu to QtWindow
The EditPopupMenu requires a View in its constructor, making it important that we do not hold a reference to it after that View is no longer valid. In cases where we do not have one, top level View that will stay valid for the lifetime of the whole Activity, e.g. when embedding a QtView to non-Qt Android Activities, making the popups QtWindow based makes sense, as the lifecycle of the popup and it's corresponding QtWindow should match. Task-number: QTBUG-126180 Change-Id: Ibb45513de98f79a293a05eeb317d959ac0328dbe Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 9e167af3f6a4b2ac192aedd83f5066808d719415) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
8d2f2cc791
commit
e04eca32a0
@ -7,6 +7,7 @@ package org.qtproject.qt.android;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
@ -16,22 +17,23 @@ import android.widget.PopupWindow;
|
||||
class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayoutChangeListener,
|
||||
EditContextView.OnClickListener
|
||||
{
|
||||
private final View m_layout;
|
||||
private final EditContextView m_view;
|
||||
private final QtEditText m_editText;
|
||||
|
||||
private PopupWindow m_popup = null;
|
||||
private final Activity m_activity;
|
||||
private int m_posX;
|
||||
private int m_posY;
|
||||
private int m_buttons;
|
||||
private QtEditText m_currentEditText = null; // TODO, get rid of this reference
|
||||
|
||||
EditPopupMenu(Activity activity, View layout)
|
||||
EditPopupMenu(QtEditText editText)
|
||||
{
|
||||
m_activity = activity;
|
||||
m_view = new EditContextView(activity, this);
|
||||
m_activity = (Activity) editText.getContext();
|
||||
m_view = new EditContextView(m_activity, this);
|
||||
m_view.addOnLayoutChangeListener(this);
|
||||
|
||||
m_layout = layout;
|
||||
m_editText = editText;
|
||||
m_editText.getViewTreeObserver().addOnPreDrawListener(this);
|
||||
}
|
||||
|
||||
private void initOverlay()
|
||||
@ -39,19 +41,16 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
if (m_popup != null)
|
||||
return;
|
||||
|
||||
Context context = m_layout.getContext();
|
||||
m_popup = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
|
||||
m_popup = new PopupWindow(m_activity, null, android.R.attr.textSelectHandleWindowStyle);
|
||||
m_popup.setSplitTouchEnabled(true);
|
||||
m_popup.setClippingEnabled(false);
|
||||
m_popup.setContentView(m_view);
|
||||
m_popup.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
m_popup.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
m_layout.getViewTreeObserver().addOnPreDrawListener(this);
|
||||
}
|
||||
|
||||
// Show the handle at a given position (or move it if it is already shown)
|
||||
void setPosition(final int x, final int y, final int buttons, final QtEditText editText)
|
||||
void setPosition(final int x, final int y, final int buttons)
|
||||
{
|
||||
initOverlay();
|
||||
|
||||
@ -59,7 +58,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
Point viewSize = m_view.getCalculatedSize();
|
||||
|
||||
final int[] layoutLocation = new int[2];
|
||||
m_layout.getLocationOnScreen(layoutLocation);
|
||||
m_editText.getLocationOnScreen(layoutLocation);
|
||||
|
||||
// These values are used for handling split screen case
|
||||
final int[] activityLocation = new int[2];
|
||||
@ -73,15 +72,21 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
x2 -= viewSize.x / 2 ;
|
||||
|
||||
y2 -= viewSize.y;
|
||||
if (y2 < 0 && editText != null) {
|
||||
y2 = editText.getSelectionHandleBottom();
|
||||
if (y2 < 0)
|
||||
y2 = m_editText.getSelectionHandleBottom();
|
||||
|
||||
if (y2 <= 0) {
|
||||
try {
|
||||
QtLayout parentLayout = (QtLayout) m_editText.getParent();
|
||||
parentLayout.requestLayout();
|
||||
} catch (ClassCastException e) {
|
||||
Log.w(QtNative.QtTAG, "QtEditText " + m_editText + " parent is not a QtLayout, " +
|
||||
"requestLayout() skipped");
|
||||
}
|
||||
}
|
||||
|
||||
if (y2 <= 0)
|
||||
m_layout.requestLayout();
|
||||
|
||||
if (m_layout.getWidth() < x + viewSize.x / 2)
|
||||
x2 = m_layout.getWidth() - viewSize.x;
|
||||
if (m_editText.getWidth() < x + viewSize.x / 2)
|
||||
x2 = m_editText.getWidth() - viewSize.x;
|
||||
|
||||
if (x2 < 0)
|
||||
x2 = 0;
|
||||
@ -89,12 +94,11 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
if (m_popup.isShowing())
|
||||
m_popup.update(x2, y2, -1, -1);
|
||||
else
|
||||
m_popup.showAtLocation(m_layout, 0, x2, y2);
|
||||
m_popup.showAtLocation(m_editText, 0, x2, y2);
|
||||
|
||||
m_posX = x;
|
||||
m_posY = y;
|
||||
m_buttons = buttons;
|
||||
m_currentEditText = editText;
|
||||
}
|
||||
|
||||
void hide() {
|
||||
@ -110,7 +114,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
// For example if the keyboard appears.
|
||||
// Adjust the position of the handle accordingly
|
||||
if (m_popup != null && m_popup.isShowing())
|
||||
setPosition(m_posX, m_posY, m_buttons, m_currentEditText);
|
||||
setPosition(m_posX, m_posY, m_buttons);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -121,7 +125,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout
|
||||
{
|
||||
if ((right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop) &&
|
||||
m_popup != null && m_popup.isShowing())
|
||||
setPosition(m_posX, m_posY, m_buttons, m_currentEditText);
|
||||
setPosition(m_posX, m_posY, m_buttons);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,7 +140,6 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
r.width(), kbHeight);
|
||||
return true;
|
||||
});
|
||||
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,12 +61,15 @@ class QtEditText extends View
|
||||
private CursorHandle m_leftSelectionHandle;
|
||||
private CursorHandle m_rightSelectionHandle;
|
||||
|
||||
final private EditPopupMenu m_editPopupMenu;
|
||||
|
||||
QtEditText(Context context, QtInputConnectionListener listener)
|
||||
{
|
||||
super(context);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
m_qtInputConnectionListener = listener;
|
||||
m_editPopupMenu = new EditPopupMenu(this);
|
||||
}
|
||||
|
||||
private void setImeOptions(int imeOptions)
|
||||
@ -299,8 +302,19 @@ class QtEditText extends View
|
||||
m_cursorHandle.hide();
|
||||
m_cursorHandle = null;
|
||||
}
|
||||
mode |= CursorHandleShowEdit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!QtClipboardManager.hasClipboardText(getContext()))
|
||||
editButtons &= ~EditContextView.PASTE_BUTTON;
|
||||
|
||||
final boolean setEditPopupPosition = (mode & QtEditText.CursorHandleShowEdit) ==
|
||||
QtEditText.CursorHandleShowEdit && editButtons != 0;
|
||||
if (setEditPopupPosition)
|
||||
m_editPopupMenu.setPosition(editX, editY, editButtons);
|
||||
else
|
||||
m_editPopupMenu.hide();
|
||||
}
|
||||
|
||||
private boolean isDisablePredictiveTextWorkaround(int inputHints)
|
||||
|
@ -105,7 +105,6 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
|
||||
BackendRegister.unregisterBackend(QtMenuInterface.class);
|
||||
BackendRegister.unregisterBackend(QtInputInterface.class);
|
||||
}
|
||||
updateInputDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,21 +150,9 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
|
||||
public void setView(QtView view)
|
||||
{
|
||||
m_view = view;
|
||||
updateInputDelegate();
|
||||
}
|
||||
// QtEmbeddedViewInterface implementation end
|
||||
|
||||
private void updateInputDelegate() {
|
||||
// If the QtView has attached to the window before Qt libs have been loaded,
|
||||
// the input delegate will be null
|
||||
if (m_inputDelegate == null)
|
||||
return;
|
||||
if (m_view == null)
|
||||
m_inputDelegate.setEditPopupMenu(null);
|
||||
else
|
||||
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_view));
|
||||
}
|
||||
|
||||
private void createRootWindow() {
|
||||
if (m_view != null && !m_windowLoaded) {
|
||||
QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(),
|
||||
|
@ -52,8 +52,6 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
private int m_landscapeKeyboardHeight = 0;
|
||||
private int m_probeKeyboardHeightDelayMs = 50;
|
||||
|
||||
private EditPopupMenu m_editPopupMenu;
|
||||
|
||||
private int m_softInputMode = 0;
|
||||
|
||||
private static Boolean m_tabletEventSupported = null;
|
||||
@ -149,12 +147,13 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
mode is one of QAndroidInputContext::CursorHandleShowMode
|
||||
*/
|
||||
@Override
|
||||
public void updateHandles(Activity activity, QtLayout layout, int mode,
|
||||
int editX, int editY, int editButtons,
|
||||
public void updateHandles(int mode, int editX, int editY, int editButtons,
|
||||
int x1, int y1, int x2, int y2, boolean rtl)
|
||||
{
|
||||
QtNative.runAction(() -> updateHandleImpl(activity, layout, mode, editX, editY, editButtons,
|
||||
x1, y1, x2, y2, rtl));
|
||||
QtNative.runAction(() -> {
|
||||
if (m_currentEditText != null)
|
||||
m_currentEditText.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -247,11 +246,6 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
return m_currentEditText;
|
||||
}
|
||||
|
||||
void setEditPopupMenu(EditPopupMenu editPopupMenu)
|
||||
{
|
||||
m_editPopupMenu = editPopupMenu;
|
||||
}
|
||||
|
||||
private void keyboardVisibilityUpdated(boolean visibility)
|
||||
{
|
||||
m_isKeyboardHidingAnimationOngoing = false;
|
||||
@ -352,37 +346,6 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
}, m_probeKeyboardHeightDelayMs);
|
||||
}
|
||||
|
||||
private void updateHandleImpl(Activity activity, QtLayout layout, int mode,
|
||||
int editX, int editY, int editButtons,
|
||||
int x1, int y1, int x2, int y2, boolean rtl)
|
||||
{
|
||||
if (m_currentEditText != null)
|
||||
m_currentEditText.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
|
||||
|
||||
switch (mode & 0xff)
|
||||
{
|
||||
case QtEditText.CursorHandleNotShown:
|
||||
if (m_editPopupMenu != null)
|
||||
m_editPopupMenu.hide();
|
||||
break;
|
||||
case QtEditText.CursorHandleShowSelection:
|
||||
mode |= QtEditText.CursorHandleShowEdit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!QtClipboardManager.hasClipboardText(activity))
|
||||
editButtons &= ~EditContextView.PASTE_BUTTON;
|
||||
|
||||
if (m_editPopupMenu != null) {
|
||||
if ((mode & QtEditText.CursorHandleShowEdit) == QtEditText.CursorHandleShowEdit &&
|
||||
editButtons != 0) {
|
||||
m_editPopupMenu.setPosition(editX, editY, editButtons, m_currentEditText);
|
||||
} else {
|
||||
m_editPopupMenu.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean onKeyDown(int keyCode, KeyEvent event)
|
||||
{
|
||||
m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
|
||||
|
@ -15,7 +15,7 @@ interface QtInputInterface {
|
||||
void hideSoftwareKeyboard();
|
||||
boolean isSoftwareKeyboardVisible();
|
||||
int getSelectionHandleWidth();
|
||||
void updateHandles(Activity activity, QtLayout layout, int mode, int editX, int editY,
|
||||
int editButtons, int x1, int y1, int x2, int y2, boolean rtl);
|
||||
void updateHandles(int mode, int editX, int editY, int editButtons,
|
||||
int x1, int y1, int x2, int y2, boolean rtl);
|
||||
QtInputConnection.QtInputConnectionListener getInputConnectionListener();
|
||||
}
|
||||
|
@ -91,8 +91,7 @@ namespace QtAndroidInput
|
||||
{
|
||||
AndroidBackendRegister *reg = QtAndroid::backendRegister();
|
||||
reg->callInterface<QtJniTypes::QtInputInterface, void>(
|
||||
"updateHandles", QtAndroidPrivate::activity(),
|
||||
qtLayout().object<QtJniTypes::QtLayout>(), mode, editMenuPos.x(), editMenuPos.y(),
|
||||
"updateHandles", mode, editMenuPos.x(), editMenuPos.y(),
|
||||
editButtons, cursor.x(), cursor.y(), anchor.x(), anchor.y(), rtl);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user