8#include "qpa/qplatformaccessibility.h"
9#include <QtGui/private/qaccessiblebridgeutils_p.h>
13#include "QtGui/qaccessible.h"
14#include <QtCore/qmath.h>
15#include <QtCore/private/qjnihelpers_p.h>
16#include <QtCore/QJniObject>
17#include <QtGui/private/qhighdpiscaling_p.h>
19#include <QtCore/QObject>
20#include <QtCore/qpointer.h>
21#include <QtCore/qvarlengtharray.h>
63 template <
typename Func,
typename Ret>
67 if (!protector.acquire()) {
68 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
69 "Could not run accessibility call in object context, accessing "
70 "main thread could lead to deadlock");
78 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
79 "Could not run accessibility call in object context, event loop suspended.");
93 static void setActive(JNIEnv *, jobject , jboolean active)
98 if (platformIntegration)
99 platformIntegration->accessibility()->setActive(active);
101 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
"Could not (yet) activate platform accessibility.");
106 QAccessibleInterface *iface =
nullptr;
107 if (objectId == -1) {
110 iface =
win->accessibleRoot();
112 iface = QAccessible::accessibleInterface(objectId);
157 if (iface && iface->isValid()) {
158 const int childCount = iface->childCount();
159 QVarLengthArray<jint, 8> ifaceIdArray;
160 ifaceIdArray.reserve(childCount);
161 for (
int i = 0;
i < childCount; ++
i) {
162 QAccessibleInterface *
child = iface->child(
i);
164 ifaceIdArray.append(QAccessible::uniqueId(
child));
174 QVarLengthArray<jint, 8> ifaceIdArray;
178 jintArray jArray = env->NewIntArray(jsize(ifaceIdArray.count()));
179 env->SetIntArrayRegion(jArray, 0, ifaceIdArray.count(), ifaceIdArray.data());
183 return env->NewIntArray(jsize(0));
189 if (iface && iface->isValid()) {
190 QAccessibleInterface *parent = iface->parent();
191 if (parent && parent->isValid()) {
192 if (parent->role() == QAccessible::Application)
194 return QAccessible::uniqueId(parent);
200 static jint
parentId(JNIEnv *, jobject , jint objectId)
215 if (iface && iface->isValid()) {
219 if (clip && iface && iface->parent() && iface->parent()->isValid()) {
221 rect =
rect.intersected(parentRect);
226 static jobject
screenRect(JNIEnv *env, jobject , jint objectId)
234 jclass rectClass = env->FindClass(
"android/graphics/Rect");
235 jmethodID ctor = env->GetMethodID(rectClass,
"<init>",
"(IIII)V");
236 jobject jrect = env->NewObject(rectClass, ctor,
rect.left(),
rect.top(),
rect.right(),
rect.bottom());
243 if (root && root->isValid()) {
246 QAccessibleInterface *
child = root->childAt(
pos.x(),
pos.y());
247 QAccessibleInterface *lastChild =
nullptr;
253 return QAccessible::uniqueId(lastChild);
258 static jint
hitTest(JNIEnv *, jobject , jfloat
x, jfloat
y)
275 actionInterface->doAction(action);
282 if (!iface || !iface->isValid() || !iface->actionInterface())
285 const auto& actionNames = iface->actionInterface()->actionNames();
287 if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
289 QAccessibleActionInterface::pressAction());
290 }
else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
292 QAccessibleActionInterface::toggleAction());
313 if (iface && iface->isValid())
326 const int firstChildId =
ids.first();
331 return scroll_helper(objectId, QAccessibleActionInterface::increaseAction());
347 const int firstChildId =
ids.first();
352 return scroll_helper(objectId, QAccessibleActionInterface::decreaseAction());
363 QAccessibleValueInterface *valueIface = iface->valueInterface();
365 const QVariant valueVar = valueIface->currentValue();
367 if (
type == QMetaType::Double ||
type == QMetaType::Float) {
373 const double val = valueVar.toDouble();
375 bool stepIsValid =
false;
376 const double step =
qAbs(valueIface->minimumStepSize().toDouble(&stepIsValid));
390 const int stop =
count + 3;
391 const auto fractional = [](
double v) {
393 std::modf(
v + 0.5, &whole);
394 return qAbs(
v - whole);
399 s = fractional(
s * 10);
407 valueStr = valueVar.toString();
418 jstring jstr = env->NewString((jchar*)
value.constData(), (jsize)
value.size());
419 if (env.checkAndClearExceptions())
420 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
"Failed to create jstring");
427 if (iface && iface->isValid()) {
428 bool hasValue =
false;
429 desc = iface->text(QAccessible::Name);
431 desc = iface->text(QAccessible::Description);
432 if (desc.isEmpty()) {
433 desc = iface->text(QAccessible::Value);
434 hasValue = !desc.isEmpty();
436 if (!hasValue && iface->valueInterface()) {
440 desc.append(
QChar(QChar::Space));
441 desc.append(valueStr);
462 return env->NewString((jchar*) desc.constData(), (jsize) desc.size());
482 if (iface && iface->isValid()) {
484 info.state = iface->state();
485 info.role = iface->role();
488 QAccessibleTextInterface *textIface = iface->textInterface();
489 if (textIface && (textIface->selectionCount() > 0)) {
490 info.hasTextSelection =
true;
491 textIface->selection(0, &
info.selectionStart, &
info.selectionEnd);
497 static jboolean
populateNode(JNIEnv *env, jobject , jint objectId, jobject node)
506 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
"Accessibility: populateNode for Invalid ID");
510 const bool hasClickableAction =
511 info.actions.contains(QAccessibleActionInterface::pressAction()) ||
512 info.actions.contains(QAccessibleActionInterface::toggleAction());
513 const bool hasIncreaseAction =
514 info.actions.contains(QAccessibleActionInterface::increaseAction());
515 const bool hasDecreaseAction =
516 info.actions.contains(QAccessibleActionInterface::decreaseAction());
536 if (hasClickableAction)
540 if (hasIncreaseAction)
544 if (hasDecreaseAction)
548 jstring jdesc = env->NewString((jchar*)
info.description.constData(),
549 (jsize)
info.description.size());
559 {
"parentId",
"(I)I", (
void*)
parentId},
561 {
"screenRect",
"(I)Landroid/graphics/Rect;", (jobject)
screenRect},
562 {
"hitTest",
"(FF)I", (
void*)
hitTest},
563 {
"populateNode",
"(ILandroid/view/accessibility/AccessibilityNodeInfo;)Z", (
void*)
populateNode},
569#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
570 VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
572 __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
578 if (!env.registerNativeMethods(
"org/qtproject/qt/android/QtNativeAccessibility",
580 __android_log_print(ANDROID_LOG_FATAL,
"Qt A11y",
"RegisterNatives failed");
584 jclass nodeInfoClass = env->FindClass(
"android/view/accessibility/AccessibilityNodeInfo");
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
static const char m_qtTag[]
static Qt::ApplicationState applicationState()
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
int typeId() const
Returns the storage type of the value stored in the variant.
static bool registerNatives()
QStringList effectiveActionNames(QAccessibleInterface *iface)
bool performEffectiveAction(QAccessibleInterface *iface, const QString &actionName)
T toNativePixels(const T &value, const C *context)
T fromNativePixels(const T &value, const C *context)
Combined button and popup list for selecting options.
void notifyObjectShow(uint accessibilityObjectId)
static bool clickAction_helper(int objectId)
void notifyLocationChange(uint accessibilityObjectId)
void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
static jmethodID m_setFocusableMethodID
static jboolean scrollForward(JNIEnv *, jobject, jint objectId)
static jmethodID m_addActionMethodID
static jmethodID m_setEditableMethodID
static jmethodID m_setClickableMethodID
static bool m_accessibilityActivated
void notifyObjectFocus(uint accessibilityObjectId)
static jboolean scrollBackward(JNIEnv *, jobject, jint objectId)
static QString descriptionForInterface(QAccessibleInterface *iface)
static int hitTest_helper(float x, float y)
static jmethodID m_setTextSelectionMethodID
static jstring descriptionForAccessibleObject(JNIEnv *env, jobject, jint objectId)
static bool scroll_helper(int objectId, const QString &actionName)
static jmethodID m_setFocusedMethodID
static QString textFromValue(QAccessibleInterface *iface)
void createAccessibilityContextObject(QObject *parent)
static QVarLengthArray< int, 8 > childIdListForAccessibleObject_helper(int objectId)
static NodeInfo populateNode_helper(int objectId)
void notifyObjectHide(uint accessibilityObjectId)
static jmethodID m_setCheckedMethodID
static jmethodID m_setScrollableMethodID
static jint hitTest(JNIEnv *, jobject, jfloat x, jfloat y)
static jboolean clickAction(JNIEnv *, jobject, jint objectId)
static jstring jvalueForAccessibleObject(int objectId)
static jmethodID m_setHeadingMethodID
static void setActive(JNIEnv *, jobject, jboolean active)
static void invokeActionOnInterfaceInMainThread(QAccessibleActionInterface *actionInterface, const QString &action)
QAccessibleInterface * interfaceFromId(jint objectId)
void notifyValueChanged(uint accessibilityObjectId)
static int parentId_helper(int objectId)
static QRect screenRect_helper(int objectId, bool clip=true)
static jmethodID m_setContentDescriptionMethodID
static QString descriptionForAccessibleObject_helper(int objectId)
static jint parentId(JNIEnv *, jobject, jint objectId)
static const JNINativeMethod methods[]
static jobject screenRect(JNIEnv *env, jobject, jint objectId)
static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject, jint objectId)
static jmethodID m_setVisibleToUserMethodID
static Q_CONSTINIT QPointer< QObject > m_accessibilityContext
static jmethodID m_setCheckableMethodID
static jboolean populateNode(JNIEnv *env, jobject, jint objectId, jobject node)
void notifyScrolledEvent(uint accessiblityObjectId)
static jmethodID m_setEnabledMethodID
Q_CORE_EXPORT jint androidSdkVersion()
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
QBasicMutex * platformInterfaceMutex()
void notifyScrolledEvent(uint accessibilityObjectId)
void notifyObjectShow(uint parentObjectId)
QtJniTypes::QtActivityDelegateBase qtActivityDelegate()
QAndroidPlatformIntegration * androidPlatformIntegration()
void notifyObjectFocus(uint accessibilityObjectId)
void notifyValueChanged(uint accessibilityObjectId, jstring value)
bool blockEventLoopsWhenSuspended()
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
@ BlockingQueuedConnection
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
constexpr T qAbs(const T &t)
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum GLenum GLsizei const GLuint * ids
GLenum GLenum GLsizei count
GLenum GLint GLint * precision