AccessibilityEvent.java revision 38e8b4e5bc3c93affdffbc064fd9db5aeccc3e8e
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 * initialized with from the given <code>event</code>. 556 * 557 * @param event The other event. 558 * @return An instance. 559 */ 560 public static AccessibilityEvent obtain(AccessibilityEvent event) { 561 AccessibilityEvent eventClone = AccessibilityEvent.obtain(); 562 eventClone.init(event); 563 564 final int recordCount = event.mRecords.size(); 565 for (int i = 0; i < recordCount; i++) { 566 AccessibilityRecord record = event.mRecords.get(i); 567 AccessibilityRecord recordClone = AccessibilityRecord.obtain(record); 568 eventClone.mRecords.add(recordClone); 569 } 570 571 return eventClone; 572 } 573 574 /** 575 * Returns a cached instance if such is available or a new one is 576 * instantiated. 577 * 578 * @return An instance. 579 */ 580 public static AccessibilityEvent obtain() { 581 synchronized (sPoolLock) { 582 if (sPool != null) { 583 AccessibilityEvent event = sPool; 584 sPool = sPool.mNext; 585 sPoolSize--; 586 event.mNext = null; 587 event.mIsInPool = false; 588 return event; 589 } 590 return new AccessibilityEvent(); 591 } 592 } 593 594 /** 595 * Recycles an instance back to be reused. 596 * <p> 597 * <b>Note: You must not touch the object after calling this function.</b> 598 * </p> 599 * 600 * @throws IllegalStateException If the event is already recycled. 601 */ 602 @Override 603 public void recycle() { 604 if (mIsInPool) { 605 throw new IllegalStateException("Event already recycled!"); 606 } 607 clear(); 608 synchronized (sPoolLock) { 609 if (sPoolSize <= MAX_POOL_SIZE) { 610 mNext = sPool; 611 sPool = this; 612 mIsInPool = true; 613 sPoolSize++; 614 } 615 } 616 } 617 618 /** 619 * Clears the state of this instance. 620 * 621 * @hide 622 */ 623 @Override 624 protected void clear() { 625 super.clear(); 626 mEventType = 0; 627 mPackageName = null; 628 mEventTime = 0; 629 while (!mRecords.isEmpty()) { 630 AccessibilityRecord record = mRecords.remove(0); 631 record.recycle(); 632 } 633 } 634 635 /** 636 * Creates a new instance from a {@link Parcel}. 637 * 638 * @param parcel A parcel containing the state of a {@link AccessibilityEvent}. 639 */ 640 public void initFromParcel(Parcel parcel) { 641 if (parcel.readInt() == 1) { 642 mConnection = IAccessibilityServiceConnection.Stub.asInterface( 643 parcel.readStrongBinder()); 644 } 645 setSealed(parcel.readInt() == 1); 646 mEventType = parcel.readInt(); 647 mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 648 mEventTime = parcel.readLong(); 649 readAccessibilityRecordFromParcel(this, parcel); 650 651 // Read the records. 652 final int recordCount = parcel.readInt(); 653 for (int i = 0; i < recordCount; i++) { 654 AccessibilityRecord record = AccessibilityRecord.obtain(); 655 // Do this to write the connection only once. 656 record.setConnection(mConnection); 657 readAccessibilityRecordFromParcel(record, parcel); 658 mRecords.add(record); 659 } 660 } 661 662 /** 663 * Reads an {@link AccessibilityRecord} from a parcel. 664 * 665 * @param record The record to initialize. 666 * @param parcel The parcel to read from. 667 */ 668 private void readAccessibilityRecordFromParcel(AccessibilityRecord record, 669 Parcel parcel) { 670 record.mBooleanProperties = parcel.readInt(); 671 record.mCurrentItemIndex = parcel.readInt(); 672 record.mItemCount = parcel.readInt(); 673 record.mFromIndex = parcel.readInt(); 674 record.mToIndex = parcel.readInt(); 675 record.mScrollX = parcel.readInt(); 676 record.mScrollY = parcel.readInt(); 677 record.mAddedCount = parcel.readInt(); 678 record.mRemovedCount = parcel.readInt(); 679 record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 680 record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 681 record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 682 record.mParcelableData = parcel.readParcelable(null); 683 parcel.readList(record.mText, null); 684 record.mSourceWindowId = parcel.readInt(); 685 record.mSourceViewId = parcel.readInt(); 686 record.mSealed = (parcel.readInt() == 1); 687 } 688 689 /** 690 * {@inheritDoc} 691 */ 692 public void writeToParcel(Parcel parcel, int flags) { 693 if (mConnection == null) { 694 parcel.writeInt(0); 695 } else { 696 parcel.writeInt(1); 697 parcel.writeStrongBinder(mConnection.asBinder()); 698 } 699 parcel.writeInt(isSealed() ? 1 : 0); 700 parcel.writeInt(mEventType); 701 TextUtils.writeToParcel(mPackageName, parcel, 0); 702 parcel.writeLong(mEventTime); 703 writeAccessibilityRecordToParcel(this, parcel, flags); 704 705 // Write the records. 706 final int recordCount = getRecordCount(); 707 parcel.writeInt(recordCount); 708 for (int i = 0; i < recordCount; i++) { 709 AccessibilityRecord record = mRecords.get(i); 710 writeAccessibilityRecordToParcel(record, parcel, flags); 711 } 712 } 713 714 /** 715 * Writes an {@link AccessibilityRecord} to a parcel. 716 * 717 * @param record The record to write. 718 * @param parcel The parcel to which to write. 719 */ 720 private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel, 721 int flags) { 722 parcel.writeInt(record.mBooleanProperties); 723 parcel.writeInt(record.mCurrentItemIndex); 724 parcel.writeInt(record.mItemCount); 725 parcel.writeInt(record.mFromIndex); 726 parcel.writeInt(record.mToIndex); 727 parcel.writeInt(record.mScrollX); 728 parcel.writeInt(record.mScrollY); 729 parcel.writeInt(record.mAddedCount); 730 parcel.writeInt(record.mRemovedCount); 731 TextUtils.writeToParcel(record.mClassName, parcel, flags); 732 TextUtils.writeToParcel(record.mContentDescription, parcel, flags); 733 TextUtils.writeToParcel(record.mBeforeText, parcel, flags); 734 parcel.writeParcelable(record.mParcelableData, flags); 735 parcel.writeList(record.mText); 736 parcel.writeInt(record.mSourceWindowId); 737 parcel.writeInt(record.mSourceViewId); 738 parcel.writeInt(record.mSealed ? 1 : 0); 739 } 740 741 /** 742 * {@inheritDoc} 743 */ 744 public int describeContents() { 745 return 0; 746 } 747 748 @Override 749 public String toString() { 750 StringBuilder builder = new StringBuilder(); 751 builder.append("EventType: ").append(eventTypeToString(mEventType)); 752 builder.append("; EventTime: ").append(mEventTime); 753 builder.append("; PackageName: ").append(mPackageName); 754 builder.append(super.toString()); 755 if (DEBUG) { 756 builder.append("\n"); 757 builder.append("; sourceWindowId: ").append(mSourceWindowId); 758 builder.append("; sourceViewId: ").append(mSourceViewId); 759 for (int i = 0; i < mRecords.size(); i++) { 760 AccessibilityRecord record = mRecords.get(i); 761 builder.append(" Record "); 762 builder.append(i); 763 builder.append(":"); 764 builder.append(" [ ClassName: " + record.mClassName); 765 builder.append("; Text: " + record.mText); 766 builder.append("; ContentDescription: " + record.mContentDescription); 767 builder.append("; ItemCount: " + record.mItemCount); 768 builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex); 769 builder.append("; IsEnabled: " + record.isEnabled()); 770 builder.append("; IsPassword: " + record.isPassword()); 771 builder.append("; IsChecked: " + record.isChecked()); 772 builder.append("; IsFullScreen: " + record.isFullScreen()); 773 builder.append("; Scrollable: " + record.isScrollable()); 774 builder.append("; BeforeText: " + record.mBeforeText); 775 builder.append("; FromIndex: " + record.mFromIndex); 776 builder.append("; ToIndex: " + record.mToIndex); 777 builder.append("; ScrollX: " + record.mScrollX); 778 builder.append("; ScrollY: " + record.mScrollY); 779 builder.append("; AddedCount: " + record.mAddedCount); 780 builder.append("; RemovedCount: " + record.mRemovedCount); 781 builder.append("; ParcelableData: " + record.mParcelableData); 782 builder.append(" ]"); 783 builder.append("\n"); 784 } 785 } else { 786 builder.append("; recordCount: ").append(getAddedCount()); 787 } 788 return builder.toString(); 789 } 790 791 /** 792 * Returns the string representation of an event type. For example, 793 * {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED. 794 * 795 * @param eventType The event type 796 * @return The string representation. 797 */ 798 public static String eventTypeToString(int eventType) { 799 switch (eventType) { 800 case TYPE_VIEW_CLICKED: 801 return "TYPE_VIEW_CLICKED"; 802 case TYPE_VIEW_LONG_CLICKED: 803 return "TYPE_VIEW_LONG_CLICKED"; 804 case TYPE_VIEW_SELECTED: 805 return "TYPE_VIEW_SELECTED"; 806 case TYPE_VIEW_FOCUSED: 807 return "TYPE_VIEW_FOCUSED"; 808 case TYPE_VIEW_TEXT_CHANGED: 809 return "TYPE_VIEW_TEXT_CHANGED"; 810 case TYPE_WINDOW_STATE_CHANGED: 811 return "TYPE_WINDOW_STATE_CHANGED"; 812 case TYPE_VIEW_HOVER_ENTER: 813 return "TYPE_VIEW_HOVER_ENTER"; 814 case TYPE_VIEW_HOVER_EXIT: 815 return "TYPE_VIEW_HOVER_EXIT"; 816 case TYPE_NOTIFICATION_STATE_CHANGED: 817 return "TYPE_NOTIFICATION_STATE_CHANGED"; 818 case TYPE_TOUCH_EXPLORATION_GESTURE_START: 819 return "TYPE_TOUCH_EXPLORATION_GESTURE_START"; 820 case TYPE_TOUCH_EXPLORATION_GESTURE_END: 821 return "TYPE_TOUCH_EXPLORATION_GESTURE_END"; 822 case TYPE_WINDOW_CONTENT_CHANGED: 823 return "TYPE_WINDOW_CONTENT_CHANGED"; 824 case TYPE_VIEW_TEXT_SELECTION_CHANGED: 825 return "TYPE_VIEW_TEXT_SELECTION_CHANGED"; 826 case TYPE_VIEW_SCROLLED: 827 return "TYPE_VIEW_SCROLLED"; 828 default: 829 return null; 830 } 831 } 832 833 /** 834 * @see Parcelable.Creator 835 */ 836 public static final Parcelable.Creator<AccessibilityEvent> CREATOR = 837 new Parcelable.Creator<AccessibilityEvent>() { 838 public AccessibilityEvent createFromParcel(Parcel parcel) { 839 AccessibilityEvent event = AccessibilityEvent.obtain(); 840 event.initFromParcel(parcel); 841 return event; 842 } 843 844 public AccessibilityEvent[] newArray(int size) { 845 return new AccessibilityEvent[size]; 846 } 847 }; 848} 849