1 /* 2 * Copyright (C) 2010 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 17 package android.view.accessibility.cts; 18 19 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertThrows; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 27 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule; 28 import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule; 29 import android.app.Activity; 30 import android.app.Instrumentation; 31 import android.app.UiAutomation; 32 import android.content.Context; 33 import android.os.Message; 34 import android.os.Parcel; 35 import android.os.SystemClock; 36 import android.platform.test.annotations.Presubmit; 37 import android.text.SpannableString; 38 import android.text.TextUtils; 39 import android.text.style.LocaleSpan; 40 import android.view.Display; 41 import android.view.View; 42 import android.view.accessibility.AccessibilityEvent; 43 import android.view.accessibility.AccessibilityNodeInfo; 44 import android.view.accessibility.AccessibilityRecord; 45 import android.widget.LinearLayout; 46 import android.widget.TextView; 47 48 import androidx.test.InstrumentationRegistry; 49 import androidx.test.filters.SmallTest; 50 import androidx.test.rule.ActivityTestRule; 51 import androidx.test.runner.AndroidJUnit4; 52 53 import org.junit.Before; 54 import org.junit.Rule; 55 import org.junit.Test; 56 import org.junit.rules.RuleChain; 57 import org.junit.runner.RunWith; 58 59 import java.util.ArrayList; 60 import java.util.List; 61 import java.util.Locale; 62 import java.util.concurrent.TimeoutException; 63 64 /** Class for testing {@link AccessibilityEvent}. */ 65 @Presubmit 66 @RunWith(AndroidJUnit4.class) 67 public class AccessibilityEventTest { 68 private static final long IDLE_TIMEOUT_MS = 500; 69 private static final long DEFAULT_TIMEOUT_MS = 2000; 70 71 // From ViewConfiguration.SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS 72 private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100; 73 74 private EventReportingLinearLayout mParentView; 75 private View mChildView; 76 private TextView mTextView; 77 private String mPackageName; 78 79 private static Instrumentation sInstrumentation; 80 private static UiAutomation sUiAutomation; 81 private final ActivityTestRule<DummyActivity> mActivityRule = 82 new ActivityTestRule<>(DummyActivity.class, false, false); 83 private final AccessibilityDumpOnFailureRule mDumpOnFailureRule = 84 new AccessibilityDumpOnFailureRule(); 85 private InstrumentedAccessibilityServiceTestRule<SpeakingAccessibilityService> 86 mInstrumentedAccessibilityServiceRule = 87 new InstrumentedAccessibilityServiceTestRule<>( 88 SpeakingAccessibilityService.class, false); 89 90 @Rule 91 public final RuleChain mRuleChain = 92 RuleChain.outerRule(mActivityRule) 93 .around(mInstrumentedAccessibilityServiceRule) 94 .around(mDumpOnFailureRule); 95 96 @Before setUp()97 public void setUp() throws Throwable { 98 sInstrumentation = InstrumentationRegistry.getInstrumentation(); 99 sUiAutomation = sInstrumentation.getUiAutomation(); 100 final Activity activity = launchActivityAndWaitForItToBeOnscreen( 101 sInstrumentation, sUiAutomation, mActivityRule); 102 mPackageName = activity.getApplicationContext().getPackageName(); 103 mInstrumentedAccessibilityServiceRule.enableService(); 104 sUiAutomation.executeAndWaitForEvent(() -> { 105 try { 106 mActivityRule.runOnUiThread(() -> { 107 final LinearLayout grandparent = new LinearLayout(activity); 108 activity.setContentView(grandparent); 109 mParentView = new EventReportingLinearLayout(activity); 110 mChildView = new View(activity); 111 mTextView = new TextView(activity); 112 grandparent.addView(mParentView); 113 mParentView.addView(mChildView); 114 mParentView.addView(mTextView); 115 }); 116 } catch (Throwable e) { 117 fail(e.toString()); 118 } 119 }, 120 // There can be a race where the test Activity gets focus and we start test. 121 // Because we don't specify flagRetrieveInteractiveWindows in this test, until 122 // the Activity gets focus, no events will be delivered from it. 123 // So. this waits for any event from the test activity. 124 accessibilityEvent -> mPackageName.equals(accessibilityEvent.getPackageName()), 125 DEFAULT_TIMEOUT_MS); 126 sUiAutomation.waitForIdle(IDLE_TIMEOUT_MS, DEFAULT_TIMEOUT_MS); 127 } 128 129 private static class EventReportingLinearLayout extends LinearLayout { 130 public List<AccessibilityEvent> mReceivedEvents = new ArrayList<AccessibilityEvent>(); 131 EventReportingLinearLayout(Context context)132 public EventReportingLinearLayout(Context context) { 133 super(context); 134 } 135 136 @Override requestSendAccessibilityEvent(View child, AccessibilityEvent event)137 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) { 138 mReceivedEvents.add(AccessibilityEvent.obtain(event)); 139 return super.requestSendAccessibilityEvent(child, event); 140 } 141 } 142 143 @Test testScrollEvent()144 public void testScrollEvent() throws Exception { 145 sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync( 146 () -> mChildView.scrollTo(0, 100)), new ScrollEventFilter(1), DEFAULT_TIMEOUT_MS); 147 } 148 149 @Test testScrollEventBurstCombined()150 public void testScrollEventBurstCombined() throws Exception { 151 sUiAutomation.executeAndWaitForEvent( 152 () -> sInstrumentation.runOnMainSync( 153 () -> { 154 mChildView.scrollTo(0, 100); 155 mChildView.scrollTo(0, 125); 156 mChildView.scrollTo(0, 150); 157 mChildView.scrollTo(0, 175); 158 }), 159 new ScrollEventFilter(1), 160 DEFAULT_TIMEOUT_MS); 161 } 162 163 @Test testScrollEventsDeliveredInCorrectInterval()164 public void testScrollEventsDeliveredInCorrectInterval() throws Exception { 165 sUiAutomation.executeAndWaitForEvent( 166 () -> { 167 sInstrumentation.runOnMainSync(() -> { 168 mChildView.scrollTo(0, 25); 169 mChildView.scrollTo(0, 50); 170 mChildView.scrollTo(0, 100); 171 }); 172 SystemClock.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); 173 sInstrumentation.runOnMainSync(() -> { 174 mChildView.scrollTo(0, 150); 175 mChildView.scrollTo(0, 175); 176 }); 177 SystemClock.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2); 178 sInstrumentation.runOnMainSync(() -> { 179 mChildView.scrollTo(0, 200); 180 }); 181 }, 182 new ScrollEventFilter(2), 183 DEFAULT_TIMEOUT_MS); 184 } 185 186 class ScrollEventFilter extends AccessibilityEventFilter { 187 private int mCount = 0; 188 private int mTargetCount; 189 ScrollEventFilter(int count)190 ScrollEventFilter(int count) { 191 mTargetCount = count; 192 } 193 accept(AccessibilityEvent event)194 public boolean accept(AccessibilityEvent event) { 195 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 196 mCount += 1; 197 mEvents.add(event); 198 return mCount >= mTargetCount; 199 } 200 return false; 201 } 202 } 203 204 @Test testScrollEventsClearedOnDetach()205 public void testScrollEventsClearedOnDetach() throws Throwable { 206 ScrollEventFilter scrollEventFilter = new ScrollEventFilter(1); 207 sUiAutomation.executeAndWaitForEvent( 208 () -> sInstrumentation.runOnMainSync( 209 () -> { 210 mChildView.scrollTo(0, 25); 211 mChildView.scrollTo(5, 50); 212 mChildView.scrollTo(7, 100); 213 }), 214 scrollEventFilter, 215 DEFAULT_TIMEOUT_MS); 216 mActivityRule.runOnUiThread( 217 () -> { 218 mParentView.removeView(mChildView); 219 mParentView.addView(mChildView); 220 }); 221 sUiAutomation.executeAndWaitForEvent( 222 () -> sInstrumentation.runOnMainSync( 223 () -> { 224 mChildView.scrollTo(0, 150); 225 }), 226 scrollEventFilter, 227 DEFAULT_TIMEOUT_MS); 228 AccessibilityEvent event = scrollEventFilter.getLastEvent(); 229 assertEquals(-7, event.getScrollDeltaX()); 230 assertEquals(50, event.getScrollDeltaY()); 231 } 232 233 @Test testScrollEventsCaptureTotalDelta()234 public void testScrollEventsCaptureTotalDelta() throws Throwable { 235 ScrollEventFilter scrollEventFilter = new ScrollEventFilter(1); 236 sUiAutomation.executeAndWaitForEvent( 237 () -> sInstrumentation.runOnMainSync( 238 () -> { 239 mChildView.scrollTo(0, 25); 240 mChildView.scrollTo(5, 50); 241 mChildView.scrollTo(7, 100); 242 }), 243 scrollEventFilter, 244 DEFAULT_TIMEOUT_MS); 245 AccessibilityEvent event = scrollEventFilter.getLastEvent(); 246 assertEquals(7, event.getScrollDeltaX()); 247 assertEquals(100, event.getScrollDeltaY()); 248 } 249 250 @Test testScrollEventsClearDeltaAfterSending()251 public void testScrollEventsClearDeltaAfterSending() throws Throwable { 252 ScrollEventFilter scrollEventFilter = new ScrollEventFilter(2); 253 sUiAutomation.executeAndWaitForEvent( 254 () -> { 255 sInstrumentation.runOnMainSync(() -> { 256 mChildView.scrollTo(0, 25); 257 mChildView.scrollTo(5, 50); 258 mChildView.scrollTo(7, 100); 259 }); 260 SystemClock.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); 261 sInstrumentation.runOnMainSync(() -> { 262 mChildView.scrollTo(0, 25); 263 mChildView.scrollTo(5, 50); 264 mChildView.scrollTo(7, 100); 265 mChildView.scrollTo(0, 150); 266 }); 267 }, 268 scrollEventFilter, 269 DEFAULT_TIMEOUT_MS); 270 AccessibilityEvent event = scrollEventFilter.getLastEvent(); 271 assertEquals(-7, event.getScrollDeltaX()); 272 assertEquals(50, event.getScrollDeltaY()); 273 } 274 275 @Test testStateEvent()276 public void testStateEvent() throws Throwable { 277 sUiAutomation.executeAndWaitForEvent( 278 () -> { 279 sendStateDescriptionChangedEvent(mChildView); 280 }, 281 new StateDescriptionEventFilter(1), 282 DEFAULT_TIMEOUT_MS); 283 } 284 285 @Test testStateEventBurstCombined()286 public void testStateEventBurstCombined() throws Throwable { 287 sUiAutomation.executeAndWaitForEvent( 288 () -> { 289 sendStateDescriptionChangedEvent(mChildView); 290 sendStateDescriptionChangedEvent(mChildView); 291 sendStateDescriptionChangedEvent(mChildView); 292 sendStateDescriptionChangedEvent(mChildView); 293 }, 294 new StateDescriptionEventFilter(1), 295 DEFAULT_TIMEOUT_MS); 296 } 297 298 @Test testStateEventsDeliveredInCorrectInterval()299 public void testStateEventsDeliveredInCorrectInterval() throws Throwable { 300 sUiAutomation.executeAndWaitForEvent( 301 () -> { 302 sendStateDescriptionChangedEvent(mChildView); 303 sendStateDescriptionChangedEvent(mChildView); 304 sendStateDescriptionChangedEvent(mChildView); 305 SystemClock.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS * 2); 306 sendStateDescriptionChangedEvent(mChildView); 307 sendStateDescriptionChangedEvent(mChildView); 308 SystemClock.sleep(SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS / 2); 309 sendStateDescriptionChangedEvent(mChildView); 310 }, 311 new StateDescriptionEventFilter(2), 312 DEFAULT_TIMEOUT_MS); 313 } 314 315 @Test testStateEventsHaveLastEventText()316 public void testStateEventsHaveLastEventText() throws Throwable { 317 StateDescriptionEventFilter stateDescriptionEventFilter = 318 new StateDescriptionEventFilter(1); 319 String expectedState = "Second state"; 320 sUiAutomation.executeAndWaitForEvent( 321 () -> { 322 sendStateDescriptionChangedEvent(mChildView, "First state"); 323 sendStateDescriptionChangedEvent(mChildView, expectedState); 324 }, 325 stateDescriptionEventFilter, 326 DEFAULT_TIMEOUT_MS); 327 AccessibilityEvent event = stateDescriptionEventFilter.getLastEvent(); 328 assertEquals(expectedState, event.getText().get(0)); 329 } 330 331 class StateDescriptionEventFilter extends AccessibilityEventFilter { 332 private int mCount; 333 private int mTargetCount; 334 StateDescriptionEventFilter(int count)335 StateDescriptionEventFilter(int count) { 336 mTargetCount = count; 337 } 338 accept(AccessibilityEvent event)339 public boolean accept(AccessibilityEvent event) { 340 if (event.getContentChangeTypes() 341 == AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) { 342 mCount += 1; 343 mEvents.add(event); 344 return mCount >= mTargetCount; 345 } 346 return false; 347 } 348 } 349 ; 350 351 private abstract class AccessibilityEventFilter 352 implements UiAutomation.AccessibilityEventFilter { 353 protected List<AccessibilityEvent> mEvents = new ArrayList<>(); 354 accept(AccessibilityEvent event)355 public abstract boolean accept(AccessibilityEvent event); 356 assertReceivedEventCount(int count)357 void assertReceivedEventCount(int count) { 358 assertEquals(count, mEvents.size()); 359 } 360 getLastEvent()361 AccessibilityEvent getLastEvent() { 362 if (mEvents.size() > 0) { 363 return mEvents.get(mEvents.size() - 1); 364 } 365 return null; 366 } 367 } 368 sendStateDescriptionChangedEvent(View view)369 private void sendStateDescriptionChangedEvent(View view) { 370 sendStateDescriptionChangedEvent(view, null); 371 } 372 sendStateDescriptionChangedEvent(View view, CharSequence text)373 private void sendStateDescriptionChangedEvent(View view, CharSequence text) { 374 AccessibilityEvent event = 375 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 376 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 377 event.getText().add(text); 378 view.sendAccessibilityEventUnchecked(event); 379 } 380 381 @Test setText_unChanged_doNotReceiveEvent()382 public void setText_unChanged_doNotReceiveEvent() throws Throwable { 383 sUiAutomation.executeAndWaitForEvent( 384 () -> sInstrumentation.runOnMainSync(() -> mTextView.setText("a")), 385 event -> isExpectedChangeType(event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT), 386 DEFAULT_TIMEOUT_MS); 387 388 assertThrows( 389 TimeoutException.class, 390 () -> 391 sUiAutomation.executeAndWaitForEvent( 392 () -> { 393 sInstrumentation.runOnMainSync( 394 () -> { 395 mTextView.setText("a"); 396 }); 397 }, 398 event -> isExpectedSource(event, mTextView), 399 DEFAULT_TIMEOUT_MS)); 400 } 401 402 @Test setText_textChanged_receivesTextEvent()403 public void setText_textChanged_receivesTextEvent() throws Throwable { 404 sUiAutomation.executeAndWaitForEvent( 405 () -> sInstrumentation.runOnMainSync(() -> mTextView.setText("a")), 406 event -> isExpectedChangeType(event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT), 407 DEFAULT_TIMEOUT_MS); 408 409 sUiAutomation.executeAndWaitForEvent( 410 () -> { 411 sInstrumentation.runOnMainSync( 412 () -> { 413 mTextView.setText("b"); 414 }); 415 }, 416 event -> 417 isExpectedSource(event, mTextView) 418 && isExpectedChangeType( 419 event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT), 420 DEFAULT_TIMEOUT_MS); 421 } 422 423 @Test setText_parcelableSpanChanged_receivesUndefinedEvent()424 public void setText_parcelableSpanChanged_receivesUndefinedEvent() throws Throwable { 425 String text = "a"; 426 sUiAutomation.executeAndWaitForEvent( 427 () -> sInstrumentation.runOnMainSync(() -> mTextView.setText(text)), 428 event -> isExpectedChangeType(event, AccessibilityEvent.CONTENT_CHANGE_TYPE_TEXT), 429 DEFAULT_TIMEOUT_MS); 430 431 sUiAutomation.executeAndWaitForEvent( 432 () -> { 433 sInstrumentation.runOnMainSync( 434 () -> { 435 SpannableString spannableString = new SpannableString(text); 436 spannableString.setSpan(new LocaleSpan(Locale.ENGLISH), 0, 1, 0); 437 mTextView.setText(spannableString); 438 }); 439 }, 440 event -> 441 isExpectedSource(event, mTextView) 442 && isExpectedChangeType( 443 event, AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED), 444 DEFAULT_TIMEOUT_MS); 445 } 446 isExpectedSource(AccessibilityEvent event, View view)447 private static boolean isExpectedSource(AccessibilityEvent event, View view) { 448 return TextUtils.equals(view.getContext().getPackageName(), event.getPackageName()) 449 && TextUtils.equals(view.getAccessibilityClassName(), event.getClassName()); 450 } 451 isExpectedChangeType(AccessibilityEvent event, int changeType)452 private static boolean isExpectedChangeType(AccessibilityEvent event, int changeType) { 453 return (event.getContentChangeTypes() & changeType) == changeType; 454 } 455 456 /** 457 * Tests whether accessibility events are correctly written and read from a parcel (version 1). 458 */ 459 @SmallTest 460 @Test testMarshaling()461 public void testMarshaling() throws Exception { 462 // fully populate the event to marshal 463 AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); 464 fullyPopulateAccessibilityEvent(sentEvent); 465 466 // marshal and unmarshal the event 467 Parcel parcel = Parcel.obtain(); 468 sentEvent.writeToParcel(parcel, 0); 469 parcel.setDataPosition(0); 470 AccessibilityEvent receivedEvent = AccessibilityEvent.CREATOR.createFromParcel(parcel); 471 472 // make sure all fields properly marshaled 473 assertEqualsAccessibilityEvent(sentEvent, receivedEvent); 474 475 parcel.recycle(); 476 } 477 478 /** Tests if {@link AccessibilityEvent} can be acquired through obtain(). */ 479 @SmallTest 480 @Test testRecycle()481 public void testRecycle() { 482 // evaluate that recycle() can be called on an event acquired by obtain() 483 AccessibilityEvent.obtain().recycle(); 484 } 485 486 /** Tests whether the event types are correctly converted to strings. */ 487 @SmallTest 488 @Test testEventTypeToString()489 public void testEventTypeToString() { 490 assertEquals( 491 "TYPE_NOTIFICATION_STATE_CHANGED", 492 AccessibilityEvent.eventTypeToString( 493 AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)); 494 assertEquals( 495 "TYPE_TOUCH_EXPLORATION_GESTURE_END", 496 AccessibilityEvent.eventTypeToString( 497 AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END)); 498 assertEquals( 499 "TYPE_TOUCH_EXPLORATION_GESTURE_START", 500 AccessibilityEvent.eventTypeToString( 501 AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START)); 502 assertEquals( 503 "TYPE_VIEW_CLICKED", 504 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_CLICKED)); 505 assertEquals( 506 "TYPE_VIEW_FOCUSED", 507 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_FOCUSED)); 508 assertEquals( 509 "TYPE_VIEW_HOVER_ENTER", 510 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)); 511 assertEquals( 512 "TYPE_VIEW_HOVER_EXIT", 513 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT)); 514 assertEquals( 515 "TYPE_VIEW_LONG_CLICKED", 516 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED)); 517 assertEquals( 518 "TYPE_VIEW_CONTEXT_CLICKED", 519 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED)); 520 assertEquals( 521 "TYPE_VIEW_SCROLLED", 522 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_SCROLLED)); 523 assertEquals( 524 "TYPE_VIEW_SELECTED", 525 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_SELECTED)); 526 assertEquals( 527 "TYPE_VIEW_TEXT_CHANGED", 528 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED)); 529 assertEquals( 530 "TYPE_VIEW_TEXT_SELECTION_CHANGED", 531 AccessibilityEvent.eventTypeToString( 532 AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED)); 533 assertEquals( 534 "TYPE_WINDOW_CONTENT_CHANGED", 535 AccessibilityEvent.eventTypeToString( 536 AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)); 537 assertEquals( 538 "TYPE_WINDOW_STATE_CHANGED", 539 AccessibilityEvent.eventTypeToString(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)); 540 } 541 542 /** Tests whether the event describes its contents consistently. */ 543 @SmallTest 544 @Test testDescribeContents()545 public void testDescribeContents() { 546 AccessibilityEvent event = AccessibilityEvent.obtain(); 547 assertSame( 548 "Accessibility events always return 0 for this method.", 549 0, 550 event.describeContents()); 551 fullyPopulateAccessibilityEvent(event); 552 assertSame( 553 "Accessibility events always return 0 for this method.", 554 0, 555 event.describeContents()); 556 } 557 558 /** 559 * Tests whether accessibility events are correctly written and read from a parcel (version 2). 560 */ 561 @SmallTest 562 @Test testMarshaling2()563 public void testMarshaling2() { 564 // fully populate the event to marshal 565 AccessibilityEvent marshaledEvent = AccessibilityEvent.obtain(); 566 fullyPopulateAccessibilityEvent(marshaledEvent); 567 568 // marshal and unmarshal the event 569 Parcel parcel = Parcel.obtain(); 570 marshaledEvent.writeToParcel(parcel, 0); 571 parcel.setDataPosition(0); 572 AccessibilityEvent unmarshaledEvent = AccessibilityEvent.obtain(); 573 unmarshaledEvent.initFromParcel(parcel); 574 575 // make sure all fields properly marshaled 576 assertEqualsAccessibilityEvent(marshaledEvent, unmarshaledEvent); 577 578 parcel.recycle(); 579 } 580 581 /** 582 * While CharSequence is immutable, some classes implementing it are mutable. Make sure they 583 * can't change the object by changing the objects backing CharSequence 584 */ 585 @SmallTest 586 @Test testChangeTextAfterSetting_shouldNotAffectEvent()587 public void testChangeTextAfterSetting_shouldNotAffectEvent() { 588 final String originalText = "Cassowary"; 589 final String newText = "Hornbill"; 590 AccessibilityEvent event = AccessibilityEvent.obtain(); 591 StringBuffer updatingString = new StringBuffer(originalText); 592 event.setBeforeText(updatingString); 593 event.setContentDescription(updatingString); 594 595 updatingString.delete(0, updatingString.length()); 596 updatingString.append(newText); 597 598 assertTrue(TextUtils.equals(originalText, event.getBeforeText())); 599 assertTrue(TextUtils.equals(originalText, event.getContentDescription())); 600 } 601 602 @SmallTest 603 @Test testConstructors()604 public void testConstructors() { 605 final AccessibilityEvent populatedEvent = new AccessibilityEvent(); 606 fullyPopulateAccessibilityEvent(populatedEvent); 607 final AccessibilityEvent event = new AccessibilityEvent(populatedEvent); 608 609 assertEqualsAccessibilityEvent(event, populatedEvent); 610 611 final AccessibilityEvent firstEvent = new AccessibilityEvent(); 612 firstEvent.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED); 613 final AccessibilityEvent secondEvent = 614 new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 615 616 assertEqualsAccessibilityEvent(firstEvent, secondEvent); 617 } 618 619 /** 620 * Fully populates the {@link AccessibilityEvent} to marshal. 621 * 622 * @param sentEvent The event to populate. 623 */ fullyPopulateAccessibilityEvent(AccessibilityEvent sentEvent)624 private void fullyPopulateAccessibilityEvent(AccessibilityEvent sentEvent) { 625 sentEvent.setAddedCount(1); 626 sentEvent.setBeforeText("BeforeText"); 627 sentEvent.setChecked(true); 628 sentEvent.setClassName("foo.bar.baz.Class"); 629 sentEvent.setContentDescription("ContentDescription"); 630 sentEvent.setCurrentItemIndex(1); 631 sentEvent.setEnabled(true); 632 sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED); 633 sentEvent.setEventTime(1000); 634 sentEvent.setFromIndex(1); 635 sentEvent.setFullScreen(true); 636 sentEvent.setItemCount(1); 637 sentEvent.setPackageName("foo.bar.baz"); 638 sentEvent.setParcelableData(Message.obtain(null, 1, 2, 3)); 639 sentEvent.setPassword(true); 640 sentEvent.setRemovedCount(1); 641 sentEvent.getText().add("Foo"); 642 sentEvent.setMaxScrollX(1); 643 sentEvent.setMaxScrollY(1); 644 sentEvent.setScrollX(1); 645 sentEvent.setScrollY(1); 646 sentEvent.setScrollDeltaX(3); 647 sentEvent.setScrollDeltaY(3); 648 sentEvent.setToIndex(1); 649 sentEvent.setScrollable(true); 650 sentEvent.setAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 651 sentEvent.setMovementGranularity(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE); 652 sentEvent.setDisplayId(Display.DEFAULT_DISPLAY); 653 sentEvent.setSpeechStateChangeTypes(AccessibilityEvent.SPEECH_STATE_SPEAKING_START); 654 655 AccessibilityRecord record = AccessibilityRecord.obtain(); 656 AccessibilityRecordTest.fullyPopulateAccessibilityRecord(record); 657 sentEvent.appendRecord(record); 658 } 659 660 /** 661 * Compares all properties of the <code>expectedEvent</code> and the <code>receivedEvent</code> 662 * to verify that the received event is the one that is expected. 663 */ assertEqualsAccessibilityEvent( AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent)664 private static void assertEqualsAccessibilityEvent( 665 AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent) { 666 assertEquals( 667 "addedCount has incorrect value", 668 expectedEvent.getAddedCount(), 669 receivedEvent.getAddedCount()); 670 assertEquals( 671 "beforeText has incorrect value", 672 expectedEvent.getBeforeText(), 673 receivedEvent.getBeforeText()); 674 assertEquals( 675 "checked has incorrect value", 676 expectedEvent.isChecked(), 677 receivedEvent.isChecked()); 678 assertEquals( 679 "className has incorrect value", 680 expectedEvent.getClassName(), 681 receivedEvent.getClassName()); 682 assertEquals( 683 "contentDescription has incorrect value", 684 expectedEvent.getContentDescription(), 685 receivedEvent.getContentDescription()); 686 assertEquals( 687 "currentItemIndex has incorrect value", 688 expectedEvent.getCurrentItemIndex(), 689 receivedEvent.getCurrentItemIndex()); 690 assertEquals( 691 "enabled has incorrect value", 692 expectedEvent.isEnabled(), 693 receivedEvent.isEnabled()); 694 assertEquals( 695 "eventType has incorrect value", 696 expectedEvent.getEventType(), 697 receivedEvent.getEventType()); 698 assertEquals( 699 "fromIndex has incorrect value", 700 expectedEvent.getFromIndex(), 701 receivedEvent.getFromIndex()); 702 assertEquals( 703 "fullScreen has incorrect value", 704 expectedEvent.isFullScreen(), 705 receivedEvent.isFullScreen()); 706 assertEquals( 707 "itemCount has incorrect value", 708 expectedEvent.getItemCount(), 709 receivedEvent.getItemCount()); 710 assertEquals( 711 "password has incorrect value", 712 expectedEvent.isPassword(), 713 receivedEvent.isPassword()); 714 assertEquals( 715 "removedCount has incorrect value", 716 expectedEvent.getRemovedCount(), 717 receivedEvent.getRemovedCount()); 718 assertSame( 719 "maxScrollX has incorrect value", 720 expectedEvent.getMaxScrollX(), 721 receivedEvent.getMaxScrollX()); 722 assertSame( 723 "maxScrollY has incorrect value", 724 expectedEvent.getMaxScrollY(), 725 receivedEvent.getMaxScrollY()); 726 assertSame( 727 "scrollX has incorrect value", 728 expectedEvent.getScrollX(), 729 receivedEvent.getScrollX()); 730 assertSame( 731 "scrollY has incorrect value", 732 expectedEvent.getScrollY(), 733 receivedEvent.getScrollY()); 734 assertSame( 735 "scrollDeltaX has incorrect value", 736 expectedEvent.getScrollDeltaX(), 737 receivedEvent.getScrollDeltaX()); 738 assertSame( 739 "scrollDeltaY has incorrect value", 740 expectedEvent.getScrollDeltaY(), 741 receivedEvent.getScrollDeltaY()); 742 assertSame( 743 "toIndex has incorrect value", 744 expectedEvent.getToIndex(), 745 receivedEvent.getToIndex()); 746 assertSame( 747 "scrollable has incorrect value", 748 expectedEvent.isScrollable(), 749 receivedEvent.isScrollable()); 750 assertSame( 751 "granularity has incorrect value", 752 expectedEvent.getMovementGranularity(), 753 receivedEvent.getMovementGranularity()); 754 assertSame( 755 "action has incorrect value", expectedEvent.getAction(), receivedEvent.getAction()); 756 assertSame( 757 "windowChangeTypes has incorrect value", 758 expectedEvent.getWindowChanges(), 759 receivedEvent.getWindowChanges()); 760 assertEquals( 761 "speechStateChangeTypes has incorrect value,", 762 expectedEvent.getSpeechStateChangeTypes(), 763 receivedEvent.getSpeechStateChangeTypes()); 764 765 AccessibilityRecordTest.assertEqualsText(expectedEvent.getText(), receivedEvent.getText()); 766 AccessibilityRecordTest.assertEqualAccessibilityRecord(expectedEvent, receivedEvent); 767 768 assertEqualAppendedRecord(expectedEvent, receivedEvent); 769 } 770 assertEqualAppendedRecord( AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent)771 private static void assertEqualAppendedRecord( 772 AccessibilityEvent expectedEvent, AccessibilityEvent receivedEvent) { 773 assertEquals( 774 "recordCount has incorrect value", 775 expectedEvent.getRecordCount(), 776 receivedEvent.getRecordCount()); 777 if (expectedEvent.getRecordCount() != 0 && receivedEvent.getRecordCount() != 0) { 778 AccessibilityRecord expectedRecord = expectedEvent.getRecord(0); 779 AccessibilityRecord receivedRecord = receivedEvent.getRecord(0); 780 AccessibilityRecordTest.assertEqualAccessibilityRecord(expectedRecord, receivedRecord); 781 } 782 } 783 } 784