From 2d88b05376092c65b0e62d7ad6a40073e415c5f9 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Fri, 25 Oct 2024 16:22:24 +0300 Subject: [PATCH] Android: move QtAccessibilityDelegate instance to QtActivityDelegateBase Similar to the display manager and the input delegate, keep the accessibility delegate under the base class. Also, following the same pattern as in the parent patch, assign a default instance for this in the delegate in the constructor, and initialize anything later when needed. Also, make sure calls for various objects under the QtAccessibilityDelegate are safe and guarded. Task-number: QTBUG-129704 Change-Id: I14a57d8e0916127ae8fa00acb3265b92803087dc Reviewed-by: Petri Virkkunen (cherry picked from commit af73c7a99eeea346efb65bed1d6e643e74ef33a6) Reviewed-by: Qt Cherry-pick Bot --- .../qt/android/QtAccessibilityDelegate.java | 43 ++++++++++++++----- .../qt/android/QtActivityDelegate.java | 30 +++---------- .../qt/android/QtActivityDelegateBase.java | 6 +++ 3 files changed, 46 insertions(+), 33 deletions(-) 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;