AccessibilityEvent.java revision e4aa13b20166219a62916a92294055e7cc5c9f10
1/* 2 * Copyright (C) 2009 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 android.view.accessibility; 18 19import android.accessibilityservice.IAccessibilityServiceConnection; 20import android.os.Parcel; 21import android.os.Parcelable; 22import android.text.TextUtils; 23 24import java.util.ArrayList; 25import java.util.List; 26 27/** 28 * <p> 29 * This class represents accessibility events that are sent by the system when 30 * something notable happens in the user interface. For example, when a 31 * {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc. 32 * </p> 33 * <p> 34 * An accessibility event is fired by an individual view which populates the event with 35 * data for its state and requests from its parent to send the event to interested 36 * parties. The parent can optionally add an {@link AccessibilityRecord} for itself before 37 * dispatching a similar request to its parent. A parent can also choose not to respect the 38 * request for sending an event. The accessibility event is sent by the topmost view in the 39 * view tree. Therefore, an {@link android.accessibilityservice.AccessibilityService} can 40 * explore all records in an accessibility event to obtain more information about the 41 * context in which the event was fired. 42 * </p> 43 * <p> 44 * The main purpose of an accessibility event is to expose enough information for an 45 * {@link android.accessibilityservice.AccessibilityService} to provide meaningful feedback 46 * to the user. Sometimes however, an accessibility service may need more contextual 47 * information then the one in the event pay-load. In such cases the service can obtain 48 * the event source which is an {@link AccessibilityNodeInfo} (snapshot of a View state) 49 * which can be used for exploring the window content. Note that the privilege for accessing 50 * an event's source, thus the window content, has to be explicitly requested. For more 51 * details refer to {@link android.accessibilityservice.AccessibilityService}. If an 52 * accessibility service has not requested to retrieve the window content the event will 53 * not contain reference to its source. Also for events of type 54 * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available. 55 * </p> 56 * <p> 57 * This class represents various semantically different accessibility event 58 * types. Each event type has an associated set of related properties. In other 59 * words, each event type is characterized via a subset of the properties exposed 60 * by this class. For each event type there is a corresponding constant defined 61 * in this class. Follows a specification of the event types and their associated properties: 62 * </p> 63 * <p> 64 * <b>VIEW TYPES</b></br> 65 * </p> 66 * <p> 67 * <b>View clicked</b> - represents the event of clicking on a {@link android.view.View} 68 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.</br> 69 * <em>Type:</em>{@link #TYPE_VIEW_CLICKED}</br> 70 * <em>Properties:</em></br> 71 * <ul> 72 * <li>{@link #getSource()} - The source info (for registered clients).</li> 73 * <li>{@link #getClassName()} - The class name of the source.</li> 74 * <li>{@link #getPackageName()} - The package name of the source.</li> 75 * <li>{@link #getEventTime()} - The event time.</li> 76 * <li>{@link #getText()} - The text of the source.</li> 77 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 78 * <li>{@link #isPassword()} - Whether the source is password.</li> 79 * <li>{@link #isChecked()} - Whether the source is checked.</li> 80 * </ul> 81 * </p> 82 * <p> 83 * <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View} 84 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc </br> 85 * <em>Type:</em>{@link #TYPE_VIEW_LONG_CLICKED}</br> 86 * <em>Properties:</em></br> 87 * <ul> 88 * <li>{@link #getSource()} - The source info (for registered clients).</li> 89 * <li>{@link #getClassName()} - The class name of the source.</li> 90 * <li>{@link #getPackageName()} - The package name of the source.</li> 91 * <li>{@link #getEventTime()} - The event time.</li> 92 * <li>{@link #getText()} - The text of the source.</li> 93 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 94 * <li>{@link #isPassword()} - Whether the source is password.</li> 95 * <li>{@link #isChecked()} - Whether the source is checked.</li> 96 * </ul> 97 * </p> 98 * <p> 99 * <b>View selected</b> - represents the event of selecting an item usually in 100 * the context of an {@link android.widget.AdapterView}.</br> 101 * <em>Type:</em> {@link #TYPE_VIEW_SELECTED}</br> 102 * <em>Properties:</em></br> 103 * <ul> 104 * <li>{@link #getSource()} - The source info (for registered clients).</li> 105 * <li>{@link #getClassName()} - The class name of the source.</li> 106 * <li>{@link #getPackageName()} - The package name of the source.</li> 107 * <li>{@link #getEventTime()} - The event time.</li> 108 * <li>{@link #getText()} - The text of the source.</li> 109 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 110 * <li>{@link #isPassword()} - Whether the source is password.</li> 111 * <li>{@link #isChecked()} - Whether the source is checked.</li> 112 * <li>{@link #getItemCount()} - The number of selectable items of the source.</li> 113 * <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li> 114 * </ul> 115 * </p> 116 * <p> 117 * <b>View focused</b> - represents the event of focusing a 118 * {@link android.view.View}.</br> 119 * <em>Type:</em> {@link #TYPE_VIEW_FOCUSED}</br> 120 * <em>Properties:</em></br> 121 * <ul> 122 * <li>{@link #getSource()} - The source info (for registered clients).</li> 123 * <li>{@link #getClassName()} - The class name of the source.</li> 124 * <li>{@link #getPackageName()} - The package name of the source.</li> 125 * <li>{@link #getEventTime()} - The event time.</li> 126 * <li>{@link #getText()} - The text of the source.</li> 127 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 128 * <li>{@link #isPassword()} - Whether the source is password.</li> 129 * <li>{@link #isChecked()} - Whether the source is checked.</li> 130 * <li>{@link #getItemCount()} - The number of focusable items on the screen.</li> 131 * <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li> 132 * </ul> 133 * </p> 134 * <p> 135 * <b>View text changed</b> - represents the event of changing the text of an 136 * {@link android.widget.EditText}.</br> 137 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_CHANGED}</br> 138 * <em>Properties:</em></br> 139 * <ul> 140 * <li>{@link #getSource()} - The source info (for registered clients).</li> 141 * <li>{@link #getClassName()} - The class name of the source.</li> 142 * <li>{@link #getPackageName()} - The package name of the source.</li> 143 * <li>{@link #getEventTime()} - The event time.</li> 144 * <li>{@link #getText()} - The text of the source.</li> 145 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 146 * <li>{@link #isPassword()} - Whether the source is password.</li> 147 * <li>{@link #isChecked()} - Whether the source is checked.</li> 148 * <li>{@link #getFromIndex()} - The text change start index.</li> 149 * <li>{@link #getAddedCount()} - The number of added characters.</li> 150 * <li>{@link #getRemovedCount()} - The number of removed characters.</li> 151 * <li>{@link #getBeforeText()} - The text of the source before the change.</li> 152 * </ul> 153 * </p> 154 * <p> 155 * <b>View text selection changed</b> - represents the event of changing the text 156 * selection of an {@link android.widget.EditText}.</br> 157 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} </br> 158 * <em>Properties:</em></br> 159 * <ul> 160 * <li>{@link #getSource()} - The source info (for registered clients).</li> 161 * <li>{@link #getClassName()} - The class name of the source.</li> 162 * <li>{@link #getPackageName()} - The package name of the source.</li> 163 * <li>{@link #getEventTime()} - The event time.</li> 164 * <li>{@link #getText()} - The text of the source.</li> 165 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 166 * <li>{@link #isPassword()} - Whether the source is password.</li> 167 * <li>{@link #getFromIndex()} - The selection start index.</li> 168 * <li>{@link #getToIndex()} - The selection end index.</li> 169 * <li>{@link #getItemCount()} - The length of the source text.</li> 170 * </ul> 171 * </p> 172 * <p> 173 * <b>View scrolled</b> - represents the event of scrolling a view. If 174 * the source is a descendant of {@link android.widget.AdapterView} the 175 * scroll is reported in terms of visible items - the first visible item, 176 * the last visible item, and the total items - because the the source 177 * is unaware if its pixel size since its adapter is responsible for 178 * creating views. In all other cases the scroll is reported as the current 179 * scroll on the X and Y axis respectively plus the height of the source in 180 * pixels.</br> 181 * <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br> 182 * <em>Properties:</em></br> 183 * <ul> 184 * <li>{@link #getSource()} - The source info (for registered clients).</li> 185 * <li>{@link #getClassName()} - The class name of the source.</li> 186 * <li>{@link #getPackageName()} - The package name of the source.</li> 187 * <li>{@link #getEventTime()} - The event time.</li> 188 * <li>{@link #getText()} - The text of the source.</li> 189 * <li>{@link #isEnabled()} - Whether the source is enabled.</li> 190 * <li>{@link #getScrollX()} - The horizontal offset of the source 191 * (without descendants of AdapterView)).</li> 192 * <li>{@link #getScrollY()} - The vertical offset of the source 193 * (without descendants of AdapterView)).</li> 194 * <li>{@link #getFromIndex()} - The index of the first visible item of the source 195 * (for descendants of AdapterView).</li> 196 * <li>{@link #getToIndex()} - The index of the last visible item of the source 197 * (for descendants of AdapterView).</li> 198 * <li>{@link #getItemCount()} - The total items of the source (for descendants of AdapterView) 199 * or the height of the source in pixels (all other cases).</li> 200 * </ul> 201 * </p> 202 * <p> 203 * <b>TRANSITION TYPES</b></br> 204 * </p> 205 * <b>Window state changed</b> - represents the event of opening a 206 * {@link android.widget.PopupWindow}, {@link android.view.Menu}, 207 * {@link android.app.Dialog}, etc.</br> 208 * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br> 209 * <em>Properties:</em></br> 210 * <ul> 211 * <li>{@link #getSource()} - The source info (for registered clients).</li> 212 * <li>{@link #getClassName()} - The class name of the source.</li> 213 * <li>{@link #getPackageName()} - The package name of the source.</li> 214 * <li>{@link #getEventTime()} - The event time.</li> 215 * <li>{@link #getText()} - The text of the source.</li> 216 * </ul> 217 * </p> 218 * <p> 219 * <b>Window content changed</b> - represents the event of change in the 220 * content of a window. This change can be adding/removing view, changing 221 * a view size, etc.</br> 222 * <p> 223 * <strong>Note:</strong> This event is fired only for the window source of the 224 * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED}) 225 * and its purpose is to notify clients that the content of the user interaction 226 * window has changed. 227 * </p> 228 * <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br> 229 * <em>Properties:</em></br> 230 * <ul> 231 * <li>{@link #getSource()} - The source info (for registered clients).</li> 232 * <li>{@link #getClassName()} - The class name of the source.</li> 233 * <li>{@link #getPackageName()} - The package name of the source.</li> 234 * <li>{@link #getEventTime()} - The event time.</li> 235 * </ul> 236 * <p> 237 * <b>NOTIFICATION TYPES</b></br> 238 * <p> 239 * <b>Notification state changed</b> - represents the event showing 240 * {@link android.app.Notification}. 241 * <em>Type:</em> {@link #TYPE_NOTIFICATION_STATE_CHANGED}</br> 242 * <em>Properties:</em></br> 243 * <ul> 244 * <li>{@link #getClassName()} - The class name of the source.</li> 245 * <li>{@link #getPackageName()} - The package name of the source.</li> 246 * <li>{@link #getEventTime()} - The event time.</li> 247 * <li>{@link #getText()} - The text of the source.</li> 248 * <li>{@link #getParcelableData()} - The posted {@link android.app.Notification}.</li> 249 * </ul> 250 * </p> 251 * <p> 252 * <b>Security note</b> 253 * <p> 254 * Since an event contains the text of its source privacy can be compromised by leaking 255 * sensitive information such as passwords. To address this issue any event fired in response 256 * to manipulation of a PASSWORD field does NOT CONTAIN the text of the password. 257 * 258 * @see android.view.accessibility.AccessibilityManager 259 * @see android.accessibilityservice.AccessibilityService 260 * @see AccessibilityNodeInfo 261 */ 262public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable { 263 private static final boolean DEBUG = false; 264 265 /** 266 * Invalid selection/focus position. 267 * 268 * @see #getCurrentItemIndex() 269 */ 270 public static final int INVALID_POSITION = -1; 271 272 /** 273 * Maximum length of the text fields. 274 * 275 * @see #getBeforeText() 276 * @see #getText() 277 * </br> 278 * Note: This constant is no longer needed since there 279 * is no limit on the length of text that is contained 280 * in an accessibility event anymore. 281 */ 282 @Deprecated 283 public static final int MAX_TEXT_LENGTH = 500; 284 285 /** 286 * Represents the event of clicking on a {@link android.view.View} like 287 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 288 */ 289 public static final int TYPE_VIEW_CLICKED = 0x00000001; 290 291 /** 292 * Represents the event of long clicking on a {@link android.view.View} like 293 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 294 */ 295 public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002; 296 297 /** 298 * Represents the event of selecting an item usually in the context of an 299 * {@link android.widget.AdapterView}. 300 */ 301 public static final int TYPE_VIEW_SELECTED = 0x00000004; 302 303 /** 304 * Represents the event of focusing a {@link android.view.View}. 305 */ 306 public static final int TYPE_VIEW_FOCUSED = 0x00000008; 307 308 /** 309 * Represents the event of changing the text of an {@link android.widget.EditText}. 310 */ 311 public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010; 312 313 /** 314 * Represents the event of opening a {@link android.widget.PopupWindow}, 315 * {@link android.view.Menu}, {@link android.app.Dialog}, etc. 316 */ 317 public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020; 318 319 /** 320 * Represents the event showing a {@link android.app.Notification}. 321 */ 322 public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040; 323 324 /** 325 * Represents the event of a hover enter over a {@link android.view.View}. 326 */ 327 public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080; 328 329 /** 330 * Represents the event of a hover exit over a {@link android.view.View}. 331 */ 332 public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100; 333 334 /** 335 * Represents the event of starting a touch exploration gesture. 336 */ 337 public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200; 338 339 /** 340 * Represents the event of ending a touch exploration gesture. 341 */ 342 public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400; 343 344 /** 345 * Represents the event of changing the content of a window. 346 */ 347 public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800; 348 349 /** 350 * Represents the event of scrolling a view. 351 */ 352 public static final int TYPE_VIEW_SCROLLED = 0x00001000; 353 354 /** 355 * Represents the event of changing the selection in an {@link android.widget.EditText}. 356 */ 357 public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000; 358 359 /** 360 * Mask for {@link AccessibilityEvent} all types. 361 * 362 * @see #TYPE_VIEW_CLICKED 363 * @see #TYPE_VIEW_LONG_CLICKED 364 * @see #TYPE_VIEW_SELECTED 365 * @see #TYPE_VIEW_FOCUSED 366 * @see #TYPE_VIEW_TEXT_CHANGED 367 * @see #TYPE_WINDOW_STATE_CHANGED 368 * @see #TYPE_NOTIFICATION_STATE_CHANGED 369 * @see #TYPE_VIEW_HOVER_ENTER 370 * @see #TYPE_VIEW_HOVER_EXIT 371 * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START 372 * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END 373 * @see #TYPE_WINDOW_CONTENT_CHANGED 374 * @see #TYPE_VIEW_SCROLLED 375 * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED 376 */ 377 public static final int TYPES_ALL_MASK = 0xFFFFFFFF; 378 379 private static final int MAX_POOL_SIZE = 10; 380 private static final Object sPoolLock = new Object(); 381 private static AccessibilityEvent sPool; 382 private static int sPoolSize; 383 private AccessibilityEvent mNext; 384 private boolean mIsInPool; 385 386 private int mEventType; 387 private CharSequence mPackageName; 388 private long mEventTime; 389 390 private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>(); 391 392 /* 393 * Hide constructor from clients. 394 */ 395 private AccessibilityEvent() { 396 } 397 398 /** 399 * Initialize an event from another one. 400 * 401 * @param event The event to initialize from. 402 */ 403 void init(AccessibilityEvent event) { 404 super.init(event); 405 mEventType = event.mEventType; 406 mEventTime = event.mEventTime; 407 mPackageName = event.mPackageName; 408 } 409 410 /** 411 * Sets the connection for interacting with the AccessibilityManagerService. 412 * 413 * @param connection The connection. 414 * 415 * @hide 416 */ 417 @Override 418 public void setConnection(IAccessibilityServiceConnection connection) { 419 super.setConnection(connection); 420 List<AccessibilityRecord> records = mRecords; 421 final int recordCount = records.size(); 422 for (int i = 0; i < recordCount; i++) { 423 AccessibilityRecord record = records.get(i); 424 record.setConnection(connection); 425 } 426 } 427 428 /** 429 * Sets if this instance is sealed. 430 * 431 * @param sealed Whether is sealed. 432 * 433 * @hide 434 */ 435 @Override 436 public void setSealed(boolean sealed) { 437 super.setSealed(sealed); 438 List<AccessibilityRecord> records = mRecords; 439 final int recordCount = records.size(); 440 for (int i = 0; i < recordCount; i++) { 441 AccessibilityRecord record = records.get(i); 442 record.setSealed(sealed); 443 } 444 } 445 446 /** 447 * Gets the number of records contained in the event. 448 * 449 * @return The number of records. 450 */ 451 public int getRecordCount() { 452 return mRecords.size(); 453 } 454 455 /** 456 * Appends an {@link AccessibilityRecord} to the end of event records. 457 * 458 * @param record The record to append. 459 * 460 * @throws IllegalStateException If called from an AccessibilityService. 461 */ 462 public void appendRecord(AccessibilityRecord record) { 463 enforceNotSealed(); 464 mRecords.add(record); 465 } 466 467 /** 468 * Gets the record at a given index. 469 * 470 * @param index The index. 471 * @return The record at the specified index. 472 */ 473 public AccessibilityRecord getRecord(int index) { 474 return mRecords.get(index); 475 } 476 477 /** 478 * Gets the event type. 479 * 480 * @return The event type. 481 */ 482 public int getEventType() { 483 return mEventType; 484 } 485 486 /** 487 * Sets the event type. 488 * 489 * @param eventType The event type. 490 * 491 * @throws IllegalStateException If called from an AccessibilityService. 492 */ 493 public void setEventType(int eventType) { 494 enforceNotSealed(); 495 mEventType = eventType; 496 } 497 498 /** 499 * Gets the time in which this event was sent. 500 * 501 * @return The event time. 502 */ 503 public long getEventTime() { 504 return mEventTime; 505 } 506 507 /** 508 * Sets the time in which this event was sent. 509 * 510 * @param eventTime The event time. 511 * 512 * @throws IllegalStateException If called from an AccessibilityService. 513 */ 514 public void setEventTime(long eventTime) { 515 enforceNotSealed(); 516 mEventTime = eventTime; 517 } 518 519 /** 520 * Gets the package name of the source. 521 * 522 * @return The package name. 523 */ 524 public CharSequence getPackageName() { 525 return mPackageName; 526 } 527 528 /** 529 * Sets the package name of the source. 530 * 531 * @param packageName The package name. 532 * 533 * @throws IllegalStateException If called from an AccessibilityService. 534 */ 535 public void setPackageName(CharSequence packageName) { 536 enforceNotSealed(); 537 mPackageName = packageName; 538 } 539 540 /** 541 * Returns a cached instance if such is available or a new one is 542 * instantiated with its type property set. 543 * 544 * @param eventType The event type. 545 * @return An instance. 546 */ 547 public static AccessibilityEvent obtain(int eventType) { 548 AccessibilityEvent event = AccessibilityEvent.obtain(); 549 event.setEventType(eventType); 550 return event; 551 } 552 553 /** 554 * Returns a cached instance if such is available or a new one is 555 * created. The returned instance is initialized from the given 556 * <code>event</code>. 557 * 558 * @param event The other event. 559 * @return An instance. 560 */ 561 public static AccessibilityEvent obtain(AccessibilityEvent event) { 562 AccessibilityEvent eventClone = AccessibilityEvent.obtain(); 563 eventClone.init(event); 564 565 final int recordCount = event.mRecords.size(); 566 for (int i = 0; i < recordCount; i++) { 567 AccessibilityRecord record = event.mRecords.get(i); 568 AccessibilityRecord recordClone = AccessibilityRecord.obtain(record); 569 eventClone.mRecords.add(recordClone); 570 } 571 572 return eventClone; 573 } 574 575 /** 576 * Returns a cached instance if such is available or a new one is 577 * instantiated. 578 * 579 * @return An instance. 580 */ 581 public static AccessibilityEvent obtain() { 582 synchronized (sPoolLock) { 583 if (sPool != null) { 584 AccessibilityEvent event = sPool; 585 sPool = sPool.mNext; 586 sPoolSize--; 587 event.mNext = null; 588 event.mIsInPool = false; 589 return event; 590 } 591 return new AccessibilityEvent(); 592 } 593 } 594 595 /** 596 * Recycles an instance back to be reused. 597 * <p> 598 * <b>Note: You must not touch the object after calling this function.</b> 599 * </p> 600 * 601 * @throws IllegalStateException If the event is already recycled. 602 */ 603 @Override 604 public void recycle() { 605 if (mIsInPool) { 606 throw new IllegalStateException("Event already recycled!"); 607 } 608 clear(); 609 synchronized (sPoolLock) { 610 if (sPoolSize <= MAX_POOL_SIZE) { 611 mNext = sPool; 612 sPool = this; 613 mIsInPool = true; 614 sPoolSize++; 615 } 616 } 617 } 618 619 /** 620 * Clears the state of this instance. 621 * 622 * @hide 623 */ 624 @Override 625 protected void clear() { 626 super.clear(); 627 mEventType = 0; 628 mPackageName = null; 629 mEventTime = 0; 630 while (!mRecords.isEmpty()) { 631 AccessibilityRecord record = mRecords.remove(0); 632 record.recycle(); 633 } 634 } 635 636 /** 637 * Creates a new instance from a {@link Parcel}. 638 * 639 * @param parcel A parcel containing the state of a {@link AccessibilityEvent}. 640 */ 641 public void initFromParcel(Parcel parcel) { 642 if (parcel.readInt() == 1) { 643 mConnection = IAccessibilityServiceConnection.Stub.asInterface( 644 parcel.readStrongBinder()); 645 } 646 setSealed(parcel.readInt() == 1); 647 mEventType = parcel.readInt(); 648 mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 649 mEventTime = parcel.readLong(); 650 readAccessibilityRecordFromParcel(this, parcel); 651 652 // Read the records. 653 final int recordCount = parcel.readInt(); 654 for (int i = 0; i < recordCount; i++) { 655 AccessibilityRecord record = AccessibilityRecord.obtain(); 656 // Do this to write the connection only once. 657 record.setConnection(mConnection); 658 readAccessibilityRecordFromParcel(record, parcel); 659 mRecords.add(record); 660 } 661 } 662 663 /** 664 * Reads an {@link AccessibilityRecord} from a parcel. 665 * 666 * @param record The record to initialize. 667 * @param parcel The parcel to read from. 668 */ 669 private void readAccessibilityRecordFromParcel(AccessibilityRecord record, 670 Parcel parcel) { 671 record.mBooleanProperties = parcel.readInt(); 672 record.mCurrentItemIndex = parcel.readInt(); 673 record.mItemCount = parcel.readInt(); 674 record.mFromIndex = parcel.readInt(); 675 record.mToIndex = parcel.readInt(); 676 record.mScrollX = parcel.readInt(); 677 record.mScrollY = parcel.readInt(); 678 record.mAddedCount = parcel.readInt(); 679 record.mRemovedCount = parcel.readInt(); 680 record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 681 record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 682 record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 683 record.mParcelableData = parcel.readParcelable(null); 684 parcel.readList(record.mText, null); 685 record.mSourceWindowId = parcel.readInt(); 686 record.mSourceViewId = parcel.readInt(); 687 record.mSealed = (parcel.readInt() == 1); 688 } 689 690 /** 691 * {@inheritDoc} 692 */ 693 public void writeToParcel(Parcel parcel, int flags) { 694 if (mConnection == null) { 695 parcel.writeInt(0); 696 } else { 697 parcel.writeInt(1); 698 parcel.writeStrongBinder(mConnection.asBinder()); 699 } 700 parcel.writeInt(isSealed() ? 1 : 0); 701 parcel.writeInt(mEventType); 702 TextUtils.writeToParcel(mPackageName, parcel, 0); 703 parcel.writeLong(mEventTime); 704 writeAccessibilityRecordToParcel(this, parcel, flags); 705 706 // Write the records. 707 final int recordCount = getRecordCount(); 708 parcel.writeInt(recordCount); 709 for (int i = 0; i < recordCount; i++) { 710 AccessibilityRecord record = mRecords.get(i); 711 writeAccessibilityRecordToParcel(record, parcel, flags); 712 } 713 } 714 715 /** 716 * Writes an {@link AccessibilityRecord} to a parcel. 717 * 718 * @param record The record to write. 719 * @param parcel The parcel to which to write. 720 */ 721 private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel, 722 int flags) { 723 parcel.writeInt(record.mBooleanProperties); 724 parcel.writeInt(record.mCurrentItemIndex); 725 parcel.writeInt(record.mItemCount); 726 parcel.writeInt(record.mFromIndex); 727 parcel.writeInt(record.mToIndex); 728 parcel.writeInt(record.mScrollX); 729 parcel.writeInt(record.mScrollY); 730 parcel.writeInt(record.mAddedCount); 731 parcel.writeInt(record.mRemovedCount); 732 TextUtils.writeToParcel(record.mClassName, parcel, flags); 733 TextUtils.writeToParcel(record.mContentDescription, parcel, flags); 734 TextUtils.writeToParcel(record.mBeforeText, parcel, flags); 735 parcel.writeParcelable(record.mParcelableData, flags); 736 parcel.writeList(record.mText); 737 parcel.writeInt(record.mSourceWindowId); 738 parcel.writeInt(record.mSourceViewId); 739 parcel.writeInt(record.mSealed ? 1 : 0); 740 } 741 742 /** 743 * {@inheritDoc} 744 */ 745 public int describeContents() { 746 return 0; 747 } 748 749 @Override 750 public String toString() { 751 StringBuilder builder = new StringBuilder(); 752 builder.append("EventType: ").append(eventTypeToString(mEventType)); 753 builder.append("; EventTime: ").append(mEventTime); 754 builder.append("; PackageName: ").append(mPackageName); 755 builder.append(super.toString()); 756 if (DEBUG) { 757 builder.append("\n"); 758 builder.append("; sourceWindowId: ").append(mSourceWindowId); 759 builder.append("; sourceViewId: ").append(mSourceViewId); 760 for (int i = 0; i < mRecords.size(); i++) { 761 AccessibilityRecord record = mRecords.get(i); 762 builder.append(" Record "); 763 builder.append(i); 764 builder.append(":"); 765 builder.append(" [ ClassName: " + record.mClassName); 766 builder.append("; Text: " + record.mText); 767 builder.append("; ContentDescription: " + record.mContentDescription); 768 builder.append("; ItemCount: " + record.mItemCount); 769 builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex); 770 builder.append("; IsEnabled: " + record.isEnabled()); 771 builder.append("; IsPassword: " + record.isPassword()); 772 builder.append("; IsChecked: " + record.isChecked()); 773 builder.append("; IsFullScreen: " + record.isFullScreen()); 774 builder.append("; Scrollable: " + record.isScrollable()); 775 builder.append("; BeforeText: " + record.mBeforeText); 776 builder.append("; FromIndex: " + record.mFromIndex); 777 builder.append("; ToIndex: " + record.mToIndex); 778 builder.append("; ScrollX: " + record.mScrollX); 779 builder.append("; ScrollY: " + record.mScrollY); 780 builder.append("; AddedCount: " + record.mAddedCount); 781 builder.append("; RemovedCount: " + record.mRemovedCount); 782 builder.append("; ParcelableData: " + record.mParcelableData); 783 builder.append(" ]"); 784 builder.append("\n"); 785 } 786 } else { 787 builder.append("; recordCount: ").append(getRecordCount()); 788 } 789 return builder.toString(); 790 } 791 792 /** 793 * Returns the string representation of an event type. For example, 794 * {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED. 795 * 796 * @param eventType The event type 797 * @return The string representation. 798 */ 799 public static String eventTypeToString(int eventType) { 800 switch (eventType) { 801 case TYPE_VIEW_CLICKED: 802 return "TYPE_VIEW_CLICKED"; 803 case TYPE_VIEW_LONG_CLICKED: 804 return "TYPE_VIEW_LONG_CLICKED"; 805 case TYPE_VIEW_SELECTED: 806 return "TYPE_VIEW_SELECTED"; 807 case TYPE_VIEW_FOCUSED: 808 return "TYPE_VIEW_FOCUSED"; 809 case TYPE_VIEW_TEXT_CHANGED: 810 return "TYPE_VIEW_TEXT_CHANGED"; 811 case TYPE_WINDOW_STATE_CHANGED: 812 return "TYPE_WINDOW_STATE_CHANGED"; 813 case TYPE_VIEW_HOVER_ENTER: 814 return "TYPE_VIEW_HOVER_ENTER"; 815 case TYPE_VIEW_HOVER_EXIT: 816 return "TYPE_VIEW_HOVER_EXIT"; 817 case TYPE_NOTIFICATION_STATE_CHANGED: 818 return "TYPE_NOTIFICATION_STATE_CHANGED"; 819 case TYPE_TOUCH_EXPLORATION_GESTURE_START: 820 return "TYPE_TOUCH_EXPLORATION_GESTURE_START"; 821 case TYPE_TOUCH_EXPLORATION_GESTURE_END: 822 return "TYPE_TOUCH_EXPLORATION_GESTURE_END"; 823 case TYPE_WINDOW_CONTENT_CHANGED: 824 return "TYPE_WINDOW_CONTENT_CHANGED"; 825 case TYPE_VIEW_TEXT_SELECTION_CHANGED: 826 return "TYPE_VIEW_TEXT_SELECTION_CHANGED"; 827 case TYPE_VIEW_SCROLLED: 828 return "TYPE_VIEW_SCROLLED"; 829 default: 830 return null; 831 } 832 } 833 834 /** 835 * @see Parcelable.Creator 836 */ 837 public static final Parcelable.Creator<AccessibilityEvent> CREATOR = 838 new Parcelable.Creator<AccessibilityEvent>() { 839 public AccessibilityEvent createFromParcel(Parcel parcel) { 840 AccessibilityEvent event = AccessibilityEvent.obtain(); 841 event.initFromParcel(parcel); 842 return event; 843 } 844 845 public AccessibilityEvent[] newArray(int size) { 846 return new AccessibilityEvent[size]; 847 } 848 }; 849} 850