summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorPiotr Mikolajczyk <piotr.mikolajczyk@qt.io>2020-11-20 15:07:59 +0100
committerPiotr Mikolajczyk <piotr.mikolajczyk@qt.io>2020-12-08 10:02:34 +0100
commitfd20bc2277f98b86bddbd3f8a0ca92457a8c7c70 (patch)
tree69939f53963fb5a8ca42c85dac20dbdc28f89fa9 /src/plugins
parent4a85160e0bcfef04ed186d3fe264566d6313727c (diff)
Android: Qml accessibility fixes
- Accessibility focus can follow the position of the widget (for example when swiping on a scrollview) - controls are clickable directly after appearing on the screen after scroll (previously you had to click somewhere else on the screen, and after that you could focus the newly appeared control) - checkbox and switch react correctly on click action - fixed combobox behavior with accessibility enabled Task-number: QTBUG-79611 Pick-to: 6.0 5.15 Change-Id: If36914ab0165f33593e68fd7ecf168693f8538a7 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp59
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.h3
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp15
-rw-r--r--src/plugins/platforms/android/androidjnimain.h4
-rw-r--r--src/plugins/platforms/android/qandroidplatformaccessibility.cpp19
5 files changed, 87 insertions, 13 deletions
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index 8d9a968b4f..a4e88d84d4 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -65,6 +65,7 @@ namespace QtAndroidAccessibility
static jmethodID m_setCheckedMethodID = 0;
static jmethodID m_setClickableMethodID = 0;
static jmethodID m_setContentDescriptionMethodID = 0;
+ static jmethodID m_setEditableMethodID = 0;
static jmethodID m_setEnabledMethodID = 0;
static jmethodID m_setFocusableMethodID = 0;
static jmethodID m_setFocusedMethodID = 0;
@@ -109,6 +110,21 @@ namespace QtAndroidAccessibility
return iface;
}
+ void notifyLocationChange()
+ {
+ QtAndroid::notifyAccessibilityLocationChange();
+ }
+
+ void notifyObjectHide(uint accessibilityObjectId)
+ {
+ QtAndroid::notifyObjectHide(accessibilityObjectId);
+ }
+
+ void notifyObjectFocus(uint accessibilityObjectId)
+ {
+ QtAndroid::notifyObjectFocus(accessibilityObjectId);
+ }
+
static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
{
QAccessibleInterface *iface = interfaceFromId(objectId);
@@ -150,6 +166,11 @@ namespace QtAndroidAccessibility
if (iface && iface->isValid()) {
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()) {
+ const auto parentRect = QHighDpi::toNativePixels(iface->parent()->rect(), iface->parent()->window());
+ rect = rect.intersected(parentRect);
+ }
jclass rectClass = env->FindClass("android/graphics/Rect");
jmethodID ctor = env->GetMethodID(rectClass, "<init>", "(IIII)V");
@@ -175,17 +196,33 @@ namespace QtAndroidAccessibility
return -1;
}
+ static void invokeActionOnInterfaceInMainThread(QAccessibleActionInterface* actionInterface,
+ const QString& action)
+ {
+ QMetaObject::invokeMethod(qApp, [actionInterface, action]() {
+ actionInterface->doAction(action);
+ });
+ }
+
static jboolean clickAction(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{
// qDebug() << "A11Y: CLICK: " << objectId;
QAccessibleInterface *iface = interfaceFromId(objectId);
- if (iface && iface->isValid() && iface->actionInterface()) {
- if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction()))
- iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
- else
- iface->actionInterface()->doAction(QAccessibleActionInterface::toggleAction());
+ if (!iface || !iface->isValid() || !iface->actionInterface())
+ return false;
+
+ const auto& actionNames = iface->actionInterface()->actionNames();
+
+ if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
+ invokeActionOnInterfaceInMainThread(iface->actionInterface(),
+ QAccessibleActionInterface::pressAction());
+ } else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
+ invokeActionOnInterfaceInMainThread(iface->actionInterface(),
+ QAccessibleActionInterface::toggleAction());
+ } else {
+ return false;
}
- return false;
+ return true;
}
static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
@@ -267,9 +304,10 @@ if (!clazz) { \
}
}
- env->CallVoidMethod(node, m_setEnabledMethodID, !state.disabled);
env->CallVoidMethod(node, m_setCheckableMethodID, (bool)state.checkable);
env->CallVoidMethod(node, m_setCheckedMethodID, (bool)state.checked);
+ env->CallVoidMethod(node, m_setEditableMethodID, state.editable);
+ env->CallVoidMethod(node, m_setEnabledMethodID, !state.disabled);
env->CallVoidMethod(node, m_setFocusableMethodID, (bool)state.focusable);
env->CallVoidMethod(node, m_setFocusedMethodID, (bool)state.focused);
env->CallVoidMethod(node, m_setVisibleToUserMethodID, !state.invisible);
@@ -278,15 +316,15 @@ if (!clazz) { \
// Add ACTION_CLICK
if (hasClickableAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)16); // ACTION_CLICK defined in AccessibilityNodeInfo
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00000010); // ACTION_CLICK defined in AccessibilityNodeInfo
// Add ACTION_SCROLL_FORWARD
if (hasIncreaseAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)4096); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00001000); // ACTION_SCROLL_FORWARD defined in AccessibilityNodeInfo
// Add ACTION_SCROLL_BACKWARD
if (hasDecreaseAction)
- env->CallVoidMethod(node, m_addActionMethodID, (int)8192); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo
+ env->CallVoidMethod(node, m_addActionMethodID, (int)0x00002000); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo
//CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc)
@@ -332,6 +370,7 @@ if (!clazz) { \
GET_AND_CHECK_STATIC_METHOD(m_setCheckedMethodID, nodeInfoClass, "setChecked", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setClickableMethodID, nodeInfoClass, "setClickable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setContentDescriptionMethodID, nodeInfoClass, "setContentDescription", "(Ljava/lang/CharSequence;)V");
+ GET_AND_CHECK_STATIC_METHOD(m_setEditableMethodID, nodeInfoClass, "setEditable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setEnabledMethodID, nodeInfoClass, "setEnabled", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setFocusableMethodID, nodeInfoClass, "setFocusable", "(Z)V");
GET_AND_CHECK_STATIC_METHOD(m_setFocusedMethodID, nodeInfoClass, "setFocused", "(Z)V");
diff --git a/src/plugins/platforms/android/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h
index 508ed4462b..de9d32a099 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.h
+++ b/src/plugins/platforms/android/androidjniaccessibility.h
@@ -49,6 +49,9 @@ namespace QtAndroidAccessibility
void initialize();
bool isActive();
bool registerNatives(JNIEnv *env);
+ void notifyLocationChange();
+ void notifyObjectHide(uint accessibilityObjectId);
+ void notifyObjectFocus(uint accessibilityObjectId);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 9e2cb228b3..bdcfb0e258 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -203,6 +203,21 @@ namespace QtAndroid
QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
}
+ void notifyAccessibilityLocationChange()
+ {
+ QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyAccessibilityLocationChange");
+ }
+
+ void notifyObjectHide(uint accessibilityObjectId)
+ {
+ QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyObjectHide","(I)V", accessibilityObjectId);
+ }
+
+ void notifyObjectFocus(uint accessibilityObjectId)
+ {
+ QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass, "notifyObjectFocus","(I)V", accessibilityObjectId);
+ }
+
jobject createBitmap(QImage img, JNIEnv *env)
{
if (!m_bitmapClass)
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index 6902f89341..db7ba4367f 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -100,6 +100,10 @@ namespace QtAndroid
jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env);
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = nullptr);
+ void notifyAccessibilityLocationChange();
+ void notifyObjectHide(uint accessibilityObjectId);
+ void notifyObjectFocus(uint accessibilityObjectId);
+
const char *classErrorMsgFmt();
const char *methodErrorMsgFmt();
const char *qtTagText();
diff --git a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
index fdff9c3eba..30114b17a2 100644
--- a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
+++ b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
@@ -42,7 +42,6 @@
#include "androidjniaccessibility.h"
QT_BEGIN_NAMESPACE
-
QAndroidPlatformAccessibility::QAndroidPlatformAccessibility()
{
QtAndroidAccessibility::initialize();
@@ -51,9 +50,23 @@ QAndroidPlatformAccessibility::QAndroidPlatformAccessibility()
QAndroidPlatformAccessibility::~QAndroidPlatformAccessibility()
{}
-void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent */*event*/)
+void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- // FIXME send events
+ if (event == nullptr || !event->accessibleInterface())
+ return;
+
+ // We do not need implementation of all events, as current statues are polled
+ // by QtAccessibilityDelegate.java on every accessibility interaction.
+ // Currently we only send notification about the element's position change,
+ // so that the element can be moved on the screen if it's focused.
+
+ if (event->type() == QAccessible::LocationChanged) {
+ QtAndroidAccessibility::notifyLocationChange();
+ } else if (event->type() == QAccessible::ObjectHide) {
+ QtAndroidAccessibility::notifyObjectHide(event->uniqueId());
+ } else if (event->type() == QAccessible::Focus) {
+ QtAndroidAccessibility::notifyObjectFocus(event->uniqueId());
+ }
}
QT_END_NAMESPACE