Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 068c66c7 authored by Daniel Norman's avatar Daniel Norman
Browse files

Make AM#isEnabled() true if any direct a11y connection exists.

Includes @TestApi AM#hasAnyDirectConnection() to improve test
reliability, because directly testing AM#isEnabled() is muddied
by UiAutomation used in the test itself.

Bug: 249164232
Test: atest AccessibilityEndToEndTest
Test: check node tree of a WebView when no real a11y service
      is enabled.
Change-Id: I4931ce316e9f5a956d266b7fd99f0faf00b8cd0d
parent bdf75500
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2961,6 +2961,7 @@ package android.view.accessibility {

  public final class AccessibilityManager {
    method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public java.util.List<java.lang.String> getAccessibilityShortcutTargets(int);
    method public boolean hasAnyDirectConnection();
  }

  public class AccessibilityNodeInfo implements android.os.Parcelable {
+4 −0
Original line number Diff line number Diff line
@@ -10499,6 +10499,8 @@ public final class ViewRootImpl implements ViewParent,
            if (mDirectConnectionId == AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
                mDirectConnectionId = AccessibilityInteractionClient.addDirectConnection(
                        new AccessibilityInteractionConnection(ViewRootImpl.this));
                // Notify listeners in the app process.
                mAccessibilityManager.notifyAccessibilityStateChanged();
            }
            return mDirectConnectionId;
        }
@@ -10507,6 +10509,8 @@ public final class ViewRootImpl implements ViewParent,
            if (mDirectConnectionId != AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID) {
                AccessibilityInteractionClient.removeConnection(mDirectConnectionId);
                mDirectConnectionId = AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
                // Notify listeners in the app process.
                mAccessibilityManager.notifyAccessibilityStateChanged();
            }
        }
    }
+10 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ public final class AccessibilityInteractionClient
    // Used to generate connection ids for direct app-process connections. Start sufficiently far
    // enough from the connection ids generated by AccessibilityManagerService.
    private static int sDirectConnectionIdCounter = 1 << 30;
    private static int sDirectConnectionCount = 0;

    /** List of timestamps which indicate the latest time an a11y service receives a scroll event
        from a window, mapping from windowId -> timestamp. */
@@ -272,12 +273,18 @@ public final class AccessibilityInteractionClient
            DirectAccessibilityConnection directAccessibilityConnection =
                    new DirectAccessibilityConnection(connection);
            sConnectionCache.put(connectionId, directAccessibilityConnection);
            sDirectConnectionCount++;
            // Do not use AccessibilityCache for this connection, since there is no corresponding
            // AccessibilityService to handle cache invalidation events.
            return connectionId;
        }
    }

    /** Check if any {@link DirectAccessibilityConnection} is currently in the connection cache. */
    public static boolean hasAnyDirectConnection() {
        return sDirectConnectionCount > 0;
    }

    /**
     * Gets a cached associated with the connection id if available.
     *
@@ -295,6 +302,9 @@ public final class AccessibilityInteractionClient
     */
    public static void removeConnection(int connectionId) {
        synchronized (sConnectionCache) {
            if (getConnection(connectionId) instanceof DirectAccessibilityConnection) {
                sDirectConnectionCount--;
            }
            sConnectionCache.remove(connectionId);
            sCaches.remove(connectionId);
        }
+17 −3
Original line number Diff line number Diff line
@@ -602,11 +602,20 @@ public final class AccessibilityManager {
     */
    public boolean isEnabled() {
        synchronized (mLock) {
            return mIsEnabled || (mAccessibilityPolicy != null
                    && mAccessibilityPolicy.isEnabled(mIsEnabled));
            return mIsEnabled || hasAnyDirectConnection()
                    || (mAccessibilityPolicy != null && mAccessibilityPolicy.isEnabled(mIsEnabled));
        }
    }

    /**
     * @see AccessibilityInteractionClient#hasAnyDirectConnection
     * @hide
     */
    @TestApi
    public boolean hasAnyDirectConnection() {
        return AccessibilityInteractionClient.hasAnyDirectConnection();
    }

    /**
     * Returns if the touch exploration in the system is enabled.
     * <p>
@@ -1942,8 +1951,13 @@ public final class AccessibilityManager {

    /**
     * Notifies the registered {@link AccessibilityStateChangeListener}s.
     *
     * Note: this method notifies only the listeners of this single instance.
     * AccessibilityManagerService is responsible for calling this method on all of
     * its AccessibilityManager clients in order to notify all listeners.
     * @hide
     */
    private void notifyAccessibilityStateChanged() {
    public void notifyAccessibilityStateChanged() {
        final boolean isEnabled;
        final ArrayMap<AccessibilityStateChangeListener, Handler> listeners;
        synchronized (mLock) {