diff --git a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java index 2c25febb4d1..2d44a8d4db9 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java @@ -35,8 +35,8 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate private static final String DEFAULT_CLASS_NAME = "$VirtualChild"; private View m_view = null; - private final AccessibilityManager m_manager; - private final QtLayout m_layout; + private AccessibilityManager m_manager; + private QtLayout m_layout; // The accessible object that currently has the "accessibility focus" // usually indicated by a yellow rectangle on screen. @@ -63,11 +63,16 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // e.g. one per window? // FIXME make QtAccessibilityDelegate window based or verify current way works // also for child windows: QTBUG-120685 - QtAccessibilityDelegate(QtLayout layout) + QtAccessibilityDelegate() { } + + void initLayoutAccessibility(QtLayout layout) { + if (m_layout == null) + Log.w(TAG, "Unable to initialize the accessibility delegate with a null layout"); + m_layout = layout; - m_manager = (AccessibilityManager) m_layout.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + m_manager = m_layout.getContext().getSystemService(AccessibilityManager.class); if (m_manager != null) { AccessibilityManagerListener accServiceListener = new AccessibilityManagerListener(); if (!m_manager.addAccessibilityStateChangeListener(accServiceListener)) @@ -82,7 +87,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate @Override public void onAccessibilityStateChanged(boolean enabled) { - if (Os.getenv("QT_ANDROID_DISABLE_ACCESSIBILITY") != null) + if (m_layout == null || Os.getenv("QT_ANDROID_DISABLE_ACCESSIBILITY") != null) return; if (enabled) { try { @@ -136,7 +141,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // (user moves finger over screen to discover items on screen). private boolean dispatchHoverEvent(MotionEvent event) { - if (!m_manager.isTouchExplorationEnabled()) { + if (m_manager == null || !m_manager.isTouchExplorationEnabled()) { return false; } @@ -177,7 +182,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // Note: This code is mostly copied from // AccessibilityNodeProvider::performAction, but we remove the // focus only if the focused view id matches the one that was hidden. - if (m_focusedVirtualViewId == viewId) { + if (m_view != null && m_focusedVirtualViewId == viewId) { m_focusedVirtualViewId = INVALID_ID; m_view.invalidate(); sendEventForVirtualViewId(viewId, @@ -212,7 +217,13 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate void notifyValueChanged(int viewId, String value) { + if (m_manager == null) + return; + QtNative.runAction(() -> { + if (m_view == null) + return; + // Send a TYPE_ANNOUNCEMENT event with the new value if ((viewId == INVALID_ID) || !m_manager.isEnabled()) { @@ -255,7 +266,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate void sendAccessibilityEvent(AccessibilityEvent event) { - if (event == null) + if (m_view == null || event == null) return; final ViewGroup group = (ViewGroup) m_view.getParent(); @@ -292,12 +303,13 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate private AccessibilityEvent getEventForVirtualViewId(int virtualViewId, int eventType) { - if ((virtualViewId == INVALID_ID) || !m_manager.isEnabled()) { + final boolean isManagerEnabled = m_manager != null && m_manager.isEnabled(); + if (m_view == null || !isManagerEnabled || (virtualViewId == INVALID_ID)) { Log.w(TAG, "getEventForVirtualViewId for invalid view"); return null; } - if (m_layout.getChildCount() == 0) + if (m_layout == null || m_layout.getChildCount() == 0) return null; final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); @@ -330,6 +342,9 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate private AccessibilityNodeInfo getNodeForView() { + if (m_view == null || m_layout == null) + return AccessibilityNodeInfo.obtain(); + // Since we don't want the parent to be focusable, but we can't remove // actions from a node, copy over the necessary fields. final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(m_view); @@ -391,6 +406,9 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate private AccessibilityNodeInfo getNodeForVirtualViewId(int virtualViewId) { + if (m_view == null || m_layout == null) + return AccessibilityNodeInfo.obtain(); + final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); @@ -456,6 +474,11 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate @Override public boolean performAction(int virtualViewId, int action, Bundle arguments) { + if (m_view == null) { + Log.e(TAG, "Unable to perform action with a null view"); + return false; + } + boolean handled = false; //Log.i(TAG, "PERFORM ACTION: " + action + " on " + virtualViewId); switch (action) { 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 cca26fb31e3..3310f85e083 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -43,7 +43,6 @@ class QtActivityDelegate extends QtActivityDelegateBase private View m_dummyView = null; private final HashMap m_nativeViews = new HashMap<>(); - private QtAccessibilityDelegate m_accessibilityDelegate = null; QtActivityDelegate(Activity activity) { @@ -248,49 +247,37 @@ class QtActivityDelegate extends QtActivityDelegateBase @Override public void notifyLocationChange(int viewId) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyLocationChange(viewId); + getAccessibilityDelegate().notifyLocationChange(viewId); } @Override public void notifyObjectHide(int viewId, int parentId) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectHide(viewId, parentId); + getAccessibilityDelegate().notifyObjectHide(viewId, parentId); } @Override public void notifyObjectShow(int parentId) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectShow(parentId); + getAccessibilityDelegate().notifyObjectShow(parentId); } @Override public void notifyObjectFocus(int viewId) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectFocus(viewId); + getAccessibilityDelegate().notifyObjectFocus(viewId); } @Override public void notifyValueChanged(int viewId, String value) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyValueChanged(viewId, value); + getAccessibilityDelegate().notifyValueChanged(viewId, value); } @Override public void notifyScrolledEvent(int viewId) { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyScrolledEvent(viewId); + getAccessibilityDelegate().notifyScrolledEvent(viewId); } @Override @@ -298,10 +285,7 @@ class QtActivityDelegate extends QtActivityDelegateBase { QtNative.runAction(() -> { // FIXME make QtAccessibilityDelegate window based - if (m_layout != null) - m_accessibilityDelegate = new QtAccessibilityDelegate(m_layout); - else - Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate."); + getAccessibilityDelegate().initLayoutAccessibility(m_layout); }); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java index bd5568fb93f..1b1c40c1fe0 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java @@ -41,6 +41,7 @@ abstract class QtActivityDelegateBase protected final HashMap m_topLevelWindows = new HashMap<>(); protected final QtDisplayManager m_displayManager; protected final QtInputDelegate m_inputDelegate; + private final QtAccessibilityDelegate m_accessibilityDelegate; private boolean m_membersInitialized = false; private boolean m_contextMenuVisible = false; @@ -60,6 +61,7 @@ abstract class QtActivityDelegateBase QtNative.setActivity(m_activity); m_displayManager = new QtDisplayManager(m_activity); m_inputDelegate = new QtInputDelegate(m_displayManager::updateFullScreen); + m_accessibilityDelegate = new QtAccessibilityDelegate(); } QtDisplayManager displayManager() { @@ -70,6 +72,10 @@ abstract class QtActivityDelegateBase return m_inputDelegate; } + QtAccessibilityDelegate getAccessibilityDelegate() { + return m_accessibilityDelegate; + } + void setContextMenuVisible(boolean contextMenuVisible) { m_contextMenuVisible = contextMenuVisible;