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

Commit 4528b4e8 authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Prefetching of accessibility node infos getting incorrect views.

1. The prefetcher of accessibility nodes infos was not folloing
   the childForAccessibility relationship when finding the views
   whose node infos to prefetch.

2. NumberPicker was not reporting the correct parent.

bug:6471710

Change-Id: Ia7ad5dd031fb4b3816dfe630d5212201cfafa236
parent 6387c8a9
Loading
Loading
Loading
Loading
+16 −13
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.util.Poolable;
import android.util.PoolableManager;
import android.util.Pools;
import android.util.SparseLongArray;
import android.view.ViewGroup.ChildListForAccessibility;
import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
@@ -623,6 +622,8 @@ final class AccessibilityInteractionController {

        private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50;

        private final ArrayList<View> mTempViewList = new ArrayList<View>();

        public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int prefetchFlags,
                List<AccessibilityNodeInfo> outInfos) {
            AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
@@ -663,8 +664,6 @@ final class AccessibilityInteractionController {
            while (parent instanceof View
                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                View parentView = (View) parent;
                final long parentNodeId = AccessibilityNodeInfo.makeNodeId(
                        parentView.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
                AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
                if (info != null) {
                    outInfos.add(info);
@@ -678,19 +677,21 @@ final class AccessibilityInteractionController {
            ViewParent parent = current.getParentForAccessibility();
            if (parent instanceof ViewGroup) {
                ViewGroup parentGroup = (ViewGroup) parent;
                ChildListForAccessibility children = ChildListForAccessibility.obtain(parentGroup,
                        false);
                ArrayList<View> children = mTempViewList;
                children.clear();
                try {
                    final int childCount = children.getChildCount();
                    parentGroup.addChildrenForAccessibility(children);
                    final int childCount = children.size();
                    for (int i = 0; i < childCount; i++) {
                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                            return;
                        }
                        View child = children.getChildAt(i);
                        View child = children.get(i);
                        if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
                                &&  isShown(child)) {
                            AccessibilityNodeInfo info = null;
                            AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
                            AccessibilityNodeProvider provider =
                                child.getAccessibilityNodeProvider();
                            if (provider == null) {
                                info = child.createAccessibilityNodeInfo();
                            } else {
@@ -703,7 +704,7 @@ final class AccessibilityInteractionController {
                        }
                    }
                } finally {
                    children.recycle();
                    children.clear();
                }
            }
        }
@@ -716,14 +717,16 @@ final class AccessibilityInteractionController {
            ViewGroup rootGroup = (ViewGroup) root;
            HashMap<View, AccessibilityNodeInfo> addedChildren =
                new HashMap<View, AccessibilityNodeInfo>();
            ChildListForAccessibility children = ChildListForAccessibility.obtain(rootGroup, false);
            ArrayList<View> children = mTempViewList;
            children.clear();
            try {
                final int childCount = children.getChildCount();
                root.addChildrenForAccessibility(children);
                final int childCount = children.size();
                for (int i = 0; i < childCount; i++) {
                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                        return;
                    }
                    View child = children.getChildAt(i);
                    View child = children.get(i);
                    if (isShown(child)) {
                        AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
                        if (provider == null) {
@@ -743,7 +746,7 @@ final class AccessibilityInteractionController {
                    }
                }
            } finally {
                children.recycle();
                children.clear();
            }
            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
+62 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.view.accessibility;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.os.Process;
@@ -27,10 +28,14 @@ import android.os.SystemClock;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
import android.util.SparseLongArray;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;

/**
@@ -74,6 +79,8 @@ public final class AccessibilityInteractionClient

    private static final boolean DEBUG = false;

    private static final boolean CHECK_INTEGRITY = true;

    private static final long TIMEOUT_INTERACTION_MILLIS = 5000;

    private static final Object sStaticLock = new Object();
@@ -491,6 +498,9 @@ public final class AccessibilityInteractionClient
                result = Collections.emptyList();
            }
            clearResultLocked();
            if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) {
                checkFindAccessibilityNodeInfoResultIntegrity(result);
            }
            return result;
        }
    }
@@ -696,4 +706,56 @@ public final class AccessibilityInteractionClient
            sConnectionCache.remove(connectionId);
        }
    }

    /**
     * Checks whether the infos are a fully connected tree with no duplicates.
     *
     * @param infos The result list to check.
     */
    private void checkFindAccessibilityNodeInfoResultIntegrity(List<AccessibilityNodeInfo> infos) {
        if (infos.size() == 0) {
            return;
        }
        // Find the root node.
        AccessibilityNodeInfo root = infos.get(0);
        final int infoCount = infos.size();
        for (int i = 1; i < infoCount; i++) {
            for (int j = i; j < infoCount; j++) {
                AccessibilityNodeInfo candidate = infos.get(j);
                if (root.getParentNodeId() == candidate.getSourceNodeId()) {
                    root = candidate;
                    break;
                }
            }
        }
        if (root == null) {
            Log.e(LOG_TAG, "No root.");
        }
        // Check for duplicates.
        HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>();
        Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
        fringe.add(root);
        while (!fringe.isEmpty()) {
            AccessibilityNodeInfo current = fringe.poll();
            if (!seen.add(current)) {
                Log.e(LOG_TAG, "Duplicate node.");
                return;
            }
            SparseLongArray childIds = current.getChildNodeIds();
            final int childCount = childIds.size();
            for (int i = 0; i < childCount; i++) {
                final long childId = childIds.valueAt(i);
                for (int j = 0; j < infoCount; j++) {
                    AccessibilityNodeInfo child = infos.get(j);
                    if (child.getSourceNodeId() == childId) {
                        fringe.add(child);
                    }
                }
            }
        }
        final int disconnectedCount = infos.size() - seen.size();
        if (disconnectedCount > 0) {
            Log.e(LOG_TAG, disconnectedCount + " Disconnected nodes.");
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -244,7 +244,7 @@ public class AccessibilityNodeInfoCache {
    /**
     * We are enforcing the invariant for a single accessibility focus.
     *
     * @param currentInputFocusId The current input focused node.
     * @param currentAccessibilityFocusId The current input focused node.
     */
    private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) {
        final int cacheSize = mCacheImpl.size();
+1 −1
Original line number Diff line number Diff line
@@ -2490,7 +2490,7 @@ public class NumberPicker extends LinearLayout {
                info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
            }

            info.setParent((View) getParent());
            info.setParent((View) getParentForAccessibility());
            info.setEnabled(NumberPicker.this.isEnabled());
            info.setScrollable(true);
            Rect boundsInParent = mTempRect;