From 5c6b10c3cee5737dbc041d0463220898c8120807 Mon Sep 17 00:00:00 2001 From: Piotr Mikolajczyk Date: Fri, 18 Dec 2020 10:51:30 +0100 Subject: [PATCH 1/2] Android: Place cursor correctly on screen when editing When editing text the cursor is not placed correctly. So this has been achieved by tricking Android into thinking that the input area is only the line where the cursor is, so it is forced to keep it on screen. Fixes: QTBUG-91073 Pick-to: 5.15 Change-Id: Icc2e8315deb76ca1a84819d3fdceaa7b027b1174 Reviewed-by: Ville Voutilainen --- .../qt/android/QtActivityDelegate.java | 15 +++++-- .../org/qtproject/qt/android/QtNative.java | 17 ++++++- .../qt/android/bindings/QtActivity.java | 11 +++-- .../platforms/android/androidjniinput.cpp | 16 ++++++- .../platforms/android/androidjniinput.h | 4 +- .../android/qandroidinputcontext.cpp | 44 +++++++++++++++++-- .../platforms/android/qandroidinputcontext.h | 2 + 7 files changed, 95 insertions(+), 14 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java index 4cae9465ba..c473c1f78b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -280,7 +280,7 @@ public class QtActivityDelegate }, 5); } - public void showSoftwareKeyboard(final int x, final int y, final int width, final int height, final int inputHints, final int enterKeyType) + public void showSoftwareKeyboard(final int x, final int y, final int width, final int height, final int editorHeight, final int inputHints, final int enterKeyType) { if (m_imm == null) return; @@ -302,7 +302,7 @@ public class QtActivityDelegate if (softInputIsHidden) return; } else { - if (height > visibleHeight) + if (editorHeight > visibleHeight) m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); else m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); @@ -419,12 +419,12 @@ public class QtActivityDelegate if (metrics.widthPixels > metrics.heightPixels) { // landscape if (m_landscapeKeyboardHeight != r.bottom) { m_landscapeKeyboardHeight = r.bottom; - showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); + showSoftwareKeyboard(x, y, width, height, editorHeight, inputHints, enterKeyType); } } else { if (m_portraitKeyboardHeight != r.bottom) { m_portraitKeyboardHeight = r.bottom; - showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); + showSoftwareKeyboard(x, y, width, height, editorHeight, inputHints, enterKeyType); } } } else { @@ -575,6 +575,13 @@ public class QtActivityDelegate } } + public void updateInputItemRectangle(final int x, final int y, final int w, final int h) + { + if (m_layout == null || m_editText == null || !m_keyboardIsVisible) + return; + m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(w, h, x, y), true); + } + public boolean loadApplication(Activity activity, ClassLoader classLoader, Bundle loaderParams) { /// check parameters integrity diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java index 001e6a7970..cb2a78b403 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -883,10 +883,25 @@ public class QtNative }); } + private static void updateInputItemRectangle(final int x, + final int y, + final int w, + final int h) + { + runAction(new Runnable() { + @Override + public void run() { + m_activityDelegate.updateInputItemRectangle(x, y, w, h); + } + }); + } + + private static void showSoftwareKeyboard(final int x, final int y, final int width, final int height, + final int editorHeight, final int inputHints, final int enterKeyType) { @@ -894,7 +909,7 @@ public class QtNative @Override public void run() { if (m_activityDelegate != null) - m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); + m_activityDelegate.showSoftwareKeyboard(x, y, width, height, editorHeight, inputHints, enterKeyType); } }); } diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java index a4e6df058d..553c9dffdd 100644 --- a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java @@ -1074,6 +1074,11 @@ public class QtActivity extends Activity QtNative.activityDelegate().resetSoftwareKeyboard(); } + public void updateInputItemRectangle(final int x, final int y, final int w, final int h) + { + QtNative.activityDelegate().updateInputItemRectangle(x, y, w, h); + } + public boolean setKeyboardVisibility(boolean visibility, long timeStamp) { return QtNative.activityDelegate().setKeyboardVisibility(visibility, timeStamp); @@ -1090,10 +1095,10 @@ public class QtActivity extends Activity } public void showSoftwareKeyboard(final int x, final int y, final int width, - final int height, final int inputHints, - final int enterKeyType) + final int height, final int editorHeight, + final int inputHints, final int enterKeyType) { - QtNative.activityDelegate().showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); + QtNative.activityDelegate().showSoftwareKeyboard(x, y, width, height, editorHeight, inputHints, enterKeyType); } public boolean startApplication() diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 1de25b2857..d720f1a317 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -79,15 +79,16 @@ namespace QtAndroidInput candidatesEnd); } - void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) + void showSoftwareKeyboard(int left, int top, int width, int height, int editorHeight, int inputHints, int enterKeyType) { QJniObject::callStaticMethod(applicationClass(), "showSoftwareKeyboard", - "(IIIIII)V", + "(IIIIIII)V", left, top, width, height, + editorHeight, inputHints, enterKeyType); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL @@ -129,6 +130,17 @@ namespace QtAndroidInput anchor.x(), anchor.y(), rtl); } + void updateInputItemRectangle(int left, int top, int width, int height) + { + QJniObject::callStaticMethod(applicationClass(), + "updateInputItemRectangle", + "(IIII)V", + left, + top, + width, + height); + } + static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y) { if (m_ignoreMouseEvents) diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h index 9e75f43a83..7a93e0214c 100644 --- a/src/plugins/platforms/android/androidjniinput.h +++ b/src/plugins/platforms/android/androidjniinput.h @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE namespace QtAndroidInput { // Software keyboard support - void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints, int enterKeyType); + void showSoftwareKeyboard(int top, int left, int width, int editorHeight, int height, int inputHints, int enterKeyType); void resetSoftwareKeyboard(); void hideSoftwareKeyboard(); bool isSoftwareKeyboardVisible(); @@ -57,6 +57,8 @@ namespace QtAndroidInput void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd); // Software keyboard support + // edit field resize + void updateInputItemRectangle(int left, int top, int width, int height); // cursor/selection handles void updateHandles(int handleCount, QPoint editMenuPos = QPoint(), uint32_t editButtons = 0, QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 29236667d3..378dfa03c8 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -47,6 +47,7 @@ #include "qandroideventdispatcher.h" #include "qandroidinputcontext.h" #include "qandroidplatformintegration.h" +#include "private/qhighdpiscaling_p.h" #include #include @@ -59,7 +60,6 @@ #include #include #include - QT_BEGIN_NAMESPACE namespace { @@ -491,7 +491,7 @@ QAndroidInputContext::QAndroidInputContext() m_androidInputContext = this; QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, - this, &QAndroidInputContext::updateSelectionHandles); + this, &QAndroidInputContext::updateInputItemRectangle); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged, this, &QAndroidInputContext::updateSelectionHandles); QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged, this, [this]{ @@ -889,12 +889,50 @@ void QAndroidInputContext::showInputPanel() else m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); - QRect rect = screenInputItemRectangle(); + QRect rect = cursorRect(); QtAndroidInput::showSoftwareKeyboard(rect.left(), rect.top(), rect.width(), rect.height(), + screenInputItemRectangle().height(), query->value(Qt::ImHints).toUInt(), query->value(Qt::ImEnterKeyType).toUInt()); } +QRect QAndroidInputContext::cursorRect() +{ + QSharedPointer query = focusObjectInputMethodQuery(); + // if single line, we do not want to mess with the editor's position, as we do not + // have to follow the cursor in vertical axis + if (query.isNull() + || (query->value(Qt::ImHints).toUInt() & Qt::ImhMultiLine) != Qt::ImhMultiLine) + return {}; + + auto im = qGuiApp->inputMethod(); + if (!im) + return {}; + + const auto cursorRect= im->cursorRectangle().toRect(); + QRect finalRect(inputItemRectangle().toRect()); + const QWindow *window = qGuiApp->focusWindow(); + const double pd = window + ? QHighDpiScaling::factor(window) + : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); + finalRect.setY(cursorRect.y() * pd); + finalRect.setHeight(cursorRect.height() * pd); + //fiddle a bit with vert margins, so the tracking rectangle is not too tight. + finalRect += QMargins(0, cursorRect.height() / 4, 0, cursorRect.height() / 4); + return finalRect; +} + +void QAndroidInputContext::updateInputItemRectangle() +{ + QRect rect = cursorRect(); + + if (!rect.isValid()) + return; + QtAndroidInput::updateInputItemRectangle(rect.left(), rect.top(), + rect.width(), rect.height()); + updateSelectionHandles(); +} + void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state) { if (state != Qt::ApplicationActive) diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index e9bfb98e66..02a66c367a 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -138,6 +138,7 @@ public: public slots: void safeCall(const std::function &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection); void updateCursorPosition(); + void updateInputItemRectangle(); void updateSelectionHandles(); void handleLocationChanged(int handleId, int x, int y); void touchDown(int x, int y); @@ -154,6 +155,7 @@ private: bool focusObjectIsComposing() const; void focusObjectStartComposing(); bool focusObjectStopComposing(); + QRect cursorRect(); private: ExtractedText m_extractedText; From 49e93b6e3928e12507ec7956d66e79a2555c13a8 Mon Sep 17 00:00:00 2001 From: Toni Saario Date: Wed, 3 Mar 2021 21:03:25 +0200 Subject: [PATCH 2/2] Skip globalstatic threadStressTest on QEMU The test causes frequent failures in the CI. This is the most subtle fix until it is properly fixed. Pick-to: 6.1 Task-number: QTBUG-91423 Change-Id: I6499378dcd3ed1c31275db38d83b572e764366cc Reviewed-by: Friedemann Kleint Reviewed-by: Edward Welbourne Reviewed-by: Samuli Piippo --- tests/auto/corelib/global/qglobalstatic/CMakeLists.txt | 1 + .../auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/tests/auto/corelib/global/qglobalstatic/CMakeLists.txt b/tests/auto/corelib/global/qglobalstatic/CMakeLists.txt index 959b2b25b0..6f8a784a0d 100644 --- a/tests/auto/corelib/global/qglobalstatic/CMakeLists.txt +++ b/tests/auto/corelib/global/qglobalstatic/CMakeLists.txt @@ -12,4 +12,5 @@ qt_internal_add_test(tst_qglobalstatic SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" PUBLIC_LIBRARIES Qt::CorePrivate + Qt::TestPrivate ) diff --git a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp index dfc62ce163..190df2a555 100644 --- a/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp +++ b/tests/auto/corelib/global/qglobalstatic/tst_qglobalstatic.cpp @@ -35,6 +35,8 @@ #include #endif +#include + class tst_QGlobalStatic : public QObject { Q_OBJECT @@ -179,6 +181,9 @@ Q_GLOBAL_STATIC_WITH_ARGS(ThrowingType, threadStressTestGS, (threadStressTestCon void tst_QGlobalStatic::threadStressTest() { + if (QTestPrivate::isRunningArmOnX86()) + QSKIP("Frequently hangs on QEMU, QTBUG-91423"); + class ThreadStressTestThread: public QThread { public: