AccessibilityEvent.java revision c0a8cd10a5829bf4e94ee073ba6f553128e9d8e9
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.os.Parcel; 20import android.os.Parcelable; 21import android.text.TextUtils; 22 23import java.util.ArrayList; 24import java.util.List; 25 26/** 27 * This class represents accessibility events that are sent by the system when 28 * something notable happens in the user interface. For example, when a 29 * {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc. 30 * <p> 31 * This class represents various semantically different accessibility event 32 * types. Each event type has associated a set of related properties. In other 33 * words, each event type is characterized via a subset of the properties exposed 34 * by this class. For each event type there is a corresponding constant defined 35 * in this class. Since some event types are semantically close there are mask 36 * constants that group them together. Follows a specification of the event 37 * types and their associated properties: 38 * <p> 39 * <b>VIEW TYPES</b> <br> 40 * <p> 41 * <b>View clicked</b> - represents the event of clicking on a {@link android.view.View} 42 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br> 43 * Type:{@link #TYPE_VIEW_CLICKED} <br> 44 * Properties: 45 * {@link #getClassName()}, 46 * {@link #getPackageName()}, 47 * {@link #getEventTime()}, 48 * {@link #getText()}, 49 * {@link #isChecked()}, 50 * {@link #isEnabled()}, 51 * {@link #isPassword()}, 52 * {@link #getItemCount()}, 53 * {@link #getCurrentItemIndex()} 54 * <p> 55 * <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View} 56 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br> 57 * Type:{@link #TYPE_VIEW_LONG_CLICKED} <br> 58 * Properties: 59 * {@link #getClassName()}, 60 * {@link #getPackageName()}, 61 * {@link #getEventTime()}, 62 * {@link #getText()}, 63 * {@link #isChecked()}, 64 * {@link #isEnabled()}, 65 * {@link #isPassword()}, 66 * {@link #getItemCount()}, 67 * {@link #getCurrentItemIndex()} 68 * <p> 69 * <b>View selected</b> - represents the event of selecting an item usually in 70 * the context of an {@link android.widget.AdapterView}. <br> 71 * Type: {@link #TYPE_VIEW_SELECTED} <br> 72 * Properties: 73 * {@link #getClassName()}, 74 * {@link #getPackageName()}, 75 * {@link #getEventTime()}, 76 * {@link #getText()}, 77 * {@link #isChecked()}, 78 * {@link #isEnabled()}, 79 * {@link #isPassword()}, 80 * {@link #getItemCount()}, 81 * {@link #getCurrentItemIndex()} 82 * <p> 83 * <b>View focused</b> - represents the event of focusing a 84 * {@link android.view.View}. <br> 85 * Type: {@link #TYPE_VIEW_FOCUSED} <br> 86 * Properties: 87 * {@link #getClassName()}, 88 * {@link #getPackageName()}, 89 * {@link #getEventTime()}, 90 * {@link #getText()}, 91 * {@link #isChecked()}, 92 * {@link #isEnabled()}, 93 * {@link #isPassword()}, 94 * {@link #getItemCount()}, 95 * {@link #getCurrentItemIndex()} 96 * <p> 97 * <b>View text changed</b> - represents the event of changing the text of an 98 * {@link android.widget.EditText}. <br> 99 * Type: {@link #TYPE_VIEW_TEXT_CHANGED} <br> 100 * Properties: 101 * {@link #getClassName()}, 102 * {@link #getPackageName()}, 103 * {@link #getEventTime()}, 104 * {@link #getText()}, 105 * {@link #isChecked()}, 106 * {@link #isEnabled()}, 107 * {@link #isPassword()}, 108 * {@link #getItemCount()}, 109 * {@link #getCurrentItemIndex()}, 110 * {@link #getFromIndex()}, 111 * {@link #getAddedCount()}, 112 * {@link #getRemovedCount()}, 113 * {@link #getBeforeText()} 114 * <p> 115 * <b>TRANSITION TYPES</b> <br> 116 * <p> 117 * <b>Window state changed</b> - represents the event of opening/closing a 118 * {@link android.widget.PopupWindow}, {@link android.view.Menu}, 119 * {@link android.app.Dialog}, etc. <br> 120 * Type: {@link #TYPE_WINDOW_STATE_CHANGED} <br> 121 * Properties: 122 * {@link #getClassName()}, 123 * {@link #getPackageName()}, 124 * {@link #getEventTime()}, 125 * {@link #getText()} 126 * <p> 127 * <b>NOTIFICATION TYPES</b> <br> 128 * <p> 129 * <b>Notification state changed</b> - represents the event showing/hiding 130 * {@link android.app.Notification}. 131 * Type: {@link #TYPE_NOTIFICATION_STATE_CHANGED} <br> 132 * Properties: 133 * {@link #getClassName()}, 134 * {@link #getPackageName()}, 135 * {@link #getEventTime()}, 136 * {@link #getText()} 137 * {@link #getParcelableData()} 138 * <p> 139 * <b>Security note</b> 140 * <p> 141 * Since an event contains the text of its source privacy can be compromised by leaking of 142 * sensitive information such as passwords. To address this issue any event fired in response 143 * to manipulation of a PASSWORD field does NOT CONTAIN the text of the password. 144 * 145 * @see android.view.accessibility.AccessibilityManager 146 * @see android.accessibilityservice.AccessibilityService 147 */ 148public final class AccessibilityEvent implements Parcelable { 149 150 /** 151 * Invalid selection/focus position. 152 * 153 * @see #getCurrentItemIndex() 154 */ 155 public static final int INVALID_POSITION = -1; 156 157 /** 158 * Maximum length of the text fields. 159 * 160 * @see #getBeforeText() 161 * @see #getText() 162 * </br> 163 * Note: This constant is no longer needed since there 164 * is no limit on the length of text that is contained 165 * in an accessibility event anymore. 166 */ 167 @Deprecated 168 public static final int MAX_TEXT_LENGTH = 500; 169 170 /** 171 * Represents the event of clicking on a {@link android.view.View} like 172 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 173 */ 174 public static final int TYPE_VIEW_CLICKED = 0x00000001; 175 176 /** 177 * Represents the event of long clicking on a {@link android.view.View} like 178 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 179 */ 180 public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002; 181 182 /** 183 * Represents the event of selecting an item usually in the context of an 184 * {@link android.widget.AdapterView}. 185 */ 186 public static final int TYPE_VIEW_SELECTED = 0x00000004; 187 188 /** 189 * Represents the event of focusing a {@link android.view.View}. 190 */ 191 public static final int TYPE_VIEW_FOCUSED = 0x00000008; 192 193 /** 194 * Represents the event of changing the text of an {@link android.widget.EditText}. 195 */ 196 public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010; 197 198 /** 199 * Represents the event of opening/closing a {@link android.widget.PopupWindow}, 200 * {@link android.view.Menu}, {@link android.app.Dialog}, etc. 201 */ 202 public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020; 203 204 /** 205 * Represents the event showing/hiding a {@link android.app.Notification}. 206 */ 207 public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040; 208 209 /** 210 * Mask for {@link AccessibilityEvent} all types. 211 * 212 * @see #TYPE_VIEW_CLICKED 213 * @see #TYPE_VIEW_LONG_CLICKED 214 * @see #TYPE_VIEW_SELECTED 215 * @see #TYPE_VIEW_FOCUSED 216 * @see #TYPE_VIEW_TEXT_CHANGED 217 * @see #TYPE_WINDOW_STATE_CHANGED 218 * @see #TYPE_NOTIFICATION_STATE_CHANGED 219 */ 220 public static final int TYPES_ALL_MASK = 0xFFFFFFFF; 221 222 private static final int MAX_POOL_SIZE = 2; 223 private static final Object mPoolLock = new Object(); 224 private static AccessibilityEvent sPool; 225 private static int sPoolSize; 226 227 private static final int CHECKED = 0x00000001; 228 private static final int ENABLED = 0x00000002; 229 private static final int PASSWORD = 0x00000004; 230 private static final int FULL_SCREEN = 0x00000080; 231 232 private AccessibilityEvent mNext; 233 234 private int mEventType; 235 private int mBooleanProperties; 236 private int mCurrentItemIndex; 237 private int mItemCount; 238 private int mFromIndex; 239 private int mAddedCount; 240 private int mRemovedCount; 241 242 private long mEventTime; 243 244 private CharSequence mClassName; 245 private CharSequence mPackageName; 246 private CharSequence mContentDescription; 247 private CharSequence mBeforeText; 248 249 private Parcelable mParcelableData; 250 251 private final List<CharSequence> mText = new ArrayList<CharSequence>(); 252 253 private boolean mIsInPool; 254 255 /* 256 * Hide constructor from clients. 257 */ 258 private AccessibilityEvent() { 259 mCurrentItemIndex = INVALID_POSITION; 260 } 261 262 /** 263 * Gets if the source is checked. 264 * 265 * @return True if the view is checked, false otherwise. 266 */ 267 public boolean isChecked() { 268 return getBooleanProperty(CHECKED); 269 } 270 271 /** 272 * Sets if the source is checked. 273 * 274 * @param isChecked True if the view is checked, false otherwise. 275 */ 276 public void setChecked(boolean isChecked) { 277 setBooleanProperty(CHECKED, isChecked); 278 } 279 280 /** 281 * Gets if the source is enabled. 282 * 283 * @return True if the view is enabled, false otherwise. 284 */ 285 public boolean isEnabled() { 286 return getBooleanProperty(ENABLED); 287 } 288 289 /** 290 * Sets if the source is enabled. 291 * 292 * @param isEnabled True if the view is enabled, false otherwise. 293 */ 294 public void setEnabled(boolean isEnabled) { 295 setBooleanProperty(ENABLED, isEnabled); 296 } 297 298 /** 299 * Gets if the source is a password field. 300 * 301 * @return True if the view is a password field, false otherwise. 302 */ 303 public boolean isPassword() { 304 return getBooleanProperty(PASSWORD); 305 } 306 307 /** 308 * Sets if the source is a password field. 309 * 310 * @param isPassword True if the view is a password field, false otherwise. 311 */ 312 public void setPassword(boolean isPassword) { 313 setBooleanProperty(PASSWORD, isPassword); 314 } 315 316 /** 317 * Sets if the source is taking the entire screen. 318 * 319 * @param isFullScreen True if the source is full screen, false otherwise. 320 */ 321 public void setFullScreen(boolean isFullScreen) { 322 setBooleanProperty(FULL_SCREEN, isFullScreen); 323 } 324 325 /** 326 * Gets if the source is taking the entire screen. 327 * 328 * @return True if the source is full screen, false otherwise. 329 */ 330 public boolean isFullScreen() { 331 return getBooleanProperty(FULL_SCREEN); 332 } 333 334 /** 335 * Gets the event type. 336 * 337 * @return The event type. 338 */ 339 public int getEventType() { 340 return mEventType; 341 } 342 343 /** 344 * Sets the event type. 345 * 346 * @param eventType The event type. 347 */ 348 public void setEventType(int eventType) { 349 mEventType = eventType; 350 } 351 352 /** 353 * Gets the number of items that can be visited. 354 * 355 * @return The number of items. 356 */ 357 public int getItemCount() { 358 return mItemCount; 359 } 360 361 /** 362 * Sets the number of items that can be visited. 363 * 364 * @param itemCount The number of items. 365 */ 366 public void setItemCount(int itemCount) { 367 mItemCount = itemCount; 368 } 369 370 /** 371 * Gets the index of the source in the list of items the can be visited. 372 * 373 * @return The current item index. 374 */ 375 public int getCurrentItemIndex() { 376 return mCurrentItemIndex; 377 } 378 379 /** 380 * Sets the index of the source in the list of items that can be visited. 381 * 382 * @param currentItemIndex The current item index. 383 */ 384 public void setCurrentItemIndex(int currentItemIndex) { 385 mCurrentItemIndex = currentItemIndex; 386 } 387 388 /** 389 * Gets the index of the first character of the changed sequence. 390 * 391 * @return The index of the first character. 392 */ 393 public int getFromIndex() { 394 return mFromIndex; 395 } 396 397 /** 398 * Sets the index of the first character of the changed sequence. 399 * 400 * @param fromIndex The index of the first character. 401 */ 402 public void setFromIndex(int fromIndex) { 403 mFromIndex = fromIndex; 404 } 405 406 /** 407 * Gets the number of added characters. 408 * 409 * @return The number of added characters. 410 */ 411 public int getAddedCount() { 412 return mAddedCount; 413 } 414 415 /** 416 * Sets the number of added characters. 417 * 418 * @param addedCount The number of added characters. 419 */ 420 public void setAddedCount(int addedCount) { 421 mAddedCount = addedCount; 422 } 423 424 /** 425 * Gets the number of removed characters. 426 * 427 * @return The number of removed characters. 428 */ 429 public int getRemovedCount() { 430 return mRemovedCount; 431 } 432 433 /** 434 * Sets the number of removed characters. 435 * 436 * @param removedCount The number of removed characters. 437 */ 438 public void setRemovedCount(int removedCount) { 439 mRemovedCount = removedCount; 440 } 441 442 /** 443 * Gets the time in which this event was sent. 444 * 445 * @return The event time. 446 */ 447 public long getEventTime() { 448 return mEventTime; 449 } 450 451 /** 452 * Sets the time in which this event was sent. 453 * 454 * @param eventTime The event time. 455 */ 456 public void setEventTime(long eventTime) { 457 mEventTime = eventTime; 458 } 459 460 /** 461 * Gets the class name of the source. 462 * 463 * @return The class name. 464 */ 465 public CharSequence getClassName() { 466 return mClassName; 467 } 468 469 /** 470 * Sets the class name of the source. 471 * 472 * @param className The lass name. 473 */ 474 public void setClassName(CharSequence className) { 475 mClassName = className; 476 } 477 478 /** 479 * Gets the package name of the source. 480 * 481 * @return The package name. 482 */ 483 public CharSequence getPackageName() { 484 return mPackageName; 485 } 486 487 /** 488 * Sets the package name of the source. 489 * 490 * @param packageName The package name. 491 */ 492 public void setPackageName(CharSequence packageName) { 493 mPackageName = packageName; 494 } 495 496 /** 497 * Gets the text of the event. The index in the list represents the priority 498 * of the text. Specifically, the lower the index the higher the priority. 499 * 500 * @return The text. 501 */ 502 public List<CharSequence> getText() { 503 return mText; 504 } 505 506 /** 507 * Sets the text before a change. 508 * 509 * @return The text before the change. 510 */ 511 public CharSequence getBeforeText() { 512 return mBeforeText; 513 } 514 515 /** 516 * Sets the text before a change. 517 * 518 * @param beforeText The text before the change. 519 */ 520 public void setBeforeText(CharSequence beforeText) { 521 mBeforeText = beforeText; 522 } 523 524 /** 525 * Gets the description of the source. 526 * 527 * @return The description. 528 */ 529 public CharSequence getContentDescription() { 530 return mContentDescription; 531 } 532 533 /** 534 * Sets the description of the source. 535 * 536 * @param contentDescription The description. 537 */ 538 public void setContentDescription(CharSequence contentDescription) { 539 mContentDescription = contentDescription; 540 } 541 542 /** 543 * Gets the {@link Parcelable} data. 544 * 545 * @return The parcelable data. 546 */ 547 public Parcelable getParcelableData() { 548 return mParcelableData; 549 } 550 551 /** 552 * Sets the {@link Parcelable} data of the event. 553 * 554 * @param parcelableData The parcelable data. 555 */ 556 public void setParcelableData(Parcelable parcelableData) { 557 mParcelableData = parcelableData; 558 } 559 560 /** 561 * Returns a cached instance if such is available or a new one is 562 * instantiated with type property set. 563 * 564 * @param eventType The event type. 565 * @return An instance. 566 */ 567 public static AccessibilityEvent obtain(int eventType) { 568 AccessibilityEvent event = AccessibilityEvent.obtain(); 569 event.setEventType(eventType); 570 return event; 571 } 572 573 /** 574 * Returns a cached instance if such is available or a new one is 575 * instantiated. 576 * 577 * @return An instance. 578 */ 579 public static AccessibilityEvent obtain() { 580 synchronized (mPoolLock) { 581 if (sPool != null) { 582 AccessibilityEvent event = sPool; 583 sPool = sPool.mNext; 584 sPoolSize--; 585 event.mNext = null; 586 event.mIsInPool = false; 587 return event; 588 } 589 return new AccessibilityEvent(); 590 } 591 } 592 593 /** 594 * Return an instance back to be reused. 595 * <p> 596 * <b>Note: You must not touch the object after calling this function.</b> 597 */ 598 public void recycle() { 599 if (mIsInPool) { 600 return; 601 } 602 603 clear(); 604 synchronized (mPoolLock) { 605 if (sPoolSize <= MAX_POOL_SIZE) { 606 mNext = sPool; 607 sPool = this; 608 mIsInPool = true; 609 sPoolSize++; 610 } 611 } 612 } 613 614 /** 615 * Clears the state of this instance. 616 */ 617 private void clear() { 618 mEventType = 0; 619 mBooleanProperties = 0; 620 mCurrentItemIndex = INVALID_POSITION; 621 mItemCount = 0; 622 mFromIndex = 0; 623 mAddedCount = 0; 624 mRemovedCount = 0; 625 mEventTime = 0; 626 mClassName = null; 627 mPackageName = null; 628 mContentDescription = null; 629 mBeforeText = null; 630 mParcelableData = null; 631 mText.clear(); 632 } 633 634 /** 635 * Gets the value of a boolean property. 636 * 637 * @param property The property. 638 * @return The value. 639 */ 640 private boolean getBooleanProperty(int property) { 641 return (mBooleanProperties & property) == property; 642 } 643 644 /** 645 * Sets a boolean property. 646 * 647 * @param property The property. 648 * @param value The value. 649 */ 650 private void setBooleanProperty(int property, boolean value) { 651 if (value) { 652 mBooleanProperties |= property; 653 } else { 654 mBooleanProperties &= ~property; 655 } 656 } 657 658 /** 659 * Creates a new instance from a {@link Parcel}. 660 * 661 * @param parcel A parcel containing the state of a {@link AccessibilityEvent}. 662 */ 663 public void initFromParcel(Parcel parcel) { 664 mEventType = parcel.readInt(); 665 mBooleanProperties = parcel.readInt(); 666 mCurrentItemIndex = parcel.readInt(); 667 mItemCount = parcel.readInt(); 668 mFromIndex = parcel.readInt(); 669 mAddedCount = parcel.readInt(); 670 mRemovedCount = parcel.readInt(); 671 mEventTime = parcel.readLong(); 672 mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 673 mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 674 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 675 mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 676 mParcelableData = parcel.readParcelable(null); 677 parcel.readList(mText, null); 678 } 679 680 public void writeToParcel(Parcel parcel, int flags) { 681 parcel.writeInt(mEventType); 682 parcel.writeInt(mBooleanProperties); 683 parcel.writeInt(mCurrentItemIndex); 684 parcel.writeInt(mItemCount); 685 parcel.writeInt(mFromIndex); 686 parcel.writeInt(mAddedCount); 687 parcel.writeInt(mRemovedCount); 688 parcel.writeLong(mEventTime); 689 TextUtils.writeToParcel(mClassName, parcel, 0); 690 TextUtils.writeToParcel(mPackageName, parcel, 0); 691 TextUtils.writeToParcel(mContentDescription, parcel, 0); 692 TextUtils.writeToParcel(mBeforeText, parcel, 0); 693 parcel.writeParcelable(mParcelableData, flags); 694 parcel.writeList(mText); 695 } 696 697 public int describeContents() { 698 return 0; 699 } 700 701 @Override 702 public String toString() { 703 StringBuilder builder = new StringBuilder(); 704 builder.append(super.toString()); 705 builder.append("; EventType: " + mEventType); 706 builder.append("; EventTime: " + mEventTime); 707 builder.append("; ClassName: " + mClassName); 708 builder.append("; PackageName: " + mPackageName); 709 builder.append("; Text: " + mText); 710 builder.append("; ContentDescription: " + mContentDescription); 711 builder.append("; ItemCount: " + mItemCount); 712 builder.append("; CurrentItemIndex: " + mCurrentItemIndex); 713 builder.append("; IsEnabled: " + isEnabled()); 714 builder.append("; IsPassword: " + isPassword()); 715 builder.append("; IsChecked: " + isChecked()); 716 builder.append("; IsFullScreen: " + isFullScreen()); 717 builder.append("; BeforeText: " + mBeforeText); 718 builder.append("; FromIndex: " + mFromIndex); 719 builder.append("; AddedCount: " + mAddedCount); 720 builder.append("; RemovedCount: " + mRemovedCount); 721 builder.append("; ParcelableData: " + mParcelableData); 722 return builder.toString(); 723 } 724 725 /** 726 * @see Parcelable.Creator 727 */ 728 public static final Parcelable.Creator<AccessibilityEvent> CREATOR = 729 new Parcelable.Creator<AccessibilityEvent>() { 730 public AccessibilityEvent createFromParcel(Parcel parcel) { 731 AccessibilityEvent event = AccessibilityEvent.obtain(); 732 event.initFromParcel(parcel); 733 return event; 734 } 735 736 public AccessibilityEvent[] newArray(int size) { 737 return new AccessibilityEvent[size]; 738 } 739 }; 740} 741