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

Commit 67d10a58 authored by Svetoslav Ganov's avatar Svetoslav Ganov Committed by Android (Google) Code Review
Browse files

Merge "Prefetching of accessibility node infos getting incorrect views." into jb-dev

parents 0763e01c 4528b4e8
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;