diff options
Diffstat (limited to 'src/plugins/platforms/android/androidjniaccessibility.cpp')
-rw-r--r-- | src/plugins/platforms/android/androidjniaccessibility.cpp | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 38b1ed0952..8990289dc4 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "androiddeadlockprotector.h" #include "androidjniaccessibility.h" #include "androidjnimain.h" #include "qandroidplatformintegration.h" @@ -61,6 +62,14 @@ namespace QtAndroidAccessibility template <typename Func, typename Ret> void runInObjectContext(QObject *context, Func &&func, Ret *retVal) { + AndroidDeadlockProtector protector; + if (!protector.acquire()) { + __android_log_print(ANDROID_LOG_WARN, m_qtTag, + "Could not run accessibility call in object context, accessing " + "main thread could lead to deadlock"); + return; + } + if (!QtAndroid::blockEventLoopsWhenSuspended() || QGuiApplication::applicationState() != Qt::ApplicationSuspended) { QMetaObject::invokeMethod(context, func, Qt::BlockingQueuedConnection, retVal); @@ -131,6 +140,11 @@ namespace QtAndroidAccessibility QtAndroid::notifyValueChanged(accessibilityObjectId, value); } + void notifyScrolledEvent(uint accessiblityObjectId) + { + QtAndroid::notifyScrolledEvent(accessiblityObjectId); + } + static QVarLengthArray<int, 8> childIdListForAccessibleObject_helper(int objectId) { QAccessibleInterface *iface = interfaceFromId(objectId); @@ -188,7 +202,7 @@ namespace QtAndroidAccessibility return result; } - static QRect screenRect_helper(int objectId) + static QRect screenRect_helper(int objectId, bool clip = true) { QRect rect; QAccessibleInterface *iface = interfaceFromId(objectId); @@ -196,7 +210,7 @@ namespace QtAndroidAccessibility rect = QHighDpi::toNativePixels(iface->rect(), iface->window()); } // If the widget is not fully in-bound in its parent then we have to clip the rectangle to draw - if (iface && iface->parent() && iface->parent()->isValid()) { + if (clip && iface && iface->parent() && iface->parent()->isValid()) { const auto parentRect = QHighDpi::toNativePixels(iface->parent()->rect(), iface->parent()->window()); rect = rect.intersected(parentRect); } @@ -298,23 +312,43 @@ namespace QtAndroidAccessibility static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) { bool result = false; + + const auto& ids = childIdListForAccessibleObject_helper(objectId); + if (ids.isEmpty()) + return false; + + const int firstChildId = ids.first(); + const QRect oldPosition = screenRect_helper(firstChildId, false); + if (m_accessibilityContext) { runInObjectContext(m_accessibilityContext, [objectId]() { return scroll_helper(objectId, QAccessibleActionInterface::increaseAction()); }, &result); } - return result; + + // Don't check for position change if the call was not successful + return result && oldPosition != screenRect_helper(firstChildId, false); } static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) { bool result = false; + + const auto& ids = childIdListForAccessibleObject_helper(objectId); + if (ids.isEmpty()) + return false; + + const int firstChildId = ids.first(); + const QRect oldPosition = screenRect_helper(firstChildId, false); + if (m_accessibilityContext) { runInObjectContext(m_accessibilityContext, [objectId]() { return scroll_helper(objectId, QAccessibleActionInterface::decreaseAction()); }, &result); } - return result; + + // Don't check for position change if the call was not successful + return result && oldPosition != screenRect_helper(firstChildId, false); } |