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 */ 163 public static final int MAX_TEXT_LENGTH = 500; 164 165 /** 166 * Represents the event of clicking on a {@link android.view.View} like 167 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 168 */ 169 public static final int TYPE_VIEW_CLICKED = 0x00000001; 170 171 /** 172 * Represents the event of long clicking on a {@link android.view.View} like 173 * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. 174 */ 175 public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002; 176 177 /** 178 * Represents the event of selecting an item usually in the context of an 179 * {@link android.widget.AdapterView}. 180 */ 181 public static final int TYPE_VIEW_SELECTED = 0x00000004; 182 183 /** 184 * Represents the event of focusing a {@link android.view.View}. 185 */ 186 public static final int TYPE_VIEW_FOCUSED = 0x00000008; 187 188 /** 189 * Represents the event of changing the text of an {@link android.widget.EditText}. 190 */ 191 public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010; 192 193 /** 194 * Represents the event of opening/closing a {@link android.widget.PopupWindow}, 195 * {@link android.view.Menu}, {@link android.app.Dialog}, etc. 196 */ 197 public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020; 198 199 /** 200 * Represents the event showing/hiding a {@link android.app.Notification}. 201 */ 202 public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040; 203 204 /** 205 * Mask for {@link AccessibilityEvent} all types. 206 * 207 * @see #TYPE_VIEW_CLICKED 208 * @see #TYPE_VIEW_LONG_CLICKED 209 * @see #TYPE_VIEW_SELECTED 210 * @see #TYPE_VIEW_FOCUSED 211 * @see #TYPE_VIEW_TEXT_CHANGED 212 * @see #TYPE_WINDOW_STATE_CHANGED 213 * @see #TYPE_NOTIFICATION_STATE_CHANGED 214 */ 215 public static final int TYPES_ALL_MASK = 0xFFFFFFFF; 216 217 private static final int MAX_POOL_SIZE = 2; 218 private static final Object mPoolLock = new Object(); 219 private static AccessibilityEvent sPool; 220 private static int sPoolSize; 221 222 private static final int CHECKED = 0x00000001; 223 private static final int ENABLED = 0x00000002; 224 private static final int PASSWORD = 0x00000004; 225 private static final int FULL_SCREEN = 0x00000080; 226 227 private AccessibilityEvent mNext; 228 229 private int mEventType; 230 private int mBooleanProperties; 231 private int mCurrentItemIndex; 232 private int mItemCount; 233 private int mFromIndex; 234 private int mAddedCount; 235 private int mRemovedCount; 236 237 private long mEventTime; 238 239 private CharSequence mClassName; 240 private CharSequence mPackageName; 241 private CharSequence mContentDescription; 242 private CharSequence mBeforeText; 243 244 private Parcelable mParcelableData; 245 246 private final List<CharSequence> mText = new ArrayList<CharSequence>(); 247 248 private boolean mIsInPool; 249 250 /* 251 * Hide constructor from clients. 252 */ 253 private AccessibilityEvent() { 254 mCurrentItemIndex = INVALID_POSITION; 255 } 256 257 /** 258 * Gets if the source is checked. 259 * 260 * @return True if the view is checked, false otherwise. 261 */ 262 public boolean isChecked() { 263 return getBooleanProperty(CHECKED); 264 } 265 266 /** 267 * Sets if the source is checked. 268 * 269 * @param isChecked True if the view is checked, false otherwise. 270 */ 271 public void setChecked(boolean isChecked) { 272 setBooleanProperty(CHECKED, isChecked); 273 } 274 275 /** 276 * Gets if the source is enabled. 277 * 278 * @return True if the view is enabled, false otherwise. 279 */ 280 public boolean isEnabled() { 281 return getBooleanProperty(ENABLED); 282 } 283 284 /** 285 * Sets if the source is enabled. 286 * 287 * @param isEnabled True if the view is enabled, false otherwise. 288 */ 289 public void setEnabled(boolean isEnabled) { 290 setBooleanProperty(ENABLED, isEnabled); 291 } 292 293 /** 294 * Gets if the source is a password field. 295 * 296 * @return True if the view is a password field, false otherwise. 297 */ 298 public boolean isPassword() { 299 return getBooleanProperty(PASSWORD); 300 } 301 302 /** 303 * Sets if the source is a password field. 304 * 305 * @param isPassword True if the view is a password field, false otherwise. 306 */ 307 public void setPassword(boolean isPassword) { 308 setBooleanProperty(PASSWORD, isPassword); 309 } 310 311 /** 312 * Sets if the source is taking the entire screen. 313 * 314 * @param isFullScreen True if the source is full screen, false otherwise. 315 */ 316 public void setFullScreen(boolean isFullScreen) { 317 setBooleanProperty(FULL_SCREEN, isFullScreen); 318 } 319 320 /** 321 * Gets if the source is taking the entire screen. 322 * 323 * @return True if the source is full screen, false otherwise. 324 */ 325 public boolean isFullScreen() { 326 return getBooleanProperty(FULL_SCREEN); 327 } 328 329 /** 330 * Gets the event type. 331 * 332 * @return The event type. 333 */ 334 public int getEventType() { 335 return mEventType; 336 } 337 338 /** 339 * Sets the event type. 340 * 341 * @param eventType The event type. 342 */ 343 public void setEventType(int eventType) { 344 mEventType = eventType; 345 } 346 347 /** 348 * Gets the number of items that can be visited. 349 * 350 * @return The number of items. 351 */ 352 public int getItemCount() { 353 return mItemCount; 354 } 355 356 /** 357 * Sets the number of items that can be visited. 358 * 359 * @param itemCount The number of items. 360 */ 361 public void setItemCount(int itemCount) { 362 mItemCount = itemCount; 363 } 364 365 /** 366 * Gets the index of the source in the list of items the can be visited. 367 * 368 * @return The current item index. 369 */ 370 public int getCurrentItemIndex() { 371 return mCurrentItemIndex; 372 } 373 374 /** 375 * Sets the index of the source in the list of items that can be visited. 376 * 377 * @param currentItemIndex The current item index. 378 */ 379 public void setCurrentItemIndex(int currentItemIndex) { 380 mCurrentItemIndex = currentItemIndex; 381 } 382 383 /** 384 * Gets the index of the first character of the changed sequence. 385 * 386 * @return The index of the first character. 387 */ 388 public int getFromIndex() { 389 return mFromIndex; 390 } 391 392 /** 393 * Sets the index of the first character of the changed sequence. 394 * 395 * @param fromIndex The index of the first character. 396 */ 397 public void setFromIndex(int fromIndex) { 398 mFromIndex = fromIndex; 399 } 400 401 /** 402 * Gets the number of added characters. 403 * 404 * @return The number of added characters. 405 */ 406 public int getAddedCount() { 407 return mAddedCount; 408 } 409 410 /** 411 * Sets the number of added characters. 412 * 413 * @param addedCount The number of added characters. 414 */ 415 public void setAddedCount(int addedCount) { 416 mAddedCount = addedCount; 417 } 418 419 /** 420 * Gets the number of removed characters. 421 * 422 * @return The number of removed characters. 423 */ 424 public int getRemovedCount() { 425 return mRemovedCount; 426 } 427 428 /** 429 * Sets the number of removed characters. 430 * 431 * @param removedCount The number of removed characters. 432 */ 433 public void setRemovedCount(int removedCount) { 434 mRemovedCount = removedCount; 435 } 436 437 /** 438 * Gets the time in which this event was sent. 439 * 440 * @return The event time. 441 */ 442 public long getEventTime() { 443 return mEventTime; 444 } 445 446 /** 447 * Sets the time in which this event was sent. 448 * 449 * @param eventTime The event time. 450 */ 451 public void setEventTime(long eventTime) { 452 mEventTime = eventTime; 453 } 454 455 /** 456 * Gets the class name of the source. 457 * 458 * @return The class name. 459 */ 460 public CharSequence getClassName() { 461 return mClassName; 462 } 463 464 /** 465 * Sets the class name of the source. 466 * 467 * @param className The lass name. 468 */ 469 public void setClassName(CharSequence className) { 470 mClassName = className; 471 } 472 473 /** 474 * Gets the package name of the source. 475 * 476 * @return The package name. 477 */ 478 public CharSequence getPackageName() { 479 return mPackageName; 480 } 481 482 /** 483 * Sets the package name of the source. 484 * 485 * @param packageName The package name. 486 */ 487 public void setPackageName(CharSequence packageName) { 488 mPackageName = packageName; 489 } 490 491 /** 492 * Gets the text of the event. The index in the list represents the priority 493 * of the text. Specifically, the lower the index the higher the priority. 494 * 495 * @return The text. 496 */ 497 public List<CharSequence> getText() { 498 return mText; 499 } 500 501 /** 502 * Sets the text before a change. 503 * 504 * @return The text before the change. 505 */ 506 public CharSequence getBeforeText() { 507 return mBeforeText; 508 } 509 510 /** 511 * Sets the text before a change. 512 * 513 * @param beforeText The text before the change. 514 */ 515 public void setBeforeText(CharSequence beforeText) { 516 mBeforeText = beforeText; 517 } 518 519 /** 520 * Gets the description of the source. 521 * 522 * @return The description. 523 */ 524 public CharSequence getContentDescription() { 525 return mContentDescription; 526 } 527 528 /** 529 * Sets the description of the source. 530 * 531 * @param contentDescription The description. 532 */ 533 public void setContentDescription(CharSequence contentDescription) { 534 mContentDescription = contentDescription; 535 } 536 537 /** 538 * Gets the {@link Parcelable} data. 539 * 540 * @return The parcelable data. 541 */ 542 public Parcelable getParcelableData() { 543 return mParcelableData; 544 } 545 546 /** 547 * Sets the {@link Parcelable} data of the event. 548 * 549 * @param parcelableData The parcelable data. 550 */ 551 public void setParcelableData(Parcelable parcelableData) { 552 mParcelableData = parcelableData; 553 } 554 555 /** 556 * Returns a cached instance if such is available or a new one is 557 * instantiated with type property set. 558 * 559 * @param eventType The event type. 560 * @return An instance. 561 */ 562 public static AccessibilityEvent obtain(int eventType) { 563 AccessibilityEvent event = AccessibilityEvent.obtain(); 564 event.setEventType(eventType); 565 return event; 566 } 567 568 /** 569 * Returns a cached instance if such is available or a new one is 570 * instantiated. 571 * 572 * @return An instance. 573 */ 574 public static AccessibilityEvent obtain() { 575 synchronized (mPoolLock) { 576 if (sPool != null) { 577 AccessibilityEvent event = sPool; 578 sPool = sPool.mNext; 579 sPoolSize--; 580 event.mNext = null; 581 event.mIsInPool = false; 582 return event; 583 } 584 return new AccessibilityEvent(); 585 } 586 } 587 588 /** 589 * Return an instance back to be reused. 590 * <p> 591 * <b>Note: You must not touch the object after calling this function.</b> 592 */ 593 public void recycle() { 594 if (mIsInPool) { 595 return; 596 } 597 598 clear(); 599 synchronized (mPoolLock) { 600 if (sPoolSize <= MAX_POOL_SIZE) { 601 mNext = sPool; 602 sPool = this; 603 mIsInPool = true; 604 sPoolSize++; 605 } 606 } 607 } 608 609 /** 610 * Clears the state of this instance. 611 */ 612 private void clear() { 613 mEventType = 0; 614 mBooleanProperties = 0; 615 mCurrentItemIndex = INVALID_POSITION; 616 mItemCount = 0; 617 mFromIndex = 0; 618 mAddedCount = 0; 619 mRemovedCount = 0; 620 mEventTime = 0; 621 mClassName = null; 622 mPackageName = null; 623 mContentDescription = null; 624 mBeforeText = null; 625 mParcelableData = null; 626 mText.clear(); 627 } 628 629 /** 630 * Gets the value of a boolean property. 631 * 632 * @param property The property. 633 * @return The value. 634 */ 635 private boolean getBooleanProperty(int property) { 636 return (mBooleanProperties & property) == property; 637 } 638 639 /** 640 * Sets a boolean property. 641 * 642 * @param property The property. 643 * @param value The value. 644 */ 645 private void setBooleanProperty(int property, boolean value) { 646 if (value) { 647 mBooleanProperties |= property; 648 } else { 649 mBooleanProperties &= ~property; 650 } 651 } 652 653 /** 654 * Creates a new instance from a {@link Parcel}. 655 * 656 * @param parcel A parcel containing the state of a {@link AccessibilityEvent}. 657 */ 658 public void initFromParcel(Parcel parcel) { 659 mEventType = parcel.readInt(); 660 mBooleanProperties = parcel.readInt(); 661 mCurrentItemIndex = parcel.readInt(); 662 mItemCount = parcel.readInt(); 663 mFromIndex = parcel.readInt(); 664 mAddedCount = parcel.readInt(); 665 mRemovedCount = parcel.readInt(); 666 mEventTime = parcel.readLong(); 667 mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 668 mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 669 mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 670 mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); 671 mParcelableData = parcel.readParcelable(null); 672 parcel.readList(mText, null); 673 } 674 675 public void writeToParcel(Parcel parcel, int flags) { 676 parcel.writeInt(mEventType); 677 parcel.writeInt(mBooleanProperties); 678 parcel.writeInt(mCurrentItemIndex); 679 parcel.writeInt(mItemCount); 680 parcel.writeInt(mFromIndex); 681 parcel.writeInt(mAddedCount); 682 parcel.writeInt(mRemovedCount); 683 parcel.writeLong(mEventTime); 684 TextUtils.writeToParcel(mClassName, parcel, 0); 685 TextUtils.writeToParcel(mPackageName, parcel, 0); 686 TextUtils.writeToParcel(mContentDescription, parcel, 0); 687 TextUtils.writeToParcel(mBeforeText, parcel, 0); 688 parcel.writeParcelable(mParcelableData, flags); 689 parcel.writeList(mText); 690 } 691 692 public int describeContents() { 693 return 0; 694 } 695 696 @Override 697 public String toString() { 698 StringBuilder builder = new StringBuilder(); 699 builder.append(super.toString()); 700 builder.append("; EventType: " + mEventType); 701 builder.append("; EventTime: " + mEventTime); 702 builder.append("; ClassName: " + mClassName); 703 builder.append("; PackageName: " + mPackageName); 704 builder.append("; Text: " + mText); 705 builder.append("; ContentDescription: " + mContentDescription); 706 builder.append("; ItemCount: " + mItemCount); 707 builder.append("; CurrentItemIndex: " + mCurrentItemIndex); 708 builder.append("; IsEnabled: " + isEnabled()); 709 builder.append("; IsPassword: " + isPassword()); 710 builder.append("; IsChecked: " + isChecked()); 711 builder.append("; IsFullScreen: " + isFullScreen()); 712 builder.append("; BeforeText: " + mBeforeText); 713 builder.append("; FromIndex: " + mFromIndex); 714 builder.append("; AddedCount: " + mAddedCount); 715 builder.append("; RemovedCount: " + mRemovedCount); 716 builder.append("; ParcelableData: " + mParcelableData); 717 return builder.toString(); 718 } 719 720 /** 721 * @see Parcelable.Creator 722 */ 723 public static final Parcelable.Creator<AccessibilityEvent> CREATOR = 724 new Parcelable.Creator<AccessibilityEvent>() { 725 public AccessibilityEvent createFromParcel(Parcel parcel) { 726 AccessibilityEvent event = AccessibilityEvent.obtain(); 727 event.initFromParcel(parcel); 728 return event; 729 } 730 731 public AccessibilityEvent[] newArray(int size) { 732 return new AccessibilityEvent[size]; 733 } 734 }; 735} 736