Android: Implement accessibility backend interface

This will provide the JNI API used by QtAndroidAccessibility namespace
via QtAndroid namespace.

Removed unnecessary functions like createAccessibilityDelegate from
QtEmbeddedDelegate, moved the interface extension to where it is
actually supported: QtActivityDelegate.

Until now, QtActivityDelegateBase has called the QtEmbeddedDelegate
implementation on createAccessibilityDelegate() in order to create a
QtAccessibilityDelegate - which has not actually created the delegate -
and then done a null check before trying to call the - always null -
QtAccessibilityDelegate member.

The embedding and service-embedding usecases are now dealt with via the
interface validity checks on the C++ side, until an actual
implementation for those is completed.

Task-number: QTBUG-118874
Change-Id: Iea3db0e17ae80c0443e9027bdfe36bba311eed2b
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Petri Virkkunen 2024-03-27 16:05:20 +02:00
parent 46a23b1fae
commit 2322c71cc7
10 changed files with 94 additions and 88 deletions

View File

@ -42,6 +42,7 @@ set(java_sources
src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
src/org/qtproject/qt/android/BackendRegister.java
src/org/qtproject/qt/android/QtWindowInterface.java
src/org/qtproject/qt/android/QtAccessibilityInterface.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android

View File

@ -61,6 +61,8 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate
}
// TODO do we want to have one QtAccessibilityDelegate for the whole app (QtRootLayout) or
// e.g. one per window?
// FIXME make QtAccessibilityDelegate window based or verify current way works
// also for child windows: QTBUG-120685
public QtAccessibilityDelegate(QtLayout layout)
{
m_layout = layout;

View File

@ -0,0 +1,14 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
@UsedFromNativeCode
public interface QtAccessibilityInterface {
default void initializeAccessibility() { }
default void notifyLocationChange(int viewId) { }
default void notifyObjectHide(int viewId, int parentId) { }
default void notifyObjectFocus(int viewId) { }
default void notifyScrolledEvent(int viewId) { }
default void notifyValueChanged(int viewId, String value) { }
default void notifyObjectShow(int parentId) { }
}

View File

@ -31,7 +31,8 @@ import android.widget.PopupMenu;
import java.util.HashMap;
class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInterface
class QtActivityDelegate
extends QtActivityDelegateBase implements QtWindowInterface, QtAccessibilityInterface
{
private static final String QtTAG = "QtActivityDelegate";
@ -42,7 +43,7 @@ class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInter
private View m_dummyView = null;
private HashMap<Integer, View> m_nativeViews = new HashMap<Integer, View>();
private QtAccessibilityDelegate m_accessibilityDelegate = null;
QtActivityDelegate(Activity activity)
{
@ -58,6 +59,8 @@ class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInter
m_backendsRegistered = true;
BackendRegister.registerBackend(QtWindowInterface.class,
(QtWindowInterface)QtActivityDelegate.this);
BackendRegister.registerBackend(QtAccessibilityInterface.class,
(QtAccessibilityInterface)QtActivityDelegate.this);
}
}
@ -66,6 +69,7 @@ class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInter
if (m_backendsRegistered) {
m_backendsRegistered = false;
BackendRegister.unregisterBackend(QtWindowInterface.class);
BackendRegister.unregisterBackend(QtAccessibilityInterface.class);
}
}
@ -226,7 +230,55 @@ class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInter
});
}
@UsedFromNativeCode
@Override
public void notifyLocationChange(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyLocationChange(viewId);
}
@Override
public void notifyObjectHide(int viewId, int parentId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
}
@Override
public void notifyObjectShow(int parentId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectShow(parentId);
}
@Override
public void notifyObjectFocus(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectFocus(viewId);
}
@Override
public void notifyValueChanged(int viewId, String value)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyValueChanged(viewId, value);
}
@Override
public void notifyScrolledEvent(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyScrolledEvent(viewId);
}
@Override
public void initializeAccessibility()
{
QtNative.runAction(() -> {
@ -362,16 +414,6 @@ class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInter
});
}
@Override
QtAccessibilityDelegate createAccessibilityDelegate()
{
if (m_layout != null)
return new QtAccessibilityDelegate(m_layout);
Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate.");
return null;
}
private void setActivityBackgroundDrawable()
{
TypedValue attr = new TypedValue();

View File

@ -37,7 +37,6 @@ abstract class QtActivityDelegateBase
{
protected Activity m_activity;
protected HashMap<Integer, QtWindow> m_topLevelWindows;
protected QtAccessibilityDelegate m_accessibilityDelegate = null;
protected QtDisplayManager m_displayManager = null;
protected QtInputDelegate m_inputDelegate = null;
@ -46,7 +45,6 @@ abstract class QtActivityDelegateBase
// Subclass must implement these
abstract void startNativeApplicationImpl(String appParams, String mainLib);
abstract QtAccessibilityDelegate createAccessibilityDelegate();
abstract QtLayout getQtLayout();
// With these we are okay with default implementation doing nothing
@ -153,62 +151,6 @@ abstract class QtActivityDelegateBase
hideSplashScreen(0);
}
@UsedFromNativeCode
public void notifyLocationChange(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyLocationChange(viewId);
}
@UsedFromNativeCode
public void notifyObjectHide(int viewId, int parentId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
}
@UsedFromNativeCode
public void notifyObjectShow(int parentId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectShow(parentId);
}
@UsedFromNativeCode
public void notifyObjectFocus(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyObjectFocus(viewId);
}
@UsedFromNativeCode
public void notifyValueChanged(int viewId, String value)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyValueChanged(viewId, value);
}
@UsedFromNativeCode
public void notifyScrolledEvent(int viewId)
{
if (m_accessibilityDelegate == null)
return;
m_accessibilityDelegate.notifyScrolledEvent(viewId);
}
@UsedFromNativeCode
public void initializeAccessibility()
{
QtNative.runAction(() -> {
m_accessibilityDelegate = createAccessibilityDelegate();
});
}
void handleUiModeChange(int uiMode)
{
// QTBUG-108365

View File

@ -122,14 +122,6 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
QtNative.startApplication(appParams, mainLib);
}
@Override
QtAccessibilityDelegate createAccessibilityDelegate()
{
// FIXME make QtAccessibilityDelegate window based or verify current way works
// also for child windows: QTBUG-120685
return null;
}
@UsedFromNativeCode
@Override
QtLayout getQtLayout()

