Home | History | Annotate | Download | only in accessibility
      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 
     17 package android.view.accessibility;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.text.TextUtils;
     22 
     23 import java.util.ArrayList;
     24 import 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  */
    148 public 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