Loading core/java/android/view/accessibility/AccessibilityCache.java +7 −0 Original line number Diff line number Diff line Loading @@ -309,6 +309,13 @@ public final class AccessibilityCache { final int oldChildCount = oldInfo.getChildCount(); for (int i = 0; i < oldChildCount; i++) { if (nodes.get(sourceId) == null) { // We've removed (and thus recycled) this node because it was its own // ancestor (the app gave us bad data), we can't continue using it. // Clear the cache for this window and give up on adding the node. clearNodesForWindowLocked(windowId); return; } final long oldChildId = oldInfo.getChildId(i); // If the child is no longer present, remove the sub-tree. if (newChildrenIds == null || newChildrenIds.indexOf(oldChildId) < 0) { Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ public class AccessibilityCacheTest { private static int OTHER_VIEW_ID = 0xCAB2; private static int PARENT_VIEW_ID = 0xFED4; private static int CHILD_VIEW_ID = 0xFEED; private static int OTHER_CHILD_VIEW_ID = 0xACE2; private static int MOCK_CONNECTION_ID = 1; AccessibilityCache mAccessibilityCache; Loading Loading @@ -481,6 +482,30 @@ public class AccessibilityCacheTest { AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); } @Test public void addNode_whenNodeBeingReplacedIsOwnGrandparent_doesntCrash() { AccessibilityNodeInfo parentNodeInfo = getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(CHILD_VIEW_ID, WINDOW_ID_1)); parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(OTHER_CHILD_VIEW_ID, WINDOW_ID_1)); AccessibilityNodeInfo childNodeInfo = getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1); childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); childNodeInfo.addChild(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); AccessibilityNodeInfo replacementParentNodeInfo = getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); try { mAccessibilityCache.add(parentNodeInfo); mAccessibilityCache.add(childNodeInfo); mAccessibilityCache.add(replacementParentNodeInfo); } finally { parentNodeInfo.recycle(); childNodeInfo.recycle(); replacementParentNodeInfo.recycle(); } } @Test public void testCacheCriticalEventList_doesntLackEvents() { for (int i = 0; i < 32; i++) { Loading Loading
core/java/android/view/accessibility/AccessibilityCache.java +7 −0 Original line number Diff line number Diff line Loading @@ -309,6 +309,13 @@ public final class AccessibilityCache { final int oldChildCount = oldInfo.getChildCount(); for (int i = 0; i < oldChildCount; i++) { if (nodes.get(sourceId) == null) { // We've removed (and thus recycled) this node because it was its own // ancestor (the app gave us bad data), we can't continue using it. // Clear the cache for this window and give up on adding the node. clearNodesForWindowLocked(windowId); return; } final long oldChildId = oldInfo.getChildId(i); // If the child is no longer present, remove the sub-tree. if (newChildrenIds == null || newChildrenIds.indexOf(oldChildId) < 0) { Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityCacheTest.java +25 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ public class AccessibilityCacheTest { private static int OTHER_VIEW_ID = 0xCAB2; private static int PARENT_VIEW_ID = 0xFED4; private static int CHILD_VIEW_ID = 0xFEED; private static int OTHER_CHILD_VIEW_ID = 0xACE2; private static int MOCK_CONNECTION_ID = 1; AccessibilityCache mAccessibilityCache; Loading Loading @@ -481,6 +482,30 @@ public class AccessibilityCacheTest { AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); } @Test public void addNode_whenNodeBeingReplacedIsOwnGrandparent_doesntCrash() { AccessibilityNodeInfo parentNodeInfo = getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(CHILD_VIEW_ID, WINDOW_ID_1)); parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(OTHER_CHILD_VIEW_ID, WINDOW_ID_1)); AccessibilityNodeInfo childNodeInfo = getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1); childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); childNodeInfo.addChild(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); AccessibilityNodeInfo replacementParentNodeInfo = getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); try { mAccessibilityCache.add(parentNodeInfo); mAccessibilityCache.add(childNodeInfo); mAccessibilityCache.add(replacementParentNodeInfo); } finally { parentNodeInfo.recycle(); childNodeInfo.recycle(); replacementParentNodeInfo.recycle(); } } @Test public void testCacheCriticalEventList_doesntLackEvents() { for (int i = 0; i < 32; i++) { Loading