summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java24
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNative.java36
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java23
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java15
-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
-rw-r--r--src/widgets/accessible/complexwidgets.cpp15
-rw-r--r--src/widgets/accessible/itemviews.cpp17
11 files changed, 210 insertions, 20 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 35d86611c6..3785eb4011 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
@@ -159,6 +159,8 @@ public class QtActivityDelegate
private CursorHandle m_rightSelectionHandle;
private EditPopupMenu m_editPopupMenu;
+ private QtAccessibilityDelegate m_accessibilityDelegate = null;
+
public void setSystemUiVisibility(int systemUiVisibility)
{
@@ -876,10 +878,30 @@ public class QtActivityDelegate
m_splashScreen.startAnimation(fadeOut);
}
+ public void notifyAccessibilityLocationChange()
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyLocationChange();
+ }
+
+ public void notifyObjectHide(int viewId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectHide(viewId);
+ }
+
+ public void notifyObjectFocus(int viewId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectFocus(viewId);
+ }
public void initializeAccessibility()
{
- new QtAccessibilityDelegate(m_activity, m_layout, this);
+ m_accessibilityDelegate = new QtAccessibilityDelegate(m_activity, m_layout, this);
}
public void onWindowFocusChanged(boolean hasFocus) {
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 bd11b255f5..001e6a7970 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
@@ -934,6 +934,42 @@ public class QtNative
});
}
+ private static void notifyAccessibilityLocationChange()
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ if (m_activityDelegate != null) {
+ m_activityDelegate.notifyAccessibilityLocationChange();
+ }
+ }
+ });
+ }
+
+ private static void notifyObjectHide(final int viewId)
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ if (m_activityDelegate != null) {
+ m_activityDelegate.notifyObjectHide(viewId);
+ }
+ }
+ });
+ }
+
+ private static void notifyObjectFocus(final int viewId)
+ {
+ runAction(new Runnable() {
+ @Override
+ public void run() {
+ if (m_activityDelegate != null) {
+ m_activityDelegate.notifyObjectFocus(viewId);
+ }
+ }
+ });
+ }
+
private static void registerClipboardManager()
{
if (m_service == null || m_activity != null) { // Avoid freezing if only service
diff --git a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java
index 1591a5b52e..57b43bc279 100644
--- a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java
@@ -191,6 +191,23 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return true;
}
+ public void notifyLocationChange()
+ {
+ invalidateVirtualViewId(m_focusedVirtualViewId);
+ }
+
+ public void notifyObjectHide(int viewId)
+ {
+ invalidateVirtualViewId(viewId);
+ }
+
+ public void notifyObjectFocus(int viewId)
+ {
+ m_view.invalidate();
+ sendEventForVirtualViewId(viewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ }
+
public boolean sendEventForVirtualViewId(int virtualViewId, int eventType)
{
if ((virtualViewId == INVALID_ID) || !m_manager.isEnabled()) {
@@ -211,7 +228,8 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
public void invalidateVirtualViewId(int virtualViewId)
{
- sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ if (virtualViewId != INVALID_ID)
+ sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
}
private void setHoveredVirtualViewId(int virtualViewId)
@@ -336,9 +354,6 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
}
- int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId);
- for (int i = 0; i < ids.length; ++i)
- node.addChild(m_view, ids[i]);
return node;
}
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 1b34658300..a4e6df058d 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
@@ -1116,4 +1116,19 @@ public class QtActivity extends Activity
{
QtNative.activityDelegate().updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
}
+
+ public void notifyAccessibilityLocationChange()
+ {
+ QtNative.activityDelegate().notifyAccessibilityLocationChange();
+ }
+
+ public void notifyObjectHide(int viewId)
+ {
+ QtNative.activityDelegate().notifyObjectHide(viewId);
+ }
+
+ public void notifyObjectFocus(int viewId)
+ {
+ QtNative.activityDelegate().notifyObjectFocus(viewId);
+ }
}
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
diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp
index 42074b63fb..ab543a79df 100644
--- a/src/widgets/accessible/complexwidgets.cpp
+++ b/src/widgets/accessible/complexwidgets.cpp
@@ -400,9 +400,24 @@ void QAccessibleComboBox::doAction(const QString &actionName)
{
if (actionName == showMenuAction() || actionName == pressAction()) {
if (comboBox()->view()->isVisible()) {
+#if defined(Q_OS_ANDROID)
+ const auto list = child(0)->tableInterface();
+ if (list && list->selectedRowCount() > 0) {
+ comboBox()->setCurrentIndex(list->selectedRows().at(0));
+ }
+ comboBox()->setFocus();
+#endif
comboBox()->hidePopup();
} else {
comboBox()->showPopup();
+#if defined(Q_OS_ANDROID)
+ const auto list = child(0)->tableInterface();
+ if (list && list->selectedRowCount() > 0) {
+ auto selectedCells = list->selectedCells();
+ QAccessibleEvent ev(selectedCells.at(0),QAccessible::Focus);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
}
}
diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp
index 677e56806a..a7b536ae54 100644
--- a/src/widgets/accessible/itemviews.cpp
+++ b/src/widgets/accessible/itemviews.cpp
@@ -934,10 +934,23 @@ QStringList QAccessibleTableCell::actionNames() const
void QAccessibleTableCell::doAction(const QString& actionName)
{
if (actionName == toggleAction()) {
- if (isSelected())
+#if defined(Q_OS_ANDROID)
+ QAccessibleInterface *parentInterface = parent();
+ while (parentInterface){
+ if (parentInterface->role() == QAccessible::ComboBox) {
+ selectCell();
+ parentInterface->actionInterface()->doAction(pressAction());
+ return;
+ } else {
+ parentInterface = parentInterface->parent();
+ }
+ }
+#endif
+ if (isSelected()) {
unselectCell();
- else
+ } else {
selectCell();
+ }
}
}