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