View File

@ -28,6 +28,7 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App
m_service = service;
QtNative.registerAppStateListener(this);
QtNative.setService(service);
// QTBUG-122920 TODO Implement accessibility for service UIs
}
@UsedFromNativeCode

View File

@ -82,7 +82,7 @@ namespace QtAndroidAccessibility
void initialize()
{
QtAndroid::qtActivityDelegate().callMethod<void>("initializeAccessibility");
QtAndroid::initializeAccessibility();
}
bool isActive()

View File

@ -95,6 +95,7 @@ Q_CONSTINIT static QBasicAtomicInt startQtAndroidPluginCalled = Q_BASIC_ATOMIC_I
Q_DECLARE_JNI_CLASS(QtEmbeddedDelegateFactory, "org/qtproject/qt/android/QtEmbeddedDelegateFactory")
Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
Q_DECLARE_JNI_CLASS(QtAccessibilityInterface, "org/qtproject/qt/android/QtAccessibilityInterface");
namespace QtAndroid
{
@ -237,36 +238,46 @@ namespace QtAndroid
return true;
}
void initializeAccessibility()
{
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"initializeAccessibility");
}
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
{
qtActivityDelegate().callMethod<void>("notifyLocationChange", accessibilityObjectId);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyLocationChange", accessibilityObjectId);
}
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
{
qtActivityDelegate().callMethod<void>("notifyObjectHide",
accessibilityObjectId, parentObjectId);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyObjectHide", accessibilityObjectId, parentObjectId);
}
void notifyObjectShow(uint parentObjectId)
{
qtActivityDelegate().callMethod<void>("notifyObjectShow",
parentObjectId);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyObjectShow", parentObjectId);
}
void notifyObjectFocus(uint accessibilityObjectId)
{
qtActivityDelegate().callMethod<void>("notifyObjectFocus", accessibilityObjectId);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyObjectFocus", accessibilityObjectId);
}
void notifyValueChanged(uint accessibilityObjectId, jstring value)
{
qtActivityDelegate().callMethod<void>("notifyValueChanged", accessibilityObjectId, value);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyValueChanged", accessibilityObjectId, value);
}
void notifyScrolledEvent(uint accessibilityObjectId)
{
qtActivityDelegate().callMethod<void>("notifyScrolledEvent", accessibilityObjectId);
m_backendRegister->callInterface<QtJniTypes::QtAccessibilityInterface, void>(
"notifyScrolledEvent", accessibilityObjectId);
}
void notifyNativePluginIntegrationReady(bool ready)

View File

@ -65,6 +65,7 @@ namespace QtAndroid
jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env);
jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = nullptr);
void initializeAccessibility();
void notifyAccessibilityLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId);
void notifyObjectShow(uint parentObjectId);