Skip to content

Commit 4528b4e

Browse files
committed
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
1 parent 6387c8a commit 4528b4e

File tree

4 files changed

+80
-15
lines changed

4 files changed

+80
-15
lines changed

core/java/android/view/AccessibilityInteractionController.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import android.util.PoolableManager;
3030
import android.util.Pools;
3131
import android.util.SparseLongArray;
32-
import android.view.ViewGroup.ChildListForAccessibility;
3332
import android.view.accessibility.AccessibilityInteractionClient;
3433
import android.view.accessibility.AccessibilityNodeInfo;
3534
import android.view.accessibility.AccessibilityNodeProvider;
@@ -623,6 +622,8 @@ private class AccessibilityNodePrefetcher {
623622

624623
private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 50;
625624

625+
private final ArrayList<View> mTempViewList = new ArrayList<View>();
626+
626627
public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int prefetchFlags,
627628
List<AccessibilityNodeInfo> outInfos) {
628629
AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
@@ -663,8 +664,6 @@ private void prefetchPredecessorsOfRealNode(View view,
663664
while (parent instanceof View
664665
&& outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
665666
View parentView = (View) parent;
666-
final long parentNodeId = AccessibilityNodeInfo.makeNodeId(
667-
parentView.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
668667
AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
669668
if (info != null) {
670669
outInfos.add(info);
@@ -678,19 +677,21 @@ private void prefetchSiblingsOfRealNode(View current,
678677
ViewParent parent = current.getParentForAccessibility();
679678
if (parent instanceof ViewGroup) {
680679
ViewGroup parentGroup = (ViewGroup) parent;
681-
ChildListForAccessibility children = ChildListForAccessibility.obtain(parentGroup,
682-
false);
680+
ArrayList<View> children = mTempViewList;
681+
children.clear();
683682
try {
684-
final int childCount = children.getChildCount();
683+
parentGroup.addChildrenForAccessibility(children);
684+
final int childCount = children.size();
685685
for (int i = 0; i < childCount; i++) {
686686
if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
687687
return;
688688
}
689-
View child = children.getChildAt(i);
689+
View child = children.get(i);
690690
if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
691691
&& isShown(child)) {
692692
AccessibilityNodeInfo info = null;
693-
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
693+
AccessibilityNodeProvider provider =
694+
child.getAccessibilityNodeProvider();
694695
if (provider == null) {
695696
info = child.createAccessibilityNodeInfo();
696697
} else {
@@ -703,7 +704,7 @@ && isShown(child)) {
703704
}
704705
}
705706
} finally {
706-
children.recycle();
707+
children.clear();
707708
}
708709
}
709710
}
@@ -716,14 +717,16 @@ private void prefetchDescendantsOfRealNode(View root,
716717
ViewGroup rootGroup = (ViewGroup) root;
717718
HashMap<View, AccessibilityNodeInfo> addedChildren =
718719
new HashMap<View, AccessibilityNodeInfo>();
719-
ChildListForAccessibility children = ChildListForAccessibility.obtain(rootGroup, false);
720+
ArrayList<View> children = mTempViewList;
721+
children.clear();
720722
try {
721-
final int childCount = children.getChildCount();
723+
root.addChildrenForAccessibility(children);
724+
final int childCount = children.size();
722725
for (int i = 0; i < childCount; i++) {
723726
if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
724727
return;
725728
}
726-
View child = children.getChildAt(i);
729+
View child = children.get(i);
727730
if (isShown(child)) {
728731
AccessibilityNodeProvider provider = child.getAccessibilityNodeProvider();
729732
if (provider == null) {
@@ -743,7 +746,7 @@ private void prefetchDescendantsOfRealNode(View root,
743746
}
744747
}
745748
} finally {
746-
children.recycle();
749+
children.clear();
747750
}
748751
if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
749752
for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {

core/java/android/view/accessibility/AccessibilityInteractionClient.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.accessibilityservice.IAccessibilityServiceConnection;
2020
import android.graphics.Rect;
2121
import android.os.Binder;
22+
import android.os.Build;
2223
import android.os.Bundle;
2324
import android.os.Message;
2425
import android.os.Process;
@@ -27,10 +28,14 @@
2728
import android.util.Log;
2829
import android.util.LongSparseArray;
2930
import android.util.SparseArray;
31+
import android.util.SparseLongArray;
3032

3133
import java.util.ArrayList;
3234
import java.util.Collections;
35+
import java.util.HashSet;
36+
import java.util.LinkedList;
3337
import java.util.List;
38+
import java.util.Queue;
3439
import java.util.concurrent.atomic.AtomicInteger;
3540

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

7580
private static final boolean DEBUG = false;
7681

82+
private static final boolean CHECK_INTEGRITY = true;
83+
7784
private static final long TIMEOUT_INTERACTION_MILLIS = 5000;
7885

7986
private static final Object sStaticLock = new Object();
@@ -491,6 +498,9 @@ private List<AccessibilityNodeInfo> getFindAccessibilityNodeInfosResultAndClear(
491498
result = Collections.emptyList();
492499
}
493500
clearResultLocked();
501+
if (Build.IS_DEBUGGABLE && CHECK_INTEGRITY) {
502+
checkFindAccessibilityNodeInfoResultIntegrity(result);
503+
}
494504
return result;
495505
}
496506
}
@@ -696,4 +706,56 @@ public void removeConnection(int connectionId) {
696706
sConnectionCache.remove(connectionId);
697707
}
698708
}
709+
710+
/**
711+
* Checks whether the infos are a fully connected tree with no duplicates.
712+
*
713+
* @param infos The result list to check.
714+
*/
715+
private void checkFindAccessibilityNodeInfoResultIntegrity(List<AccessibilityNodeInfo> infos) {
716+
if (infos.size() == 0) {
717+
return;
718+
}
719+
// Find the root node.
720+
AccessibilityNodeInfo root = infos.get(0);
721+
final int infoCount = infos.size();
722+
for (int i = 1; i < infoCount; i++) {
723+
for (int j = i; j < infoCount; j++) {
724+
AccessibilityNodeInfo candidate = infos.get(j);
725+
if (root.getParentNodeId() == candidate.getSourceNodeId()) {
726+
root = candidate;
727+
break;
728+
}
729+
}
730+
}
731+
if (root == null) {
732+
Log.e(LOG_TAG, "No root.");
733+
}
734+
// Check for duplicates.
735+
HashSet<AccessibilityNodeInfo> seen = new HashSet<AccessibilityNodeInfo>();
736+
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
737+
fringe.add(root);
738+
while (!fringe.isEmpty()) {
739+
AccessibilityNodeInfo current = fringe.poll();
740+
if (!seen.add(current)) {
741+
Log.e(LOG_TAG, "Duplicate node.");
742+
return;
743+
}
744+
SparseLongArray childIds = current.getChildNodeIds();
745+
final int childCount = childIds.size();
746+
for (int i = 0; i < childCount; i++) {
747+
final long childId = childIds.valueAt(i);
748+
for (int j = 0; j < infoCount; j++) {
749+
AccessibilityNodeInfo child = infos.get(j);
750+
if (child.getSourceNodeId() == childId) {
751+
fringe.add(child);
752+
}
753+
}
754+
}
755+
}
756+
final int disconnectedCount = infos.size() - seen.size();
757+
if (disconnectedCount > 0) {
758+
Log.e(LOG_TAG, disconnectedCount + " Disconnected nodes.");
759+
}
760+
}
699761
}

core/java/android/view/accessibility/AccessibilityNodeInfoCache.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ private void clearSubtreeWithOldInputFocusLocked(long currentInputFocusId) {
244244
/**
245245
* We are enforcing the invariant for a single accessibility focus.
246246
*
247-
* @param currentInputFocusId The current input focused node.
247+
* @param currentAccessibilityFocusId The current input focused node.
248248
*/
249249
private void clearSubtreeWithOldAccessibilityFocusLocked(long currentAccessibilityFocusId) {
250250
final int cacheSize = mCacheImpl.size();

core/java/android/widget/NumberPicker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2490,7 +2490,7 @@ private AccessibilityNodeInfo createAccessibilityNodeInfoForNumberPicker(int lef
24902490
info.addChild(NumberPicker.this, VIRTUAL_VIEW_ID_INCREMENT);
24912491
}
24922492

2493-
info.setParent((View) getParent());
2493+
info.setParent((View) getParentForAccessibility());
24942494
info.setEnabled(NumberPicker.this.isEnabled());
24952495
info.setScrollable(true);
24962496
Rect boundsInParent = mTempRect;

0 commit comments

Comments
 (0)