43 #include "qpa/qplatformaccessibility.h"
44 #include <QtGui/private/qaccessiblebridgeutils_p.h>
48 #include "QtGui/qaccessible.h"
49 #include <QtCore/qmath.h>
50 #include <QtCore/private/qjnihelpers_p.h>
51 #include <QtCore/QJniObject>
52 #include <QtGui/private/qhighdpiscaling_p.h>
53 #include <QtCore/QObject>
55 static const char m_qtTag[] =
"Qt A11Y";
56 static const char m_classErrorMsg[] =
"Can't find class \"%s\"";
62 static jmethodID m_addActionMethodID = 0;
63 static jmethodID m_setCheckableMethodID = 0;
64 static jmethodID m_setCheckedMethodID = 0;
65 static jmethodID m_setClickableMethodID = 0;
66 static jmethodID m_setContentDescriptionMethodID = 0;
67 static jmethodID m_setEditableMethodID = 0;
68 static jmethodID m_setEnabledMethodID = 0;
69 static jmethodID m_setFocusableMethodID = 0;
70 static jmethodID m_setFocusedMethodID = 0;
71 static jmethodID m_setHeadingMethodID = 0;
72 static jmethodID m_setScrollableMethodID = 0;
73 static jmethodID m_setTextSelectionMethodID = 0;
74 static jmethodID m_setVisibleToUserMethodID = 0;
76 static bool m_accessibilityActivated =
false;
89 if (m_accessibilityContext)
94 template <
typename Func,
typename Ret>
103 "initializeAccessibility");
108 return m_accessibilityActivated;
111 static void setActive(JNIEnv *, jobject , jboolean active)
115 m_accessibilityActivated = active;
116 if (platformIntegration)
119 __android_log_print(ANDROID_LOG_WARN, m_qtTag,
"Could not (yet) activate platform accessibility.");
125 if (objectId == -1) {
128 iface =
win->accessibleRoot();
140 static int parentId_helper(
int objectId);
144 const auto parentObjectId = parentId_helper(accessibilityObjectId);
153 static jstring jvalueForAccessibleObject(
int objectId);
157 jstring
value = jvalueForAccessibleObject(accessibilityObjectId);
164 if (iface && iface->
isValid()) {
167 ifaceIdArray.
reserve(childCount);
168 for (
int i = 0;
i < childCount; ++
i) {
178 static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject , jint objectId)
180 if (m_accessibilityContext) {
183 return childIdListForAccessibleObject_helper(objectId);
185 jintArray jArray = env->NewIntArray(jsize(ifaceIdArray.
count()));
186 env->SetIntArrayRegion(jArray, 0, ifaceIdArray.
count(), ifaceIdArray.
data());
190 return env->NewIntArray(jsize(0));
193 static int parentId_helper(
int objectId)
196 if (iface && iface->
isValid()) {
207 static jint parentId(JNIEnv *, jobject , jint objectId)
210 if (m_accessibilityContext) {
212 return parentId_helper(objectId);
218 static QRect screenRect_helper(
int objectId)
222 if (iface && iface->
isValid()) {
228 rect =
rect.intersected(parentRect);
233 static jobject screenRect(JNIEnv *env, jobject , jint objectId)
236 if (m_accessibilityContext) {
238 return screenRect_helper(objectId);
241 jclass rectClass = env->FindClass(
"android/graphics/Rect");
242 jmethodID ctor = env->GetMethodID(rectClass,
"<init>",
"(IIII)V");
243 jobject jrect = env->NewObject(rectClass, ctor,
rect.left(),
rect.top(),
rect.right(),
rect.bottom());
247 static int hitTest_helper(
float x,
float y)
265 static jint hitTest(JNIEnv *, jobject , jfloat
x, jfloat
y)
268 if (m_accessibilityContext) {
270 return hitTest_helper(
x,
y);
286 static bool clickAction_helper(
int objectId)
306 static jboolean clickAction(JNIEnv *, jobject , jint objectId)
309 if (m_accessibilityContext) {
311 return clickAction_helper(objectId);
317 static bool scroll_helper(
int objectId,
const QString &actionName)
325 static jboolean scrollForward(JNIEnv *, jobject , jint objectId)
328 if (m_accessibilityContext) {
336 static jboolean scrollBackward(JNIEnv *, jobject , jint objectId)
339 if (m_accessibilityContext) {
348 #define FIND_AND_CHECK_CLASS(CLASS_NAME) \
349 clazz = env->FindClass(CLASS_NAME); \
351 __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
372 bool stepIsValid =
false;
387 const int stop =
count + 3;
388 const auto fractional = [](
double v) {
390 std::modf(
v + 0.5, &whole);
391 return qAbs(
v - whole);
396 s = fractional(
s * 10);
410 static jstring jvalueForAccessibleObject(
int objectId)
415 jstring jstr = env->NewString((jchar*)
value.constData(), (jsize)
value.size());
416 if (env.checkAndClearExceptions())
417 __android_log_print(ANDROID_LOG_WARN, m_qtTag,
"Failed to create jstring");
424 if (iface && iface->
isValid()) {
425 bool hasValue =
false;
429 if (
desc.isEmpty()) {
431 hasValue = !
desc.isEmpty();
434 const QString valueStr = textFromValue(iface);
438 desc.append(valueStr);
445 static QString descriptionForAccessibleObject_helper(
int objectId)
448 return descriptionForInterface(iface);
451 static jstring descriptionForAccessibleObject(JNIEnv *env, jobject , jint objectId)
454 if (m_accessibilityContext) {
456 return descriptionForAccessibleObject_helper(objectId);
459 return env->NewString((jchar*)
desc.constData(), (jsize)
desc.size());
475 static NodeInfo populateNode_helper(
int objectId)
479 if (iface && iface->
isValid()) {
484 info.description = descriptionForInterface(iface);
487 info.hasTextSelection =
true;
494 static jboolean populateNode(JNIEnv *env, jobject , jint objectId, jobject
node)
497 if (m_accessibilityContext) {
499 return populateNode_helper(objectId);
503 __android_log_print(ANDROID_LOG_WARN, m_qtTag,
"Accessibility: populateNode for Invalid ID");
507 const bool hasClickableAction =
510 const bool hasIncreaseAction =
512 const bool hasDecreaseAction =
515 if (
info.hasTextSelection && m_setTextSelectionMethodID) {
516 env->CallVoidMethod(
node, m_setTextSelectionMethodID,
info.selectionStart,
520 env->CallVoidMethod(
node, m_setCheckableMethodID, (
bool)
info.state.checkable);
521 env->CallVoidMethod(
node, m_setCheckedMethodID, (
bool)
info.state.checked);
522 env->CallVoidMethod(
node, m_setEditableMethodID,
info.state.editable);
523 env->CallVoidMethod(
node, m_setEnabledMethodID, !
info.state.disabled);
524 env->CallVoidMethod(
node, m_setFocusableMethodID, (
bool)
info.state.focusable);
525 env->CallVoidMethod(
node, m_setFocusedMethodID, (
bool)
info.state.focused);
526 if (m_setHeadingMethodID)
528 env->CallVoidMethod(
node, m_setVisibleToUserMethodID, !
info.state.invisible);
529 env->CallVoidMethod(
node, m_setScrollableMethodID, hasIncreaseAction || hasDecreaseAction);
533 if (hasClickableAction)
534 env->CallVoidMethod(
node, m_addActionMethodID, (
int)0x00000010);
537 if (hasIncreaseAction)
538 env->CallVoidMethod(
node, m_addActionMethodID, (
int)0x00001000);
541 if (hasDecreaseAction)
542 env->CallVoidMethod(
node, m_addActionMethodID, (
int)0x00002000);
545 jstring jdesc = env->NewString((jchar*)
info.description.constData(),
546 (jsize)
info.description.size());
548 env->CallVoidMethod(
node, m_setContentDescriptionMethodID, jdesc);
553 static JNINativeMethod methods[] = {
554 {
"setActive",
"(Z)V",(
void*)setActive},
555 {
"childIdListForAccessibleObject",
"(I)[I", (jintArray)childIdListForAccessibleObject},
556 {
"parentId",
"(I)I", (
void*)parentId},
557 {
"descriptionForAccessibleObject",
"(I)Ljava/lang/String;", (jstring)descriptionForAccessibleObject},
558 {
"screenRect",
"(I)Landroid/graphics/Rect;", (jobject)screenRect},
559 {
"hitTest",
"(FF)I", (
void*)hitTest},
560 {
"populateNode",
"(ILandroid/view/accessibility/AccessibilityNodeInfo;)Z", (
void*)populateNode},
561 {
"clickAction",
"(I)Z", (
void*)clickAction},
562 {
"scrollForward",
"(I)Z", (
void*)scrollForward},
563 {
"scrollBackward",
"(I)Z", (
void*)scrollBackward},
566 #define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
567 VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
569 __android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
577 jclass appClass =
static_cast<jclass
>(env->NewGlobalRef(clazz));
579 if (env->RegisterNatives(appClass, methods,
sizeof(methods) /
sizeof(methods[0])) < 0) {
580 __android_log_print(ANDROID_LOG_FATAL,
"Qt A11y",
"RegisterNatives failed");
584 jclass nodeInfoClass = env->FindClass(
"android/view/accessibility/AccessibilityNodeInfo");
589 GET_AND_CHECK_STATIC_METHOD(m_setContentDescriptionMethodID, nodeInfoClass,
"setContentDescription",
"(Ljava/lang/CharSequence;)V");
small capitals from c petite p scientific f u
small capitals from c petite p scientific i
[1]
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
The QAccessibleActionInterface class implements support for invocable actions in the interface.
static const QString & decreaseAction()
static const QString & toggleAction()
virtual QStringList actionNames() const =0
virtual void doAction(const QString &actionName)=0
static const QString & increaseAction()
static const QString & pressAction()
static Id uniqueId(QAccessibleInterface *iface)
static QAccessibleInterface * accessibleInterface(Id uniqueId)
The QAccessibleInterface class defines an interface that exposes information about accessible objects...
QAccessibleValueInterface * valueInterface()
virtual bool isValid() const =0
QAccessibleTextInterface * textInterface()
virtual QAccessible::Role role() const =0
virtual QAccessible::State state() const =0
virtual QAccessibleInterface * childAt(int x, int y) const =0
virtual QWindow * window() const
virtual int childCount() const =0
virtual QString text(QAccessible::Text t) const =0
QAccessibleActionInterface * actionInterface()
virtual QAccessibleInterface * parent() const =0
virtual QAccessibleInterface * child(int index) const =0
virtual QRect rect() const =0
The QAccessibleTextInterface class implements support for text handling.
virtual void selection(int selectionIndex, int *startOffset, int *endOffset) const =0
virtual int selectionCount() const =0
The QAccessibleValueInterface class implements support for objects that manipulate a value.
virtual QVariant minimumStepSize() const =0
virtual QVariant currentValue() const =0
The QChar class provides a 16-bit Unicode character.
The QJniEnvironment class provides access to the JNI Environment (JNIEnv).
The QMutexLocker class is a convenience class that simplifies locking and unlocking mutexes.
The QObject class is the base class of all Qt objects.
The QPoint class defines a point in the plane using integer precision.
The QRect class defines a rectangle in the plane using integer precision.
The QString class provides a Unicode character string.
static QString number(int, int base=10)
The QStringList class provides a list of strings.
void reserve(qsizetype sz)
The QVariant class acts like a union for the most common Qt data types.
double toDouble(bool *ok=nullptr) const
The QWindow class represents a window in the underlying windowing system.
backing_store_ptr info
[4]
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)
void notifyLocationChange(uint accessibilityObjectId)
void runInObjectContext(QObject *context, Func &&func, Ret *retVal)
bool registerNatives(JNIEnv *env)
void notifyObjectFocus(uint accessibilityObjectId)
QAccessibleInterface * interfaceFromId(jint objectId)
void createAccessibilityContextObject(QObject *parent)
void notifyObjectHide(uint accessibilityObjectId)
void notifyValueChanged(uint accessibilityObjectId)
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
QBasicMutex * platformInterfaceMutex()
QAndroidPlatformIntegration * androidPlatformIntegration()
void notifyObjectFocus(uint accessibilityObjectId)
void notifyValueChanged(uint accessibilityObjectId, jstring value)
jclass applicationClass()
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
Q_CORE_EXPORT jint androidSdkVersion()
@ BlockingQueuedConnection
EGLOutputLayerEXT EGLint EGLAttrib value
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum GLenum GLsizei count
GLenum GLint GLint * precision
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent