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