AccessibilityCacheTest.java revision 62d20fabf239e26e7dc6bbb2fbf0b1118a51aff0
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.accessibility; 18 19import static junit.framework.Assert.assertEquals; 20import static junit.framework.Assert.assertNull; 21import static org.mockito.Matchers.anyBoolean; 22import static org.mockito.Matchers.anyObject; 23import static org.mockito.Mockito.doAnswer; 24import static org.mockito.Mockito.mock; 25import static org.mockito.Mockito.verify; 26import static org.mockito.Mockito.when; 27 28import android.support.test.runner.AndroidJUnit4; 29import android.view.accessibility.AccessibilityCache; 30import android.view.accessibility.AccessibilityEvent; 31import android.view.accessibility.AccessibilityInteractionClient; 32import android.view.accessibility.AccessibilityNodeInfo; 33import android.view.accessibility.AccessibilityWindowInfo; 34import android.view.View; 35import org.junit.After; 36import org.junit.Before; 37import org.junit.Test; 38import org.junit.runner.RunWith; 39import org.mockito.invocation.InvocationOnMock; 40import org.mockito.stubbing.Answer; 41 42import java.util.Arrays; 43import java.util.List; 44import java.util.concurrent.atomic.AtomicInteger; 45 46 47@RunWith(AndroidJUnit4.class) 48public class AccessibilityCacheTest { 49 private static int WINDOW_ID_1 = 0xBEEF; 50 private static int WINDOW_ID_2 = 0xFACE; 51 private static int SINGLE_VIEW_ID = 0xCAFE; 52 private static int OTHER_VIEW_ID = 0xCAB2; 53 private static int PARENT_VIEW_ID = 0xFED4; 54 private static int CHILD_VIEW_ID = 0xFEED; 55 private static int MOCK_CONNECTION_ID = 1; 56 57 AccessibilityCache mAccessibilityCache; 58 AccessibilityCache.AccessibilityNodeRefresher mAccessibilityNodeRefresher; 59 AtomicInteger numA11yNodeInfosInUse = new AtomicInteger(0); 60 AtomicInteger numA11yWinInfosInUse = new AtomicInteger(0); 61 62 @Before 63 public void setUp() { 64 mAccessibilityNodeRefresher = mock(AccessibilityCache.AccessibilityNodeRefresher.class); 65 when(mAccessibilityNodeRefresher.refreshNode(anyObject(), anyBoolean())).thenReturn(true); 66 mAccessibilityCache = new AccessibilityCache(mAccessibilityNodeRefresher); 67 AccessibilityNodeInfo.setNumInstancesInUseCounter(numA11yNodeInfosInUse); 68 AccessibilityWindowInfo.setNumInstancesInUseCounter(numA11yWinInfosInUse); 69 } 70 71 @After 72 public void tearDown() { 73 // Make sure we're recycling all of our window and node infos 74 mAccessibilityCache.clear(); 75 AccessibilityInteractionClient.getInstance().clearCache(); 76 assertEquals(0, numA11yWinInfosInUse.get()); 77 assertEquals(0, numA11yNodeInfosInUse.get()); 78 } 79 80 @Test 81 public void testEmptyCache_returnsNull() { 82 assertNull(mAccessibilityCache.getNode(0, 0)); 83 assertNull(mAccessibilityCache.getWindows()); 84 assertNull(mAccessibilityCache.getWindow(0)); 85 } 86 87 @Test 88 public void testEmptyCache_clearDoesntCrash() { 89 mAccessibilityCache.clear(); 90 } 91 92 @Test 93 public void testEmptyCache_a11yEventsHaveNoEffect() { 94 AccessibilityEvent event = AccessibilityEvent.obtain(); 95 int[] a11yEventTypes = { 96 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, 97 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, 98 AccessibilityEvent.TYPE_VIEW_FOCUSED, 99 AccessibilityEvent.TYPE_VIEW_SELECTED, 100 AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, 101 AccessibilityEvent.TYPE_VIEW_CLICKED, 102 AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, 103 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 104 AccessibilityEvent.TYPE_VIEW_SCROLLED, 105 AccessibilityEvent.TYPE_WINDOWS_CHANGED, 106 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED}; 107 for (int i = 0; i < a11yEventTypes.length; i++) { 108 event.setEventType(a11yEventTypes[i]); 109 mAccessibilityCache.onAccessibilityEvent(event); 110 } 111 } 112 113 @Test 114 public void addThenGetWindow_returnsEquivalentButNotSameWindow() { 115 AccessibilityWindowInfo windowInfo = null, copyOfInfo = null, windowFromCache = null; 116 try { 117 windowInfo = AccessibilityWindowInfo.obtain(); 118 windowInfo.setId(WINDOW_ID_1); 119 mAccessibilityCache.addWindow(windowInfo); 120 // Make a copy 121 copyOfInfo = AccessibilityWindowInfo.obtain(windowInfo); 122 windowInfo.setId(WINDOW_ID_2); // Simulate recycling and reusing the original info 123 windowFromCache = mAccessibilityCache.getWindow(WINDOW_ID_1); 124 assertEquals(copyOfInfo, windowFromCache); 125 } finally { 126 windowFromCache.recycle(); 127 windowInfo.recycle(); 128 copyOfInfo.recycle(); 129 } 130 } 131 132 @Test 133 public void addWindowThenClear_noLongerInCache() { 134 putWindowWithIdInCache(WINDOW_ID_1); 135 mAccessibilityCache.clear(); 136 assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); 137 } 138 139 @Test 140 public void addWindowGetOtherId_returnsNull() { 141 putWindowWithIdInCache(WINDOW_ID_1); 142 assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1 + 1)); 143 } 144 145 @Test 146 public void addWindowThenGetWindows_returnsNull() { 147 putWindowWithIdInCache(WINDOW_ID_1); 148 assertNull(mAccessibilityCache.getWindows()); 149 } 150 151 @Test 152 public void setWindowsThenGetWindows_returnsInDecreasingLayerOrder() { 153 AccessibilityWindowInfo windowInfo1 = null, windowInfo2 = null; 154 AccessibilityWindowInfo window1Out = null, window2Out = null; 155 List<AccessibilityWindowInfo> windowsOut = null; 156 try { 157 windowInfo1 = AccessibilityWindowInfo.obtain(); 158 windowInfo1.setId(WINDOW_ID_1); 159 windowInfo1.setLayer(5); 160 windowInfo2 = AccessibilityWindowInfo.obtain(); 161 windowInfo2.setId(WINDOW_ID_2); 162 windowInfo2.setLayer(windowInfo1.getLayer() + 1); 163 List<AccessibilityWindowInfo> windowsIn = Arrays.asList(windowInfo1, windowInfo2); 164 mAccessibilityCache.setWindows(windowsIn); 165 166 windowsOut = mAccessibilityCache.getWindows(); 167 window1Out = mAccessibilityCache.getWindow(WINDOW_ID_1); 168 window2Out = mAccessibilityCache.getWindow(WINDOW_ID_2); 169 170 assertEquals(2, windowsOut.size()); 171 assertEquals(windowInfo2, windowsOut.get(0)); 172 assertEquals(windowInfo1, windowsOut.get(1)); 173 assertEquals(windowInfo1, window1Out); 174 assertEquals(windowInfo2, window2Out); 175 } finally { 176 window1Out.recycle(); 177 window2Out.recycle(); 178 windowInfo1.recycle(); 179 windowInfo2.recycle(); 180 for (AccessibilityWindowInfo windowInfo : windowsOut) { 181 windowInfo.recycle(); 182 } 183 } 184 } 185 186 @Test 187 public void addWindowThenStateChangedEvent_noLongerInCache() { 188 putWindowWithIdInCache(WINDOW_ID_1); 189 mAccessibilityCache.onAccessibilityEvent( 190 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)); 191 assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); 192 } 193 194 @Test 195 public void addWindowThenWindowsChangedEvent_noLongerInCache() { 196 putWindowWithIdInCache(WINDOW_ID_1); 197 mAccessibilityCache.onAccessibilityEvent( 198 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOWS_CHANGED)); 199 assertNull(mAccessibilityCache.getWindow(WINDOW_ID_1)); 200 } 201 202 @Test 203 public void addThenGetNode_returnsEquivalentNode() { 204 AccessibilityNodeInfo nodeInfo, nodeCopy = null, nodeFromCache = null; 205 try { 206 nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 207 long id = nodeInfo.getSourceNodeId(); 208 nodeCopy = AccessibilityNodeInfo.obtain(nodeInfo); 209 mAccessibilityCache.add(nodeInfo); 210 nodeInfo.recycle(); 211 nodeFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id); 212 assertEquals(nodeCopy, nodeFromCache); 213 } finally { 214 nodeFromCache.recycle(); 215 nodeCopy.recycle(); 216 } 217 } 218 219 @Test 220 public void overwriteThenGetNode_returnsNewNode() { 221 final CharSequence contentDescription1 = "foo"; 222 final CharSequence contentDescription2 = "bar"; 223 AccessibilityNodeInfo nodeInfo1 = null, nodeInfo2 = null, nodeFromCache = null; 224 try { 225 nodeInfo1 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 226 nodeInfo1.setContentDescription(contentDescription1); 227 long id = nodeInfo1.getSourceNodeId(); 228 nodeInfo2 = AccessibilityNodeInfo.obtain(nodeInfo1); 229 nodeInfo2.setContentDescription(contentDescription2); 230 mAccessibilityCache.add(nodeInfo1); 231 mAccessibilityCache.add(nodeInfo2); 232 nodeFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id); 233 assertEquals(nodeInfo2, nodeFromCache); 234 assertEquals(contentDescription2, nodeFromCache.getContentDescription()); 235 } finally { 236 nodeFromCache.recycle(); 237 nodeInfo2.recycle(); 238 nodeInfo1.recycle(); 239 } 240 } 241 242 @Test 243 public void nodesInDifferentWindowWithSameId_areKeptSeparate() { 244 final CharSequence contentDescription1 = "foo"; 245 final CharSequence contentDescription2 = "bar"; 246 AccessibilityNodeInfo nodeInfo1 = null, nodeInfo2 = null, 247 node1FromCache = null, node2FromCache = null; 248 try { 249 nodeInfo1 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 250 nodeInfo1.setContentDescription(contentDescription1); 251 long id = nodeInfo1.getSourceNodeId(); 252 nodeInfo2 = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_2); 253 nodeInfo2.setContentDescription(contentDescription2); 254 assertEquals(id, nodeInfo2.getSourceNodeId()); 255 mAccessibilityCache.add(nodeInfo1); 256 mAccessibilityCache.add(nodeInfo2); 257 node1FromCache = mAccessibilityCache.getNode(WINDOW_ID_1, id); 258 node2FromCache = mAccessibilityCache.getNode(WINDOW_ID_2, id); 259 assertEquals(nodeInfo1, node1FromCache); 260 assertEquals(nodeInfo2, node2FromCache); 261 assertEquals(nodeInfo1.getContentDescription(), node1FromCache.getContentDescription()); 262 assertEquals(nodeInfo2.getContentDescription(), node2FromCache.getContentDescription()); 263 } finally { 264 node1FromCache.recycle(); 265 node2FromCache.recycle(); 266 nodeInfo1.recycle(); 267 nodeInfo2.recycle(); 268 } 269 } 270 271 @Test 272 public void addNodeThenClear_nodeIsRemoved() { 273 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 274 long id = nodeInfo.getSourceNodeId(); 275 mAccessibilityCache.add(nodeInfo); 276 nodeInfo.recycle(); 277 mAccessibilityCache.clear(); 278 assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, id)); 279 } 280 281 @Test 282 public void windowStateChangeAndWindowsChangedEvents_clearsNode() { 283 assertEventTypeClearsNode(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 284 assertEventTypeClearsNode(AccessibilityEvent.TYPE_WINDOWS_CHANGED); 285 } 286 287 @Test 288 public void subTreeChangeEvent_clearsNodeAndChild() { 289 AccessibilityEvent event = AccessibilityEvent 290 .obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 291 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 292 event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); 293 294 try { 295 assertEventClearsParentAndChild(event); 296 } finally { 297 event.recycle(); 298 } 299 } 300 301 @Test 302 public void scrollEvent_clearsNodeAndChild() { 303 AccessibilityEvent event = AccessibilityEvent 304 .obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 305 event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); 306 try { 307 assertEventClearsParentAndChild(event); 308 } finally { 309 event.recycle(); 310 } 311 } 312 313 @Test 314 public void reparentNode_clearsOldParent() { 315 AccessibilityNodeInfo parentNodeInfo = getParentNode(); 316 AccessibilityNodeInfo childNodeInfo = getChildNode(); 317 long parentId = parentNodeInfo.getSourceNodeId(); 318 mAccessibilityCache.add(parentNodeInfo); 319 mAccessibilityCache.add(childNodeInfo); 320 321 childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID + 1, WINDOW_ID_1)); 322 mAccessibilityCache.add(childNodeInfo); 323 324 AccessibilityNodeInfo parentFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, parentId); 325 try { 326 assertNull(parentFromCache); 327 } finally { 328 parentNodeInfo.recycle(); 329 childNodeInfo.recycle(); 330 if (parentFromCache != null) { 331 parentFromCache.recycle(); 332 } 333 } 334 } 335 336 @Test 337 public void removeChildFromParent_clearsChild() { 338 AccessibilityNodeInfo parentNodeInfo = getParentNode(); 339 AccessibilityNodeInfo childNodeInfo = getChildNode(); 340 long childId = childNodeInfo.getSourceNodeId(); 341 mAccessibilityCache.add(parentNodeInfo); 342 mAccessibilityCache.add(childNodeInfo); 343 344 AccessibilityNodeInfo parentNodeInfoWithNoChildren = 345 getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); 346 mAccessibilityCache.add(parentNodeInfoWithNoChildren); 347 348 AccessibilityNodeInfo childFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, childId); 349 try { 350 assertNull(childFromCache); 351 } finally { 352 parentNodeInfoWithNoChildren.recycle(); 353 parentNodeInfo.recycle(); 354 childNodeInfo.recycle(); 355 if (childFromCache != null) { 356 childFromCache.recycle(); 357 } 358 } 359 } 360 361 @Test 362 public void nodeSourceOfA11yFocusEvent_getsRefreshed() { 363 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 364 nodeInfo.setAccessibilityFocused(false); 365 mAccessibilityCache.add(nodeInfo); 366 AccessibilityEvent event = AccessibilityEvent.obtain( 367 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 368 event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1)); 369 mAccessibilityCache.onAccessibilityEvent(event); 370 event.recycle(); 371 try { 372 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 373 } finally { 374 nodeInfo.recycle(); 375 } 376 } 377 378 @Test 379 public void nodeWithA11yFocusWhenAnotherNodeGetsFocus_getsRefreshed() { 380 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 381 nodeInfo.setAccessibilityFocused(true); 382 mAccessibilityCache.add(nodeInfo); 383 AccessibilityEvent event = AccessibilityEvent.obtain( 384 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 385 event.setSource(getMockViewWithA11yAndWindowIds(OTHER_VIEW_ID, WINDOW_ID_1)); 386 mAccessibilityCache.onAccessibilityEvent(event); 387 event.recycle(); 388 try { 389 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 390 } finally { 391 nodeInfo.recycle(); 392 } 393 } 394 395 @Test 396 public void nodeWithA11yFocusClearsIt_refreshes() { 397 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 398 nodeInfo.setAccessibilityFocused(true); 399 mAccessibilityCache.add(nodeInfo); 400 AccessibilityEvent event = AccessibilityEvent.obtain( 401 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 402 event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1)); 403 mAccessibilityCache.onAccessibilityEvent(event); 404 event.recycle(); 405 try { 406 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 407 } finally { 408 nodeInfo.recycle(); 409 } 410 } 411 412 @Test 413 public void nodeSourceOfInputFocusEvent_getsRefreshed() { 414 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 415 nodeInfo.setFocused(false); 416 mAccessibilityCache.add(nodeInfo); 417 AccessibilityEvent event = AccessibilityEvent.obtain( 418 AccessibilityEvent.TYPE_VIEW_FOCUSED); 419 event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1)); 420 mAccessibilityCache.onAccessibilityEvent(event); 421 event.recycle(); 422 try { 423 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 424 } finally { 425 nodeInfo.recycle(); 426 } 427 } 428 429 @Test 430 public void nodeWithInputFocusWhenAnotherNodeGetsFocus_getsRefreshed() { 431 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 432 nodeInfo.setFocused(true); 433 mAccessibilityCache.add(nodeInfo); 434 AccessibilityEvent event = AccessibilityEvent.obtain( 435 AccessibilityEvent.TYPE_VIEW_FOCUSED); 436 event.setSource(getMockViewWithA11yAndWindowIds(OTHER_VIEW_ID, WINDOW_ID_1)); 437 mAccessibilityCache.onAccessibilityEvent(event); 438 event.recycle(); 439 try { 440 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 441 } finally { 442 nodeInfo.recycle(); 443 } 444 } 445 446 @Test 447 public void nodeEventSaysWasSelected_getsRefreshed() { 448 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_SELECTED, 449 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 450 } 451 452 @Test 453 public void nodeEventSaysHadTextChanged_getsRefreshed() { 454 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED, 455 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 456 } 457 458 @Test 459 public void nodeEventSaysWasClicked_getsRefreshed() { 460 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_CLICKED, 461 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 462 } 463 464 @Test 465 public void nodeEventSaysHadSelectionChange_getsRefreshed() { 466 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED, 467 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 468 } 469 470 @Test 471 public void nodeEventSaysHadTextContentChange_getsRefreshed() { 472 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 473 AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT); 474 } 475 476 @Test 477 public void nodeEventSaysHadContentDescriptionChange_getsRefreshed() { 478 assertNodeIsRefreshedWithEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED, 479 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 480 } 481 482 private void assertNodeIsRefreshedWithEventType(int eventType, int contentChangeTypes) { 483 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(SINGLE_VIEW_ID, WINDOW_ID_1); 484 mAccessibilityCache.add(nodeInfo); 485 AccessibilityEvent event = AccessibilityEvent.obtain(eventType); 486 event.setSource(getMockViewWithA11yAndWindowIds(SINGLE_VIEW_ID, WINDOW_ID_1)); 487 event.setContentChangeTypes(contentChangeTypes); 488 mAccessibilityCache.onAccessibilityEvent(event); 489 event.recycle(); 490 try { 491 verify(mAccessibilityNodeRefresher).refreshNode(nodeInfo, true); 492 } finally { 493 nodeInfo.recycle(); 494 } 495 } 496 497 private void putWindowWithIdInCache(int id) { 498 AccessibilityWindowInfo windowInfo = AccessibilityWindowInfo.obtain(); 499 windowInfo.setId(id); 500 mAccessibilityCache.addWindow(windowInfo); 501 windowInfo.recycle(); 502 } 503 504 private AccessibilityNodeInfo getNodeWithA11yAndWindowId(int a11yId, int windowId) { 505 AccessibilityNodeInfo node = 506 AccessibilityNodeInfo.obtain(getMockViewWithA11yAndWindowIds(a11yId, windowId)); 507 node.setConnectionId(MOCK_CONNECTION_ID); 508 return node; 509 } 510 511 private View getMockViewWithA11yAndWindowIds(int a11yId, int windowId) { 512 View mockView = mock(View.class); 513 when(mockView.getAccessibilityViewId()).thenReturn(a11yId); 514 when(mockView.getAccessibilityWindowId()).thenReturn(windowId); 515 doAnswer(new Answer<AccessibilityNodeInfo>() { 516 public AccessibilityNodeInfo answer(InvocationOnMock invocation) { 517 return AccessibilityNodeInfo.obtain((View) invocation.getMock()); 518 } 519 }).when(mockView).createAccessibilityNodeInfo(); 520 return mockView; 521 } 522 523 private void assertEventTypeClearsNode(int eventType) { 524 final int nodeId = 0xBEEF; 525 AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(nodeId, WINDOW_ID_1); 526 long id = nodeInfo.getSourceNodeId(); 527 mAccessibilityCache.add(nodeInfo); 528 nodeInfo.recycle(); 529 mAccessibilityCache.onAccessibilityEvent(AccessibilityEvent.obtain(eventType)); 530 assertNull(mAccessibilityCache.getNode(WINDOW_ID_1, id)); 531 } 532 533 private AccessibilityNodeInfo getParentNode() { 534 AccessibilityNodeInfo parentNodeInfo = 535 getNodeWithA11yAndWindowId(PARENT_VIEW_ID, WINDOW_ID_1); 536 parentNodeInfo.addChild(getMockViewWithA11yAndWindowIds(CHILD_VIEW_ID, WINDOW_ID_1)); 537 return parentNodeInfo; 538 } 539 540 private AccessibilityNodeInfo getChildNode() { 541 AccessibilityNodeInfo childNodeInfo = 542 getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1); 543 childNodeInfo.setParent(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1)); 544 return childNodeInfo; 545 } 546 547 private void assertEventClearsParentAndChild(AccessibilityEvent event) { 548 AccessibilityNodeInfo parentNodeInfo = getParentNode(); 549 AccessibilityNodeInfo childNodeInfo = getChildNode(); 550 long parentId = parentNodeInfo.getSourceNodeId(); 551 long childId = childNodeInfo.getSourceNodeId(); 552 mAccessibilityCache.add(parentNodeInfo); 553 mAccessibilityCache.add(childNodeInfo); 554 555 mAccessibilityCache.onAccessibilityEvent(event); 556 parentNodeInfo.recycle(); 557 childNodeInfo.recycle(); 558 559 AccessibilityNodeInfo parentFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, parentId); 560 AccessibilityNodeInfo childFromCache = mAccessibilityCache.getNode(WINDOW_ID_1, childId); 561 try { 562 assertNull(parentFromCache); 563 assertNull(childFromCache); 564 } finally { 565 if (parentFromCache != null) { 566 parentFromCache.recycle(); 567 } 568 if (childFromCache != null) { 569 childFromCache.recycle(); 570 } 571 } 572 } 573} 574