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>
18#include <QtCore/QObject>
19#include <QtCore/qvarlengtharray.h>
62 template <
typename Func,
typename Ret>
67 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
68 "Could not run accessibility call in object context, accessing "
69 "main thread could lead to deadlock");
77 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
78 "Could not run accessibility call in object context, event loop suspended.");
85 "initializeAccessibility");
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);
151 if (iface && iface->isValid()) {
152 const int childCount = iface->childCount();
154 ifaceIdArray.
reserve(childCount);
155 for (
int i = 0;
i < childCount; ++
i) {
156 QAccessibleInterface *
child = iface->child(
i);
172 jintArray jArray = env->NewIntArray(jsize(ifaceIdArray.
count()));
173 env->SetIntArrayRegion(jArray, 0, ifaceIdArray.
count(), ifaceIdArray.
data());
177 return env->NewIntArray(jsize(0));
183 if (iface && iface->isValid()) {
184 QAccessibleInterface *
parent = iface->parent();
186 if (
parent->role() == QAccessible::Application)
188 return QAccessible::uniqueId(
parent);
194 static jint
parentId(JNIEnv *, jobject , jint objectId)
209 if (iface && iface->isValid()) {
213 if (clip && iface && iface->parent() && iface->parent()->isValid()) {
215 rect =
rect.intersected(parentRect);
220 static jobject
screenRect(JNIEnv *env, jobject , jint objectId)
228 jclass rectClass = env->FindClass(
"android/graphics/Rect");
229 jmethodID ctor = env->GetMethodID(rectClass,
"<init>",
"(IIII)V");
230 jobject jrect = env->NewObject(rectClass, ctor,
rect.left(),
rect.top(),
rect.right(),
rect.bottom());
237 if (root && root->isValid()) {
240 QAccessibleInterface *
child = root->childAt(
pos.x(),
pos.y());
241 QAccessibleInterface *lastChild =
nullptr;
247 return QAccessible::uniqueId(lastChild);
252 static jint
hitTest(JNIEnv *, jobject , jfloat
x, jfloat
y)
269 actionInterface->doAction(action);
276 if (!iface || !iface->isValid() || !iface->actionInterface())
279 const auto& actionNames = iface->actionInterface()->actionNames();
281 if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
283 QAccessibleActionInterface::pressAction());
284 }
else if (actionNames.contains(QAccessibleActionInterface::toggleAction())) {
286 QAccessibleActionInterface::toggleAction());
307 if (iface && iface->isValid())
320 const int firstChildId =
ids.first();
325 return scroll_helper(objectId, QAccessibleActionInterface::increaseAction());
341 const int firstChildId =
ids.first();
346 return scroll_helper(objectId, QAccessibleActionInterface::decreaseAction());
355#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
356clazz = env->FindClass(CLASS_NAME); \
358 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
367 QAccessibleValueInterface *valueIface = iface->valueInterface();
369 const QVariant valueVar = valueIface->currentValue();
371 if (
type == QMetaType::Double ||
type == QMetaType::Float) {
379 bool stepIsValid =
false;
380 const double step =
qAbs(valueIface->minimumStepSize().toDouble(&stepIsValid));
394 const int stop =
count + 3;
395 const auto fractional = [](
double v) {
397 std::modf(
v + 0.5, &whole);
398 return qAbs(
v - whole);
403 s = fractional(
s * 10);
422 jstring jstr = env->NewString((jchar*)
value.constData(), (jsize)
value.size());
423 if (env.checkAndClearExceptions())
424 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
"Failed to create jstring");
431 if (iface && iface->isValid()) {
432 bool hasValue =
false;
433 desc = iface->text(QAccessible::Name);
435 desc = iface->text(QAccessible::Description);
436 if (
desc.isEmpty()) {
437 desc = iface->text(QAccessible::Value);
438 hasValue = !
desc.isEmpty();
440 if (!hasValue && iface->valueInterface()) {
445 desc.append(valueStr);
466 return env->NewString((jchar*)
desc.constData(), (jsize)
desc.size());
486 if (iface && iface->isValid()) {
488 info.state = iface->state();
489 info.role = iface->role();
492 QAccessibleTextInterface *textIface = iface->textInterface();
493 if (textIface && (textIface->selectionCount() > 0)) {
494 info.hasTextSelection =
true;
495 textIface->selection(0, &
info.selectionStart, &
info.selectionEnd);
501 static jboolean
populateNode(JNIEnv *env, jobject , jint objectId, jobject node)
510 __android_log_print(ANDROID_LOG_WARN,
m_qtTag,
"Accessibility: populateNode for Invalid ID");
514 const bool hasClickableAction =
515 info.actions.contains(QAccessibleActionInterface::pressAction()) ||
516 info.actions.contains(QAccessibleActionInterface::toggleAction());
517 const bool hasIncreaseAction =
518 info.actions.contains(QAccessibleActionInterface::increaseAction());
519 const bool hasDecreaseAction =
520 info.actions.contains(QAccessibleActionInterface::decreaseAction());
540 if (hasClickableAction)
544 if (hasIncreaseAction)
548 if (hasDecreaseAction)
552 jstring jdesc = env->NewString((jchar*)
info.description.constData(),
563 {
"parentId",
"(I)I", (
void*)
parentId},
565 {
"screenRect",
"(I)Landroid/graphics/Rect;", (jobject)
screenRect},
566 {
"hitTest",
"(FF)I", (
void*)
hitTest},
567 {
"populateNode",
"(ILandroid/view/accessibility/AccessibilityNodeInfo;)Z", (
void*)
populateNode},
573#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
574 VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
576 __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
584 jclass appClass =
static_cast<jclass
>(env->NewGlobalRef(clazz));
587 __android_log_print(ANDROID_LOG_FATAL,
"Qt A11y",
"RegisterNatives failed");
591 jclass nodeInfoClass = env->FindClass(
"android/view/accessibility/AccessibilityNodeInfo");
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
static const char m_classErrorMsg[]
static const char m_qtTag[]
qint64 size() const
Returns the file size in bytes.
static Qt::ApplicationState applicationState()
void deleteLater()
\threadsafe
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool isEmpty() const
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...
void reserve(qsizetype sz)
double toDouble(bool *ok=nullptr) const
Returns the variant as a double if the variant has userType() \l QMetaType::Double,...
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
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.
static bool clickAction_helper(int objectId)
void notifyLocationChange(uint accessibilityObjectId)
void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
static JNINativeMethod methods[]
static jmethodID m_setFocusableMethodID
static QPointer< QObject > m_accessibilityContext
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 jobject screenRect(JNIEnv *env, jobject, jint objectId)
static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject, jint objectId)
static jmethodID m_setVisibleToUserMethodID
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)
QAndroidPlatformIntegration * androidPlatformIntegration()
void notifyObjectFocus(uint accessibilityObjectId)
void notifyValueChanged(uint accessibilityObjectId, jstring value)
bool blockEventLoopsWhenSuspended()
jclass applicationClass()
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
QFileInfo info(fileName)
[8]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent