summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/android/androidjniaccessibility.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/android/androidjniaccessibility.cpp')
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp42
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);
}