Home | History | Annotate | Download | only in accessibility
      1 /*
      2  * Copyright (C) 2011 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 static java.util.Collections.EMPTY_LIST;
     20 
     21 import android.accessibilityservice.AccessibilityService;
     22 import android.accessibilityservice.AccessibilityServiceInfo;
     23 import android.annotation.Nullable;
     24 import android.annotation.TestApi;
     25 import android.graphics.Rect;
     26 import android.os.Bundle;
     27 import android.os.Parcel;
     28 import android.os.Parcelable;
     29 import android.text.InputType;
     30 import android.text.Spannable;
     31 import android.text.SpannableStringBuilder;
     32 import android.text.Spanned;
     33 import android.text.TextUtils;
     34 import android.text.style.AccessibilityClickableSpan;
     35 import android.text.style.AccessibilityURLSpan;
     36 import android.text.style.ClickableSpan;
     37 import android.text.style.URLSpan;
     38 import android.util.ArraySet;
     39 import android.util.LongArray;
     40 import android.util.Pools.SynchronizedPool;
     41 import android.view.View;
     42 
     43 import com.android.internal.R;
     44 
     45 import java.util.ArrayList;
     46 import java.util.Collections;
     47 import java.util.List;
     48 import java.util.concurrent.atomic.AtomicInteger;
     49 
     50 /**
     51  * This class represents a node of the window content as well as actions that
     52  * can be requested from its source. From the point of view of an
     53  * {@link android.accessibilityservice.AccessibilityService} a window's content is
     54  * presented as a tree of accessibility node infos, which may or may not map one-to-one
     55  * to the view hierarchy. In other words, a custom view is free to report itself as
     56  * a tree of accessibility node info.
     57  * </p>
     58  * <p>
     59  * Once an accessibility node info is delivered to an accessibility service it is
     60  * made immutable and calling a state mutation method generates an error.
     61  * </p>
     62  * <p>
     63  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
     64  * details about how to obtain a handle to window content as a tree of accessibility
     65  * node info as well as details about the security model.
     66  * </p>
     67  * <div class="special reference">
     68  * <h3>Developer Guides</h3>
     69  * <p>For more information about making applications accessible, read the
     70  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     71  * developer guide.</p>
     72  * </div>
     73  *
     74  * @see android.accessibilityservice.AccessibilityService
     75  * @see AccessibilityEvent
     76  * @see AccessibilityManager
     77  */
     78 public class AccessibilityNodeInfo implements Parcelable {
     79 
     80     private static final boolean DEBUG = false;
     81 
     82     /** @hide */
     83     public static final int UNDEFINED_CONNECTION_ID = -1;
     84 
     85     /** @hide */
     86     public static final int UNDEFINED_SELECTION_INDEX = -1;
     87 
     88     /* Special IDs for node source IDs */
     89     /** @hide */
     90     public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE;
     91 
     92     /** @hide */
     93     public static final int ROOT_ITEM_ID = Integer.MAX_VALUE - 1;
     94 
     95     /** @hide */
     96     public static final long UNDEFINED_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID);
     97 
     98     /** @hide */
     99     public static final long ROOT_NODE_ID = makeNodeId(ROOT_ITEM_ID,
    100             AccessibilityNodeProvider.HOST_VIEW_ID);
    101 
    102     /** @hide */
    103     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
    104 
    105     /** @hide */
    106     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
    107 
    108     /** @hide */
    109     public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
    110 
    111     /** @hide */
    112     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
    113 
    114     /** @hide */
    115     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
    116 
    117     // Actions.
    118 
    119     /**
    120      * Action that gives input focus to the node.
    121      */
    122     public static final int ACTION_FOCUS =  0x00000001;
    123 
    124     /**
    125      * Action that clears input focus of the node.
    126      */
    127     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
    128 
    129     /**
    130      * Action that selects the node.
    131      */
    132     public static final int ACTION_SELECT = 0x00000004;
    133 
    134     /**
    135      * Action that deselects the node.
    136      */
    137     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
    138 
    139     /**
    140      * Action that clicks on the node info.
    141      *
    142      * See {@link AccessibilityAction#ACTION_CLICK}
    143      */
    144     public static final int ACTION_CLICK = 0x00000010;
    145 
    146     /**
    147      * Action that long clicks on the node.
    148      */
    149     public static final int ACTION_LONG_CLICK = 0x00000020;
    150 
    151     /**
    152      * Action that gives accessibility focus to the node.
    153      */
    154     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
    155 
    156     /**
    157      * Action that clears accessibility focus of the node.
    158      */
    159     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
    160 
    161     /**
    162      * Action that requests to go to the next entity in this node's text
    163      * at a given movement granularity. For example, move to the next character,
    164      * word, etc.
    165      * <p>
    166      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    167      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    168      * <strong>Example:</strong> Move to the previous character and do not extend selection.
    169      * <code><pre><p>
    170      *   Bundle arguments = new Bundle();
    171      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    172      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    173      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    174      *           false);
    175      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
    176      * </code></pre></p>
    177      * </p>
    178      *
    179      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    180      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    181      *
    182      * @see #setMovementGranularities(int)
    183      * @see #getMovementGranularities()
    184      *
    185      * @see #MOVEMENT_GRANULARITY_CHARACTER
    186      * @see #MOVEMENT_GRANULARITY_WORD
    187      * @see #MOVEMENT_GRANULARITY_LINE
    188      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    189      * @see #MOVEMENT_GRANULARITY_PAGE
    190      */
    191     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
    192 
    193     /**
    194      * Action that requests to go to the previous entity in this node's text
    195      * at a given movement granularity. For example, move to the next character,
    196      * word, etc.
    197      * <p>
    198      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    199      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    200      * <strong>Example:</strong> Move to the next character and do not extend selection.
    201      * <code><pre><p>
    202      *   Bundle arguments = new Bundle();
    203      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    204      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    205      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    206      *           false);
    207      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
    208      *           arguments);
    209      * </code></pre></p>
    210      * </p>
    211      *
    212      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    213      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    214      *
    215      * @see #setMovementGranularities(int)
    216      * @see #getMovementGranularities()
    217      *
    218      * @see #MOVEMENT_GRANULARITY_CHARACTER
    219      * @see #MOVEMENT_GRANULARITY_WORD
    220      * @see #MOVEMENT_GRANULARITY_LINE
    221      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    222      * @see #MOVEMENT_GRANULARITY_PAGE
    223      */
    224     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
    225 
    226     /**
    227      * Action to move to the next HTML element of a given type. For example, move
    228      * to the BUTTON, INPUT, TABLE, etc.
    229      * <p>
    230      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    231      * <strong>Example:</strong>
    232      * <code><pre><p>
    233      *   Bundle arguments = new Bundle();
    234      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    235      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
    236      * </code></pre></p>
    237      * </p>
    238      */
    239     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
    240 
    241     /**
    242      * Action to move to the previous HTML element of a given type. For example, move
    243      * to the BUTTON, INPUT, TABLE, etc.
    244      * <p>
    245      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    246      * <strong>Example:</strong>
    247      * <code><pre><p>
    248      *   Bundle arguments = new Bundle();
    249      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    250      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
    251      * </code></pre></p>
    252      * </p>
    253      */
    254     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
    255 
    256     /**
    257      * Action to scroll the node content forward.
    258      */
    259     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
    260 
    261     /**
    262      * Action to scroll the node content backward.
    263      */
    264     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
    265 
    266     /**
    267      * Action to copy the current selection to the clipboard.
    268      */
    269     public static final int ACTION_COPY = 0x00004000;
    270 
    271     /**
    272      * Action to paste the current clipboard content.
    273      */
    274     public static final int ACTION_PASTE = 0x00008000;
    275 
    276     /**
    277      * Action to cut the current selection and place it to the clipboard.
    278      */
    279     public static final int ACTION_CUT = 0x00010000;
    280 
    281     /**
    282      * Action to set the selection. Performing this action with no arguments
    283      * clears the selection.
    284      * <p>
    285      * <strong>Arguments:</strong>
    286      * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
    287      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
    288      * <strong>Example:</strong>
    289      * <code><pre><p>
    290      *   Bundle arguments = new Bundle();
    291      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
    292      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
    293      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
    294      * </code></pre></p>
    295      * </p>
    296      *
    297      * @see #ACTION_ARGUMENT_SELECTION_START_INT
    298      * @see #ACTION_ARGUMENT_SELECTION_END_INT
    299      */
    300     public static final int ACTION_SET_SELECTION = 0x00020000;
    301 
    302     /**
    303      * Action to expand an expandable node.
    304      */
    305     public static final int ACTION_EXPAND = 0x00040000;
    306 
    307     /**
    308      * Action to collapse an expandable node.
    309      */
    310     public static final int ACTION_COLLAPSE = 0x00080000;
    311 
    312     /**
    313      * Action to dismiss a dismissable node.
    314      */
    315     public static final int ACTION_DISMISS = 0x00100000;
    316 
    317     /**
    318      * Action that sets the text of the node. Performing the action without argument, using <code>
    319      * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
    320      * cursor at the end of text.
    321      * <p>
    322      * <strong>Arguments:</strong>
    323      * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
    324      * <strong>Example:</strong>
    325      * <code><pre><p>
    326      *   Bundle arguments = new Bundle();
    327      *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
    328      *       "android");
    329      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
    330      * </code></pre></p>
    331      */
    332     public static final int ACTION_SET_TEXT = 0x00200000;
    333 
    334     private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
    335 
    336     /**
    337      * Mask to see if the value is larger than the largest ACTION_ constant
    338      */
    339     private static final int ACTION_TYPE_MASK = 0xFF000000;
    340 
    341     // Action arguments
    342 
    343     /**
    344      * Argument for which movement granularity to be used when traversing the node text.
    345      * <p>
    346      * <strong>Type:</strong> int<br>
    347      * <strong>Actions:</strong>
    348      * <ul>
    349      *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
    350      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
    351      * </ul>
    352      * </p>
    353      *
    354      * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    355      * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    356      */
    357     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
    358             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
    359 
    360     /**
    361      * Argument for which HTML element to get moving to the next/previous HTML element.
    362      * <p>
    363      * <strong>Type:</strong> String<br>
    364      * <strong>Actions:</strong>
    365      * <ul>
    366      *     <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li>
    367      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li>
    368      * </ul>
    369      * </p>
    370      *
    371      * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT
    372      * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT
    373      */
    374     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
    375             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
    376 
    377     /**
    378      * Argument for whether when moving at granularity to extend the selection
    379      * or to move it otherwise.
    380      * <p>
    381      * <strong>Type:</strong> boolean<br>
    382      * <strong>Actions:</strong>
    383      * <ul>
    384      *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
    385      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
    386      * </ul>
    387      *
    388      * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    389      * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    390      */
    391     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
    392             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
    393 
    394     /**
    395      * Argument for specifying the selection start.
    396      * <p>
    397      * <strong>Type:</strong> int<br>
    398      * <strong>Actions:</strong>
    399      * <ul>
    400      *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
    401      * </ul>
    402      *
    403      * @see AccessibilityAction#ACTION_SET_SELECTION
    404      */
    405     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
    406             "ACTION_ARGUMENT_SELECTION_START_INT";
    407 
    408     /**
    409      * Argument for specifying the selection end.
    410      * <p>
    411      * <strong>Type:</strong> int<br>
    412      * <strong>Actions:</strong>
    413      * <ul>
    414      *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
    415      * </ul>
    416      *
    417      * @see AccessibilityAction#ACTION_SET_SELECTION
    418      */
    419     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
    420             "ACTION_ARGUMENT_SELECTION_END_INT";
    421 
    422     /**
    423      * Argument for specifying the text content to set.
    424      * <p>
    425      * <strong>Type:</strong> CharSequence<br>
    426      * <strong>Actions:</strong>
    427      * <ul>
    428      *     <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li>
    429      * </ul>
    430      *
    431      * @see AccessibilityAction#ACTION_SET_TEXT
    432      */
    433     public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
    434             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
    435 
    436     /**
    437      * Argument for specifying the collection row to make visible on screen.
    438      * <p>
    439      * <strong>Type:</strong> int<br>
    440      * <strong>Actions:</strong>
    441      * <ul>
    442      *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
    443      * </ul>
    444      *
    445      * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
    446      */
    447     public static final String ACTION_ARGUMENT_ROW_INT =
    448             "android.view.accessibility.action.ARGUMENT_ROW_INT";
    449 
    450     /**
    451      * Argument for specifying the collection column to make visible on screen.
    452      * <p>
    453      * <strong>Type:</strong> int<br>
    454      * <strong>Actions:</strong>
    455      * <ul>
    456      *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
    457      * </ul>
    458      *
    459      * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
    460      */
    461     public static final String ACTION_ARGUMENT_COLUMN_INT =
    462             "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
    463 
    464     /**
    465      * Argument for specifying the progress value to set.
    466      * <p>
    467      * <strong>Type:</strong> float<br>
    468      * <strong>Actions:</strong>
    469      * <ul>
    470      *     <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li>
    471      * </ul>
    472      *
    473      * @see AccessibilityAction#ACTION_SET_PROGRESS
    474      */
    475     public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
    476             "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
    477 
    478     /**
    479      * Argument for specifying the x coordinate to which to move a window.
    480      * <p>
    481      * <strong>Type:</strong> int<br>
    482      * <strong>Actions:</strong>
    483      * <ul>
    484      *     <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
    485      * </ul>
    486      *
    487      * @see AccessibilityAction#ACTION_MOVE_WINDOW
    488      */
    489     public static final String ACTION_ARGUMENT_MOVE_WINDOW_X =
    490             "ACTION_ARGUMENT_MOVE_WINDOW_X";
    491 
    492     /**
    493      * Argument for specifying the y coordinate to which to move a window.
    494      * <p>
    495      * <strong>Type:</strong> int<br>
    496      * <strong>Actions:</strong>
    497      * <ul>
    498      *     <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
    499      * </ul>
    500      *
    501      * @see AccessibilityAction#ACTION_MOVE_WINDOW
    502      */
    503     public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y =
    504             "ACTION_ARGUMENT_MOVE_WINDOW_Y";
    505 
    506     /**
    507      * Argument to pass the {@link AccessibilityClickableSpan}.
    508      * For use with R.id.accessibilityActionClickOnClickableSpan
    509      * @hide
    510      */
    511     public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
    512             "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
    513 
    514     // Focus types
    515 
    516     /**
    517      * The input focus.
    518      */
    519     public static final int FOCUS_INPUT = 1;
    520 
    521     /**
    522      * The accessibility focus.
    523      */
    524     public static final int FOCUS_ACCESSIBILITY = 2;
    525 
    526     // Movement granularities
    527 
    528     /**
    529      * Movement granularity bit for traversing the text of a node by character.
    530      */
    531     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
    532 
    533     /**
    534      * Movement granularity bit for traversing the text of a node by word.
    535      */
    536     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
    537 
    538     /**
    539      * Movement granularity bit for traversing the text of a node by line.
    540      */
    541     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
    542 
    543     /**
    544      * Movement granularity bit for traversing the text of a node by paragraph.
    545      */
    546     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
    547 
    548     /**
    549      * Movement granularity bit for traversing the text of a node by page.
    550      */
    551     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
    552 
    553     /**
    554      * Key used to request and locate extra data for text character location. This key requests that
    555      * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with
    556      * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two
    557      * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and
    558      * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid
    559      * inside the CharSequence returned by {@link #getText()}, and the length must be positive.
    560      * <p>
    561      * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this
    562      * string as a key for {@link Bundle#getParcelableArray(String)}. The
    563      * {@link android.graphics.RectF} will be null for characters that either do not exist or are
    564      * off the screen.
    565      *
    566      * {@see #refreshWithExtraData(String, Bundle)}
    567      */
    568     public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY =
    569             "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
    570 
    571     /**
    572      * Integer argument specifying the start index of the requested text location data. Must be
    573      * valid inside the CharSequence returned by {@link #getText()}.
    574      *
    575      * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
    576      */
    577     public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX =
    578             "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
    579 
    580     /**
    581      * Integer argument specifying the end index of the requested text location data. Must be
    582      * positive.
    583      *
    584      * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
    585      */
    586     public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
    587             "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
    588 
    589     /** @hide */
    590     public static final String EXTRA_DATA_REQUESTED_KEY =
    591             "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
    592 
    593     // Boolean attributes.
    594 
    595     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
    596 
    597     private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
    598 
    599     private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
    600 
    601     private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
    602 
    603     private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
    604 
    605     private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
    606 
    607     private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
    608 
    609     private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
    610 
    611     private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
    612 
    613     private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
    614 
    615     private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
    616 
    617     private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
    618 
    619     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
    620 
    621     private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
    622 
    623     private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
    624 
    625     private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
    626 
    627     private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
    628 
    629     private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 0x00020000;
    630 
    631     private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
    632 
    633     private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
    634 
    635     /**
    636      * Bits that provide the id of a virtual descendant of a view.
    637      */
    638     private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
    639 
    640     /**
    641      * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
    642      * virtual descendant of a view. Such a descendant does not exist in the view
    643      * hierarchy and is only reported via the accessibility APIs.
    644      */
    645     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
    646 
    647     private static AtomicInteger sNumInstancesInUse;
    648 
    649     /**
    650      * Gets the accessibility view id which identifies a View in the view three.
    651      *
    652      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    653      * @return The accessibility view id part of the node id.
    654      *
    655      * @hide
    656      */
    657     public static int getAccessibilityViewId(long accessibilityNodeId) {
    658         return (int) accessibilityNodeId;
    659     }
    660 
    661     /**
    662      * Gets the virtual descendant id which identifies an imaginary view in a
    663      * containing View.
    664      *
    665      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    666      * @return The virtual view id part of the node id.
    667      *
    668      * @hide
    669      */
    670     public static int getVirtualDescendantId(long accessibilityNodeId) {
    671         return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
    672                 >> VIRTUAL_DESCENDANT_ID_SHIFT);
    673     }
    674 
    675     /**
    676      * Makes a node id by shifting the <code>virtualDescendantId</code>
    677      * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
    678      * the bitwise or with the <code>accessibilityViewId</code>.
    679      *
    680      * @param accessibilityViewId A View accessibility id.
    681      * @param virtualDescendantId A virtual descendant id.
    682      * @return The node id.
    683      *
    684      * @hide
    685      */
    686     public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
    687         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
    688     }
    689 
    690     // Housekeeping.
    691     private static final int MAX_POOL_SIZE = 50;
    692     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
    693             new SynchronizedPool<>(MAX_POOL_SIZE);
    694 
    695     private boolean mSealed;
    696 
    697     // Data.
    698     private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
    699     private long mSourceNodeId = UNDEFINED_NODE_ID;
    700     private long mParentNodeId = UNDEFINED_NODE_ID;
    701     private long mLabelForId = UNDEFINED_NODE_ID;
    702     private long mLabeledById = UNDEFINED_NODE_ID;
    703     private long mTraversalBefore = UNDEFINED_NODE_ID;
    704     private long mTraversalAfter = UNDEFINED_NODE_ID;
    705 
    706     private int mBooleanProperties;
    707     private final Rect mBoundsInParent = new Rect();
    708     private final Rect mBoundsInScreen = new Rect();
    709     private int mDrawingOrderInParent;
    710 
    711     private CharSequence mPackageName;
    712     private CharSequence mClassName;
    713     // Hidden, unparceled value used to hold the original value passed to setText
    714     private CharSequence mOriginalText;
    715     private CharSequence mText;
    716     private CharSequence mHintText;
    717     private CharSequence mError;
    718     private CharSequence mContentDescription;
    719     private String mViewIdResourceName;
    720     private ArrayList<String> mExtraDataKeys;
    721 
    722     private LongArray mChildNodeIds;
    723     private ArrayList<AccessibilityAction> mActions;
    724 
    725     private int mMaxTextLength = -1;
    726     private int mMovementGranularities;
    727 
    728     private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
    729     private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
    730     private int mInputType = InputType.TYPE_NULL;
    731     private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
    732 
    733     private Bundle mExtras;
    734 
    735     private int mConnectionId = UNDEFINED_CONNECTION_ID;
    736 
    737     private RangeInfo mRangeInfo;
    738     private CollectionInfo mCollectionInfo;
    739     private CollectionItemInfo mCollectionItemInfo;
    740 
    741     /**
    742      * Hide constructor from clients.
    743      */
    744     private AccessibilityNodeInfo() {
    745         /* do nothing */
    746     }
    747 
    748     /**
    749      * Sets the source.
    750      * <p>
    751      *   <strong>Note:</strong> Cannot be called from an
    752      *   {@link android.accessibilityservice.AccessibilityService}.
    753      *   This class is made immutable before being delivered to an AccessibilityService.
    754      * </p>
    755      *
    756      * @param source The info source.
    757      */
    758     public void setSource(View source) {
    759         setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID);
    760     }
    761 
    762     /**
    763      * Sets the source to be a virtual descendant of the given <code>root</code>.
    764      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
    765      * is set as the source.
    766      * <p>
    767      * A virtual descendant is an imaginary View that is reported as a part of the view
    768      * hierarchy for accessibility purposes. This enables custom views that draw complex
    769      * content to report themselves as a tree of virtual views, thus conveying their
    770      * logical structure.
    771      * </p>
    772      * <p>
    773      *   <strong>Note:</strong> Cannot be called from an
    774      *   {@link android.accessibilityservice.AccessibilityService}.
    775      *   This class is made immutable before being delivered to an AccessibilityService.
    776      * </p>
    777      *
    778      * @param root The root of the virtual subtree.
    779      * @param virtualDescendantId The id of the virtual descendant.
    780      */
    781     public void setSource(View root, int virtualDescendantId) {
    782         enforceNotSealed();
    783         mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID;
    784         final int rootAccessibilityViewId =
    785             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
    786         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    787     }
    788 
    789     /**
    790      * Find the view that has the specified focus type. The search starts from
    791      * the view represented by this node info.
    792      *
    793      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
    794      *         {@link #FOCUS_ACCESSIBILITY}.
    795      * @return The node info of the focused view or null.
    796      *
    797      * @see #FOCUS_INPUT
    798      * @see #FOCUS_ACCESSIBILITY
    799      */
    800     public AccessibilityNodeInfo findFocus(int focus) {
    801         enforceSealed();
    802         enforceValidFocusType(focus);
    803         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    804             return null;
    805         }
    806         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
    807                 mSourceNodeId, focus);
    808     }
    809 
    810     /**
    811      * Searches for the nearest view in the specified direction that can take
    812      * the input focus.
    813      *
    814      * @param direction The direction. Can be one of:
    815      *     {@link View#FOCUS_DOWN},
    816      *     {@link View#FOCUS_UP},
    817      *     {@link View#FOCUS_LEFT},
    818      *     {@link View#FOCUS_RIGHT},
    819      *     {@link View#FOCUS_FORWARD},
    820      *     {@link View#FOCUS_BACKWARD}.
    821      *
    822      * @return The node info for the view that can take accessibility focus.
    823      */
    824     public AccessibilityNodeInfo focusSearch(int direction) {
    825         enforceSealed();
    826         enforceValidFocusDirection(direction);
    827         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    828             return null;
    829         }
    830         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
    831                 mSourceNodeId, direction);
    832     }
    833 
    834     /**
    835      * Gets the id of the window from which the info comes from.
    836      *
    837      * @return The window id.
    838      */
    839     public int getWindowId() {
    840         return mWindowId;
    841     }
    842 
    843     /**
    844      * Refreshes this info with the latest state of the view it represents.
    845      * <p>
    846      * <strong>Note:</strong> If this method returns false this info is obsolete
    847      * since it represents a view that is no longer in the view tree and should
    848      * be recycled.
    849      * </p>
    850      *
    851      * @param bypassCache Whether to bypass the cache.
    852      * @return Whether the refresh succeeded.
    853      *
    854      * @hide
    855      */
    856     public boolean refresh(Bundle arguments, boolean bypassCache) {
    857         enforceSealed();
    858         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    859             return false;
    860         }
    861         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    862         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
    863                 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments);
    864         if (refreshedInfo == null) {
    865             return false;
    866         }
    867         init(refreshedInfo);
    868         refreshedInfo.recycle();
    869         return true;
    870     }
    871 
    872     /**
    873      * Refreshes this info with the latest state of the view it represents.
    874      *
    875      * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
    876      * by this node is no longer in the view tree (and thus this node is obsolete and should be
    877      * recycled).
    878      */
    879     public boolean refresh() {
    880         return refresh(null, true);
    881     }
    882 
    883     /**
    884      * Refreshes this info with the latest state of the view it represents, and request new
    885      * data be added by the View.
    886      *
    887      * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
    888      *                     with this mechanism is generally expensive to retrieve, so should only be
    889      *                     requested when needed. See
    890      *                     {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
    891      *                     {@link #getAvailableExtraData()}.
    892      * @param args A bundle of arguments for the request. These depend on the particular request.
    893      *
    894      * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
    895      * by this node is no longer in the view tree (and thus this node is obsolete and should be
    896      * recycled).
    897      */
    898     public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
    899         args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
    900         return refresh(args, true);
    901     }
    902 
    903     /**
    904      * Returns the array containing the IDs of this node's children.
    905      *
    906      * @hide
    907      */
    908     public LongArray getChildNodeIds() {
    909         return mChildNodeIds;
    910     }
    911 
    912     /**
    913      * Returns the id of the child at the specified index.
    914      *
    915      * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
    916      *             getChildCount()
    917      * @hide
    918      */
    919     public long getChildId(int index) {
    920         if (mChildNodeIds == null) {
    921             throw new IndexOutOfBoundsException();
    922         }
    923         return mChildNodeIds.get(index);
    924     }
    925 
    926     /**
    927      * Gets the number of children.
    928      *
    929      * @return The child count.
    930      */
    931     public int getChildCount() {
    932         return mChildNodeIds == null ? 0 : mChildNodeIds.size();
    933     }
    934 
    935     /**
    936      * Get the child at given index.
    937      * <p>
    938      *   <strong>Note:</strong> It is a client responsibility to recycle the
    939      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    940      *     to avoid creating of multiple instances.
    941      * </p>
    942      *
    943      * @param index The child index.
    944      * @return The child node.
    945      *
    946      * @throws IllegalStateException If called outside of an AccessibilityService.
    947      *
    948      */
    949     public AccessibilityNodeInfo getChild(int index) {
    950         enforceSealed();
    951         if (mChildNodeIds == null) {
    952             return null;
    953         }
    954         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    955             return null;
    956         }
    957         final long childId = mChildNodeIds.get(index);
    958         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    959         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
    960                 childId, false, FLAG_PREFETCH_DESCENDANTS, null);
    961     }
    962 
    963     /**
    964      * Adds a child.
    965      * <p>
    966      * <strong>Note:</strong> Cannot be called from an
    967      * {@link android.accessibilityservice.AccessibilityService}.
    968      * This class is made immutable before being delivered to an AccessibilityService.
    969      * </p>
    970      *
    971      * @param child The child.
    972      *
    973      * @throws IllegalStateException If called from an AccessibilityService.
    974      */
    975     public void addChild(View child) {
    976         addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, true);
    977     }
    978 
    979     /**
    980      * Unchecked version of {@link #addChild(View)} that does not verify
    981      * uniqueness. For framework use only.
    982      *
    983      * @hide
    984      */
    985     public void addChildUnchecked(View child) {
    986         addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, false);
    987     }
    988 
    989     /**
    990      * Removes a child. If the child was not previously added to the node,
    991      * calling this method has no effect.
    992      * <p>
    993      * <strong>Note:</strong> Cannot be called from an
    994      * {@link android.accessibilityservice.AccessibilityService}.
    995      * This class is made immutable before being delivered to an AccessibilityService.
    996      * </p>
    997      *
    998      * @param child The child.
    999      * @return true if the child was present
   1000      *
   1001      * @throws IllegalStateException If called from an AccessibilityService.
   1002      */
   1003     public boolean removeChild(View child) {
   1004         return removeChild(child, AccessibilityNodeProvider.HOST_VIEW_ID);
   1005     }
   1006 
   1007     /**
   1008      * Adds a virtual child which is a descendant of the given <code>root</code>.
   1009      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
   1010      * is added as a child.
   1011      * <p>
   1012      * A virtual descendant is an imaginary View that is reported as a part of the view
   1013      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1014      * content to report them selves as a tree of virtual views, thus conveying their
   1015      * logical structure.
   1016      * </p>
   1017      *
   1018      * @param root The root of the virtual subtree.
   1019      * @param virtualDescendantId The id of the virtual child.
   1020      */
   1021     public void addChild(View root, int virtualDescendantId) {
   1022         addChildInternal(root, virtualDescendantId, true);
   1023     }
   1024 
   1025     private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
   1026         enforceNotSealed();
   1027         if (mChildNodeIds == null) {
   1028             mChildNodeIds = new LongArray();
   1029         }
   1030         final int rootAccessibilityViewId =
   1031             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   1032         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1033         // If we're checking uniqueness and the ID already exists, abort.
   1034         if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
   1035             return;
   1036         }
   1037         mChildNodeIds.add(childNodeId);
   1038     }
   1039 
   1040     /**
   1041      * Removes a virtual child which is a descendant of the given
   1042      * <code>root</code>. If the child was not previously added to the node,
   1043      * calling this method has no effect.
   1044      *
   1045      * @param root The root of the virtual subtree.
   1046      * @param virtualDescendantId The id of the virtual child.
   1047      * @return true if the child was present
   1048      * @see #addChild(View, int)
   1049      */
   1050     public boolean removeChild(View root, int virtualDescendantId) {
   1051         enforceNotSealed();
   1052         final LongArray childIds = mChildNodeIds;
   1053         if (childIds == null) {
   1054             return false;
   1055         }
   1056         final int rootAccessibilityViewId =
   1057                 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   1058         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1059         final int index = childIds.indexOf(childNodeId);
   1060         if (index < 0) {
   1061             return false;
   1062         }
   1063         childIds.remove(index);
   1064         return true;
   1065     }
   1066 
   1067     /**
   1068      * Gets the actions that can be performed on the node.
   1069      */
   1070     public List<AccessibilityAction> getActionList() {
   1071         if (mActions == null) {
   1072             return Collections.emptyList();
   1073         }
   1074 
   1075         return mActions;
   1076     }
   1077 
   1078     /**
   1079      * Gets the actions that can be performed on the node.
   1080      *
   1081      * @return The bit mask of with actions.
   1082      *
   1083      * @see AccessibilityNodeInfo#ACTION_FOCUS
   1084      * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
   1085      * @see AccessibilityNodeInfo#ACTION_SELECT
   1086      * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
   1087      * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
   1088      * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
   1089      * @see AccessibilityNodeInfo#ACTION_CLICK
   1090      * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
   1091      * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
   1092      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
   1093      * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
   1094      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
   1095      * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
   1096      * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
   1097      *
   1098      * @deprecated Use {@link #getActionList()}.
   1099      */
   1100     @Deprecated
   1101     public int getActions() {
   1102         int returnValue = 0;
   1103 
   1104         if (mActions == null) {
   1105             return returnValue;
   1106         }
   1107 
   1108         final int actionSize = mActions.size();
   1109         for (int i = 0; i < actionSize; i++) {
   1110             int actionId = mActions.get(i).getId();
   1111             if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
   1112                 returnValue |= actionId;
   1113             }
   1114         }
   1115 
   1116         return returnValue;
   1117     }
   1118 
   1119     /**
   1120      * Adds an action that can be performed on the node.
   1121      * <p>
   1122      * To add a standard action use the static constants on {@link AccessibilityAction}.
   1123      * To add a custom action create a new {@link AccessibilityAction} by passing in a
   1124      * resource id from your application as the action id and an optional label that
   1125      * describes the action. To override one of the standard actions use as the action
   1126      * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
   1127      * describes the action.
   1128      * </p>
   1129      * <p>
   1130      *   <strong>Note:</strong> Cannot be called from an
   1131      *   {@link android.accessibilityservice.AccessibilityService}.
   1132      *   This class is made immutable before being delivered to an AccessibilityService.
   1133      * </p>
   1134      *
   1135      * @param action The action.
   1136      *
   1137      * @throws IllegalStateException If called from an AccessibilityService.
   1138      */
   1139     public void addAction(AccessibilityAction action) {
   1140         enforceNotSealed();
   1141 
   1142         addActionUnchecked(action);
   1143     }
   1144 
   1145     private void addActionUnchecked(AccessibilityAction action) {
   1146         if (action == null) {
   1147             return;
   1148         }
   1149 
   1150         if (mActions == null) {
   1151             mActions = new ArrayList<>();
   1152         }
   1153 
   1154         mActions.remove(action);
   1155         mActions.add(action);
   1156     }
   1157 
   1158     /**
   1159      * Adds an action that can be performed on the node.
   1160      * <p>
   1161      *   <strong>Note:</strong> Cannot be called from an
   1162      *   {@link android.accessibilityservice.AccessibilityService}.
   1163      *   This class is made immutable before being delivered to an AccessibilityService.
   1164      * </p>
   1165      *
   1166      * @param action The action.
   1167      *
   1168      * @throws IllegalStateException If called from an AccessibilityService.
   1169      * @throws IllegalArgumentException If the argument is not one of the standard actions.
   1170      *
   1171      * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
   1172      */
   1173     @Deprecated
   1174     public void addAction(int action) {
   1175         enforceNotSealed();
   1176 
   1177         if ((action & ACTION_TYPE_MASK) != 0) {
   1178             throw new IllegalArgumentException("Action is not a combination of the standard " +
   1179                     "actions: " + action);
   1180         }
   1181 
   1182         addLegacyStandardActions(action);
   1183     }
   1184 
   1185     /**
   1186      * Removes an action that can be performed on the node. If the action was
   1187      * not already added to the node, calling this method has no effect.
   1188      * <p>
   1189      *   <strong>Note:</strong> Cannot be called from an
   1190      *   {@link android.accessibilityservice.AccessibilityService}.
   1191      *   This class is made immutable before being delivered to an AccessibilityService.
   1192      * </p>
   1193      *
   1194      * @param action The action to be removed.
   1195      *
   1196      * @throws IllegalStateException If called from an AccessibilityService.
   1197      * @deprecated Use {@link #removeAction(AccessibilityAction)}
   1198      */
   1199     @Deprecated
   1200     public void removeAction(int action) {
   1201         enforceNotSealed();
   1202 
   1203         removeAction(getActionSingleton(action));
   1204     }
   1205 
   1206     /**
   1207      * Removes an action that can be performed on the node. If the action was
   1208      * not already added to the node, calling this method has no effect.
   1209      * <p>
   1210      *   <strong>Note:</strong> Cannot be called from an
   1211      *   {@link android.accessibilityservice.AccessibilityService}.
   1212      *   This class is made immutable before being delivered to an AccessibilityService.
   1213      * </p>
   1214      *
   1215      * @param action The action to be removed.
   1216      * @return The action removed from the list of actions.
   1217      *
   1218      * @throws IllegalStateException If called from an AccessibilityService.
   1219      */
   1220     public boolean removeAction(AccessibilityAction action) {
   1221         enforceNotSealed();
   1222 
   1223         if (mActions == null || action == null) {
   1224             return false;
   1225         }
   1226 
   1227         return mActions.remove(action);
   1228     }
   1229 
   1230     /**
   1231      * Removes all actions.
   1232      *
   1233      * @hide
   1234      */
   1235     public void removeAllActions() {
   1236         if (mActions != null) {
   1237             mActions.clear();
   1238         }
   1239     }
   1240 
   1241     /**
   1242      * Gets the node before which this one is visited during traversal. A screen-reader
   1243      * must visit the content of this node before the content of the one it precedes.
   1244      *
   1245      * @return The succeeding node if such or <code>null</code>.
   1246      *
   1247      * @see #setTraversalBefore(android.view.View)
   1248      * @see #setTraversalBefore(android.view.View, int)
   1249      */
   1250     public AccessibilityNodeInfo getTraversalBefore() {
   1251         enforceSealed();
   1252         return getNodeForAccessibilityId(mTraversalBefore);
   1253     }
   1254 
   1255     /**
   1256      * Sets the view before whose node this one should be visited during traversal. A
   1257      * screen-reader must visit the content of this node before the content of the one
   1258      * it precedes.
   1259      * <p>
   1260      *   <strong>Note:</strong> Cannot be called from an
   1261      *   {@link android.accessibilityservice.AccessibilityService}.
   1262      *   This class is made immutable before being delivered to an AccessibilityService.
   1263      * </p>
   1264      *
   1265      * @param view The view providing the preceding node.
   1266      *
   1267      * @see #getTraversalBefore()
   1268      */
   1269     public void setTraversalBefore(View view) {
   1270         setTraversalBefore(view, AccessibilityNodeProvider.HOST_VIEW_ID);
   1271     }
   1272 
   1273     /**
   1274      * Sets the node before which this one is visited during traversal. A screen-reader
   1275      * must visit the content of this node before the content of the one it precedes.
   1276      * The successor is a virtual descendant of the given <code>root</code>. If
   1277      * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
   1278      * as the successor.
   1279      * <p>
   1280      * A virtual descendant is an imaginary View that is reported as a part of the view
   1281      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1282      * content to report them selves as a tree of virtual views, thus conveying their
   1283      * logical structure.
   1284      * </p>
   1285      * <p>
   1286      *   <strong>Note:</strong> Cannot be called from an
   1287      *   {@link android.accessibilityservice.AccessibilityService}.
   1288      *   This class is made immutable before being delivered to an AccessibilityService.
   1289      * </p>
   1290      *
   1291      * @param root The root of the virtual subtree.
   1292      * @param virtualDescendantId The id of the virtual descendant.
   1293      */
   1294     public void setTraversalBefore(View root, int virtualDescendantId) {
   1295         enforceNotSealed();
   1296         final int rootAccessibilityViewId = (root != null)
   1297                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   1298         mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1299     }
   1300 
   1301     /**
   1302      * Gets the node after which this one is visited in accessibility traversal.
   1303      * A screen-reader must visit the content of the other node before the content
   1304      * of this one.
   1305      *
   1306      * @return The succeeding node if such or <code>null</code>.
   1307      *
   1308      * @see #setTraversalAfter(android.view.View)
   1309      * @see #setTraversalAfter(android.view.View, int)
   1310      */
   1311     public AccessibilityNodeInfo getTraversalAfter() {
   1312         enforceSealed();
   1313         return getNodeForAccessibilityId(mTraversalAfter);
   1314     }
   1315 
   1316     /**
   1317      * Sets the view whose node is visited after this one in accessibility traversal.
   1318      * A screen-reader must visit the content of the other node before the content
   1319      * of this one.
   1320      * <p>
   1321      *   <strong>Note:</strong> Cannot be called from an
   1322      *   {@link android.accessibilityservice.AccessibilityService}.
   1323      *   This class is made immutable before being delivered to an AccessibilityService.
   1324      * </p>
   1325      *
   1326      * @param view The previous view.
   1327      *
   1328      * @see #getTraversalAfter()
   1329      */
   1330     public void setTraversalAfter(View view) {
   1331         setTraversalAfter(view, AccessibilityNodeProvider.HOST_VIEW_ID);
   1332     }
   1333 
   1334     /**
   1335      * Sets the node after which this one is visited in accessibility traversal.
   1336      * A screen-reader must visit the content of the other node before the content
   1337      * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
   1338      * the root is set as the predecessor.
   1339      * <p>
   1340      * A virtual descendant is an imaginary View that is reported as a part of the view
   1341      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1342      * content to report them selves as a tree of virtual views, thus conveying their
   1343      * logical structure.
   1344      * </p>
   1345      * <p>
   1346      *   <strong>Note:</strong> Cannot be called from an
   1347      *   {@link android.accessibilityservice.AccessibilityService}.
   1348      *   This class is made immutable before being delivered to an AccessibilityService.
   1349      * </p>
   1350      *
   1351      * @param root The root of the virtual subtree.
   1352      * @param virtualDescendantId The id of the virtual descendant.
   1353      */
   1354     public void setTraversalAfter(View root, int virtualDescendantId) {
   1355         enforceNotSealed();
   1356         final int rootAccessibilityViewId = (root != null)
   1357                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   1358         mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1359     }
   1360 
   1361     /**
   1362      * Get the extra data available for this node.
   1363      * <p>
   1364      * Some data that is useful for some accessibility services is expensive to compute, and would
   1365      * place undue overhead on apps to compute all the time. That data can be requested with
   1366      * {@link #refreshWithExtraData(String, Bundle)}.
   1367      *
   1368      * @return An unmodifiable list of keys corresponding to extra data that can be requested.
   1369      * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
   1370      */
   1371     public List<String> getAvailableExtraData() {
   1372         if (mExtraDataKeys != null) {
   1373             return Collections.unmodifiableList(mExtraDataKeys);
   1374         } else {
   1375             return EMPTY_LIST;
   1376         }
   1377     }
   1378 
   1379     /**
   1380      * Set the extra data available for this node.
   1381      * <p>
   1382      * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that
   1383      * it will populate the node's extras with corresponding pieces of information in
   1384      * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}.
   1385      * <p>
   1386      * <strong>Note:</strong> Cannot be called from an
   1387      * {@link android.accessibilityservice.AccessibilityService}.
   1388      * This class is made immutable before being delivered to an AccessibilityService.
   1389      *
   1390      * @param extraDataKeys A list of types of extra data that are available.
   1391      * @see #getAvailableExtraData()
   1392      *
   1393      * @throws IllegalStateException If called from an AccessibilityService.
   1394      */
   1395     public void setAvailableExtraData(List<String> extraDataKeys) {
   1396         enforceNotSealed();
   1397         mExtraDataKeys = new ArrayList<>(extraDataKeys);
   1398     }
   1399 
   1400     /**
   1401      * Sets the maximum text length, or -1 for no limit.
   1402      * <p>
   1403      * Typically used to indicate that an editable text field has a limit on
   1404      * the number of characters entered.
   1405      * <p>
   1406      * <strong>Note:</strong> Cannot be called from an
   1407      * {@link android.accessibilityservice.AccessibilityService}.
   1408      * This class is made immutable before being delivered to an AccessibilityService.
   1409      *
   1410      * @param max The maximum text length.
   1411      * @see #getMaxTextLength()
   1412      *
   1413      * @throws IllegalStateException If called from an AccessibilityService.
   1414      */
   1415     public void setMaxTextLength(int max) {
   1416         enforceNotSealed();
   1417         mMaxTextLength = max;
   1418     }
   1419 
   1420     /**
   1421      * Returns the maximum text length for this node.
   1422      *
   1423      * @return The maximum text length, or -1 for no limit.
   1424      * @see #setMaxTextLength(int)
   1425      */
   1426     public int getMaxTextLength() {
   1427         return mMaxTextLength;
   1428     }
   1429 
   1430     /**
   1431      * Sets the movement granularities for traversing the text of this node.
   1432      * <p>
   1433      *   <strong>Note:</strong> Cannot be called from an
   1434      *   {@link android.accessibilityservice.AccessibilityService}.
   1435      *   This class is made immutable before being delivered to an AccessibilityService.
   1436      * </p>
   1437      *
   1438      * @param granularities The bit mask with granularities.
   1439      *
   1440      * @throws IllegalStateException If called from an AccessibilityService.
   1441      */
   1442     public void setMovementGranularities(int granularities) {
   1443         enforceNotSealed();
   1444         mMovementGranularities = granularities;
   1445     }
   1446 
   1447     /**
   1448      * Gets the movement granularities for traversing the text of this node.
   1449      *
   1450      * @return The bit mask with granularities.
   1451      */
   1452     public int getMovementGranularities() {
   1453         return mMovementGranularities;
   1454     }
   1455 
   1456     /**
   1457      * Performs an action on the node.
   1458      * <p>
   1459      *   <strong>Note:</strong> An action can be performed only if the request is made
   1460      *   from an {@link android.accessibilityservice.AccessibilityService}.
   1461      * </p>
   1462      *
   1463      * @param action The action to perform.
   1464      * @return True if the action was performed.
   1465      *
   1466      * @throws IllegalStateException If called outside of an AccessibilityService.
   1467      */
   1468     public boolean performAction(int action) {
   1469         enforceSealed();
   1470         if (!canPerformRequestOverConnection(mSourceNodeId)) {
   1471             return false;
   1472         }
   1473         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1474         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
   1475                 action, null);
   1476     }
   1477 
   1478     /**
   1479      * Performs an action on the node.
   1480      * <p>
   1481      *   <strong>Note:</strong> An action can be performed only if the request is made
   1482      *   from an {@link android.accessibilityservice.AccessibilityService}.
   1483      * </p>
   1484      *
   1485      * @param action The action to perform.
   1486      * @param arguments A bundle with additional arguments.
   1487      * @return True if the action was performed.
   1488      *
   1489      * @throws IllegalStateException If called outside of an AccessibilityService.
   1490      */
   1491     public boolean performAction(int action, Bundle arguments) {
   1492         enforceSealed();
   1493         if (!canPerformRequestOverConnection(mSourceNodeId)) {
   1494             return false;
   1495         }
   1496         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1497         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
   1498                 action, arguments);
   1499     }
   1500 
   1501     /**
   1502      * Finds {@link AccessibilityNodeInfo}s by text. The match is case
   1503      * insensitive containment. The search is relative to this info i.e.
   1504      * this info is the root of the traversed tree.
   1505      *
   1506      * <p>
   1507      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1508      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1509      *     to avoid creating of multiple instances.
   1510      * </p>
   1511      *
   1512      * @param text The searched text.
   1513      * @return A list of node info.
   1514      */
   1515     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
   1516         enforceSealed();
   1517         if (!canPerformRequestOverConnection(mSourceNodeId)) {
   1518             return Collections.emptyList();
   1519         }
   1520         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1521         return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
   1522                 text);
   1523     }
   1524 
   1525     /**
   1526      * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
   1527      * name where a fully qualified id is of the from "package:id/id_resource_name".
   1528      * For example, if the target application's package is "foo.bar" and the id
   1529      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
   1530      *
   1531      * <p>
   1532      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1533      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1534      *     to avoid creating of multiple instances.
   1535      * </p>
   1536      * <p>
   1537      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   1538      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
   1539      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
   1540      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   1541      * </p>
   1542      *
   1543      * @param viewId The fully qualified resource name of the view id to find.
   1544      * @return A list of node info.
   1545      */
   1546     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
   1547         enforceSealed();
   1548         if (!canPerformRequestOverConnection(mSourceNodeId)) {
   1549             return Collections.emptyList();
   1550         }
   1551         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1552         return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
   1553                 viewId);
   1554     }
   1555 
   1556     /**
   1557      * Gets the window to which this node belongs.
   1558      *
   1559      * @return The window.
   1560      *
   1561      * @see android.accessibilityservice.AccessibilityService#getWindows()
   1562      */
   1563     public AccessibilityWindowInfo getWindow() {
   1564         enforceSealed();
   1565         if (!canPerformRequestOverConnection(mSourceNodeId)) {
   1566             return null;
   1567         }
   1568         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1569         return client.getWindow(mConnectionId, mWindowId);
   1570     }
   1571 
   1572     /**
   1573      * Gets the parent.
   1574      * <p>
   1575      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1576      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1577      *     to avoid creating of multiple instances.
   1578      * </p>
   1579      *
   1580      * @return The parent.
   1581      */
   1582     public AccessibilityNodeInfo getParent() {
   1583         enforceSealed();
   1584         return getNodeForAccessibilityId(mParentNodeId);
   1585     }
   1586 
   1587     /**
   1588      * @return The parent node id.
   1589      *
   1590      * @hide
   1591      */
   1592     public long getParentNodeId() {
   1593         return mParentNodeId;
   1594     }
   1595 
   1596     /**
   1597      * Sets the parent.
   1598      * <p>
   1599      *   <strong>Note:</strong> Cannot be called from an
   1600      *   {@link android.accessibilityservice.AccessibilityService}.
   1601      *   This class is made immutable before being delivered to an AccessibilityService.
   1602      * </p>
   1603      *
   1604      * @param parent The parent.
   1605      *
   1606      * @throws IllegalStateException If called from an AccessibilityService.
   1607      */
   1608     public void setParent(View parent) {
   1609         setParent(parent, AccessibilityNodeProvider.HOST_VIEW_ID);
   1610     }
   1611 
   1612     /**
   1613      * Sets the parent to be a virtual descendant of the given <code>root</code>.
   1614      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
   1615      * is set as the parent.
   1616      * <p>
   1617      * A virtual descendant is an imaginary View that is reported as a part of the view
   1618      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1619      * content to report them selves as a tree of virtual views, thus conveying their
   1620      * logical structure.
   1621      * </p>
   1622      * <p>
   1623      *   <strong>Note:</strong> Cannot be called from an
   1624      *   {@link android.accessibilityservice.AccessibilityService}.
   1625      *   This class is made immutable before being delivered to an AccessibilityService.
   1626      * </p>
   1627      *
   1628      * @param root The root of the virtual subtree.
   1629      * @param virtualDescendantId The id of the virtual descendant.
   1630      */
   1631     public void setParent(View root, int virtualDescendantId) {
   1632         enforceNotSealed();
   1633         final int rootAccessibilityViewId =
   1634             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   1635         mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1636     }
   1637 
   1638     /**
   1639      * Gets the node bounds in parent coordinates.
   1640      *
   1641      * @param outBounds The output node bounds.
   1642      */
   1643     public void getBoundsInParent(Rect outBounds) {
   1644         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
   1645                 mBoundsInParent.right, mBoundsInParent.bottom);
   1646     }
   1647 
   1648     /**
   1649      * Sets the node bounds in parent coordinates.
   1650      * <p>
   1651      *   <strong>Note:</strong> Cannot be called from an
   1652      *   {@link android.accessibilityservice.AccessibilityService}.
   1653      *   This class is made immutable before being delivered to an AccessibilityService.
   1654      * </p>
   1655      *
   1656      * @param bounds The node bounds.
   1657      *
   1658      * @throws IllegalStateException If called from an AccessibilityService.
   1659      */
   1660     public void setBoundsInParent(Rect bounds) {
   1661         enforceNotSealed();
   1662         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1663     }
   1664 
   1665     /**
   1666      * Gets the node bounds in screen coordinates.
   1667      *
   1668      * @param outBounds The output node bounds.
   1669      */
   1670     public void getBoundsInScreen(Rect outBounds) {
   1671         outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
   1672                 mBoundsInScreen.right, mBoundsInScreen.bottom);
   1673     }
   1674 
   1675     /**
   1676      * Returns the actual rect containing the node bounds in screen coordinates.
   1677      *
   1678      * @hide Not safe to expose outside the framework.
   1679      */
   1680     public Rect getBoundsInScreen() {
   1681         return mBoundsInScreen;
   1682     }
   1683 
   1684     /**
   1685      * Sets the node bounds in screen coordinates.
   1686      * <p>
   1687      *   <strong>Note:</strong> Cannot be called from an
   1688      *   {@link android.accessibilityservice.AccessibilityService}.
   1689      *   This class is made immutable before being delivered to an AccessibilityService.
   1690      * </p>
   1691      *
   1692      * @param bounds The node bounds.
   1693      *
   1694      * @throws IllegalStateException If called from an AccessibilityService.
   1695      */
   1696     public void setBoundsInScreen(Rect bounds) {
   1697         enforceNotSealed();
   1698         mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1699     }
   1700 
   1701     /**
   1702      * Gets whether this node is checkable.
   1703      *
   1704      * @return True if the node is checkable.
   1705      */
   1706     public boolean isCheckable() {
   1707         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
   1708     }
   1709 
   1710     /**
   1711      * Sets whether this node is checkable.
   1712      * <p>
   1713      *   <strong>Note:</strong> Cannot be called from an
   1714      *   {@link android.accessibilityservice.AccessibilityService}.
   1715      *   This class is made immutable before being delivered to an AccessibilityService.
   1716      * </p>
   1717      *
   1718      * @param checkable True if the node is checkable.
   1719      *
   1720      * @throws IllegalStateException If called from an AccessibilityService.
   1721      */
   1722     public void setCheckable(boolean checkable) {
   1723         setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
   1724     }
   1725 
   1726     /**
   1727      * Gets whether this node is checked.
   1728      *
   1729      * @return True if the node is checked.
   1730      */
   1731     public boolean isChecked() {
   1732         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
   1733     }
   1734 
   1735     /**
   1736      * Sets whether this node is checked.
   1737      * <p>
   1738      *   <strong>Note:</strong> Cannot be called from an
   1739      *   {@link android.accessibilityservice.AccessibilityService}.
   1740      *   This class is made immutable before being delivered to an AccessibilityService.
   1741      * </p>
   1742      *
   1743      * @param checked True if the node is checked.
   1744      *
   1745      * @throws IllegalStateException If called from an AccessibilityService.
   1746      */
   1747     public void setChecked(boolean checked) {
   1748         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
   1749     }
   1750 
   1751     /**
   1752      * Gets whether this node is focusable.
   1753      *
   1754      * @return True if the node is focusable.
   1755      */
   1756     public boolean isFocusable() {
   1757         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
   1758     }
   1759 
   1760     /**
   1761      * Sets whether this node is focusable.
   1762      * <p>
   1763      *   <strong>Note:</strong> Cannot be called from an
   1764      *   {@link android.accessibilityservice.AccessibilityService}.
   1765      *   This class is made immutable before being delivered to an AccessibilityService.
   1766      * </p>
   1767      *
   1768      * @param focusable True if the node is focusable.
   1769      *
   1770      * @throws IllegalStateException If called from an AccessibilityService.
   1771      */
   1772     public void setFocusable(boolean focusable) {
   1773         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
   1774     }
   1775 
   1776     /**
   1777      * Gets whether this node is focused.
   1778      *
   1779      * @return True if the node is focused.
   1780      */
   1781     public boolean isFocused() {
   1782         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
   1783     }
   1784 
   1785     /**
   1786      * Sets whether this node is focused.
   1787      * <p>
   1788      *   <strong>Note:</strong> Cannot be called from an
   1789      *   {@link android.accessibilityservice.AccessibilityService}.
   1790      *   This class is made immutable before being delivered to an AccessibilityService.
   1791      * </p>
   1792      *
   1793      * @param focused True if the node is focused.
   1794      *
   1795      * @throws IllegalStateException If called from an AccessibilityService.
   1796      */
   1797     public void setFocused(boolean focused) {
   1798         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
   1799     }
   1800 
   1801     /**
   1802      * Gets whether this node is visible to the user.
   1803      *
   1804      * @return Whether the node is visible to the user.
   1805      */
   1806     public boolean isVisibleToUser() {
   1807         return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
   1808     }
   1809 
   1810     /**
   1811      * Sets whether this node is visible to the user.
   1812      * <p>
   1813      *   <strong>Note:</strong> Cannot be called from an
   1814      *   {@link android.accessibilityservice.AccessibilityService}.
   1815      *   This class is made immutable before being delivered to an AccessibilityService.
   1816      * </p>
   1817      *
   1818      * @param visibleToUser Whether the node is visible to the user.
   1819      *
   1820      * @throws IllegalStateException If called from an AccessibilityService.
   1821      */
   1822     public void setVisibleToUser(boolean visibleToUser) {
   1823         setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
   1824     }
   1825 
   1826     /**
   1827      * Gets whether this node is accessibility focused.
   1828      *
   1829      * @return True if the node is accessibility focused.
   1830      */
   1831     public boolean isAccessibilityFocused() {
   1832         return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
   1833     }
   1834 
   1835     /**
   1836      * Sets whether this node is accessibility focused.
   1837      * <p>
   1838      *   <strong>Note:</strong> Cannot be called from an
   1839      *   {@link android.accessibilityservice.AccessibilityService}.
   1840      *   This class is made immutable before being delivered to an AccessibilityService.
   1841      * </p>
   1842      *
   1843      * @param focused True if the node is accessibility focused.
   1844      *
   1845      * @throws IllegalStateException If called from an AccessibilityService.
   1846      */
   1847     public void setAccessibilityFocused(boolean focused) {
   1848         setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
   1849     }
   1850 
   1851     /**
   1852      * Gets whether this node is selected.
   1853      *
   1854      * @return True if the node is selected.
   1855      */
   1856     public boolean isSelected() {
   1857         return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
   1858     }
   1859 
   1860     /**
   1861      * Sets whether this node is selected.
   1862      * <p>
   1863      *   <strong>Note:</strong> Cannot be called from an
   1864      *   {@link android.accessibilityservice.AccessibilityService}.
   1865      *   This class is made immutable before being delivered to an AccessibilityService.
   1866      * </p>
   1867      *
   1868      * @param selected True if the node is selected.
   1869      *
   1870      * @throws IllegalStateException If called from an AccessibilityService.
   1871      */
   1872     public void setSelected(boolean selected) {
   1873         setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
   1874     }
   1875 
   1876     /**
   1877      * Gets whether this node is clickable.
   1878      *
   1879      * @return True if the node is clickable.
   1880      */
   1881     public boolean isClickable() {
   1882         return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
   1883     }
   1884 
   1885     /**
   1886      * Sets whether this node is clickable.
   1887      * <p>
   1888      *   <strong>Note:</strong> Cannot be called from an
   1889      *   {@link android.accessibilityservice.AccessibilityService}.
   1890      *   This class is made immutable before being delivered to an AccessibilityService.
   1891      * </p>
   1892      *
   1893      * @param clickable True if the node is clickable.
   1894      *
   1895      * @throws IllegalStateException If called from an AccessibilityService.
   1896      */
   1897     public void setClickable(boolean clickable) {
   1898         setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
   1899     }
   1900 
   1901     /**
   1902      * Gets whether this node is long clickable.
   1903      *
   1904      * @return True if the node is long clickable.
   1905      */
   1906     public boolean isLongClickable() {
   1907         return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
   1908     }
   1909 
   1910     /**
   1911      * Sets whether this node is long clickable.
   1912      * <p>
   1913      *   <strong>Note:</strong> Cannot be called from an
   1914      *   {@link android.accessibilityservice.AccessibilityService}.
   1915      *   This class is made immutable before being delivered to an AccessibilityService.
   1916      * </p>
   1917      *
   1918      * @param longClickable True if the node is long clickable.
   1919      *
   1920      * @throws IllegalStateException If called from an AccessibilityService.
   1921      */
   1922     public void setLongClickable(boolean longClickable) {
   1923         setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
   1924     }
   1925 
   1926     /**
   1927      * Gets whether this node is enabled.
   1928      *
   1929      * @return True if the node is enabled.
   1930      */
   1931     public boolean isEnabled() {
   1932         return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
   1933     }
   1934 
   1935     /**
   1936      * Sets whether this node is enabled.
   1937      * <p>
   1938      *   <strong>Note:</strong> Cannot be called from an
   1939      *   {@link android.accessibilityservice.AccessibilityService}.
   1940      *   This class is made immutable before being delivered to an AccessibilityService.
   1941      * </p>
   1942      *
   1943      * @param enabled True if the node is enabled.
   1944      *
   1945      * @throws IllegalStateException If called from an AccessibilityService.
   1946      */
   1947     public void setEnabled(boolean enabled) {
   1948         setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
   1949     }
   1950 
   1951     /**
   1952      * Gets whether this node is a password.
   1953      *
   1954      * @return True if the node is a password.
   1955      */
   1956     public boolean isPassword() {
   1957         return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
   1958     }
   1959 
   1960     /**
   1961      * Sets whether this node is a password.
   1962      * <p>
   1963      *   <strong>Note:</strong> Cannot be called from an
   1964      *   {@link android.accessibilityservice.AccessibilityService}.
   1965      *   This class is made immutable before being delivered to an AccessibilityService.
   1966      * </p>
   1967      *
   1968      * @param password True if the node is a password.
   1969      *
   1970      * @throws IllegalStateException If called from an AccessibilityService.
   1971      */
   1972     public void setPassword(boolean password) {
   1973         setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
   1974     }
   1975 
   1976     /**
   1977      * Gets if the node is scrollable.
   1978      *
   1979      * @return True if the node is scrollable, false otherwise.
   1980      */
   1981     public boolean isScrollable() {
   1982         return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
   1983     }
   1984 
   1985     /**
   1986      * Sets if the node is scrollable.
   1987      * <p>
   1988      *   <strong>Note:</strong> Cannot be called from an
   1989      *   {@link android.accessibilityservice.AccessibilityService}.
   1990      *   This class is made immutable before being delivered to an AccessibilityService.
   1991      * </p>
   1992      *
   1993      * @param scrollable True if the node is scrollable, false otherwise.
   1994      *
   1995      * @throws IllegalStateException If called from an AccessibilityService.
   1996      */
   1997     public void setScrollable(boolean scrollable) {
   1998         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
   1999     }
   2000 
   2001     /**
   2002      * Gets if the node is editable.
   2003      *
   2004      * @return True if the node is editable, false otherwise.
   2005      */
   2006     public boolean isEditable() {
   2007         return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
   2008     }
   2009 
   2010     /**
   2011      * Sets whether this node is editable.
   2012      * <p>
   2013      *   <strong>Note:</strong> Cannot be called from an
   2014      *   {@link android.accessibilityservice.AccessibilityService}.
   2015      *   This class is made immutable before being delivered to an AccessibilityService.
   2016      * </p>
   2017      *
   2018      * @param editable True if the node is editable.
   2019      *
   2020      * @throws IllegalStateException If called from an AccessibilityService.
   2021      */
   2022     public void setEditable(boolean editable) {
   2023         setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
   2024     }
   2025 
   2026     /**
   2027      * Get the drawing order of the view corresponding it this node.
   2028      * <p>
   2029      * Drawing order is determined only within the node's parent, so this index is only relative
   2030      * to its siblings.
   2031      * <p>
   2032      * In some cases, the drawing order is essentially simultaneous, so it is possible for two
   2033      * siblings to return the same value. It is also possible that values will be skipped.
   2034      *
   2035      * @return The drawing position of the view corresponding to this node relative to its siblings.
   2036      */
   2037     public int getDrawingOrder() {
   2038         return mDrawingOrderInParent;
   2039     }
   2040 
   2041     /**
   2042      * Set the drawing order of the view corresponding it this node.
   2043      *
   2044      * <p>
   2045      *   <strong>Note:</strong> Cannot be called from an
   2046      *   {@link android.accessibilityservice.AccessibilityService}.
   2047      *   This class is made immutable before being delivered to an AccessibilityService.
   2048      * </p>
   2049      * @param drawingOrderInParent
   2050      * @throws IllegalStateException If called from an AccessibilityService.
   2051      */
   2052     public void setDrawingOrder(int drawingOrderInParent) {
   2053         enforceNotSealed();
   2054         mDrawingOrderInParent = drawingOrderInParent;
   2055     }
   2056 
   2057     /**
   2058      * Gets the collection info if the node is a collection. A collection
   2059      * child is always a collection item.
   2060      *
   2061      * @return The collection info.
   2062      */
   2063     public CollectionInfo getCollectionInfo() {
   2064         return mCollectionInfo;
   2065     }
   2066 
   2067     /**
   2068      * Sets the collection info if the node is a collection. A collection
   2069      * child is always a collection item.
   2070      * <p>
   2071      *   <strong>Note:</strong> Cannot be called from an
   2072      *   {@link android.accessibilityservice.AccessibilityService}.
   2073      *   This class is made immutable before being delivered to an AccessibilityService.
   2074      * </p>
   2075      *
   2076      * @param collectionInfo The collection info.
   2077      */
   2078     public void setCollectionInfo(CollectionInfo collectionInfo) {
   2079         enforceNotSealed();
   2080         mCollectionInfo = collectionInfo;
   2081     }
   2082 
   2083     /**
   2084      * Gets the collection item info if the node is a collection item. A collection
   2085      * item is always a child of a collection.
   2086      *
   2087      * @return The collection item info.
   2088      */
   2089     public CollectionItemInfo getCollectionItemInfo() {
   2090         return mCollectionItemInfo;
   2091     }
   2092 
   2093     /**
   2094      * Sets the collection item info if the node is a collection item. A collection
   2095      * item is always a child of a collection.
   2096      * <p>
   2097      *   <strong>Note:</strong> Cannot be called from an
   2098      *   {@link android.accessibilityservice.AccessibilityService}.
   2099      *   This class is made immutable before being delivered to an AccessibilityService.
   2100      * </p>
   2101      */
   2102     public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
   2103         enforceNotSealed();
   2104         mCollectionItemInfo = collectionItemInfo;
   2105     }
   2106 
   2107     /**
   2108      * Gets the range info if this node is a range.
   2109      *
   2110      * @return The range.
   2111      */
   2112     public RangeInfo getRangeInfo() {
   2113         return mRangeInfo;
   2114     }
   2115 
   2116     /**
   2117      * Sets the range info if this node is a range.
   2118      * <p>
   2119      *   <strong>Note:</strong> Cannot be called from an
   2120      *   {@link android.accessibilityservice.AccessibilityService}.
   2121      *   This class is made immutable before being delivered to an AccessibilityService.
   2122      * </p>
   2123      *
   2124      * @param rangeInfo The range info.
   2125      */
   2126     public void setRangeInfo(RangeInfo rangeInfo) {
   2127         enforceNotSealed();
   2128         mRangeInfo = rangeInfo;
   2129     }
   2130 
   2131     /**
   2132      * Gets if the content of this node is invalid. For example,
   2133      * a date is not well-formed.
   2134      *
   2135      * @return If the node content is invalid.
   2136      */
   2137     public boolean isContentInvalid() {
   2138         return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
   2139     }
   2140 
   2141     /**
   2142      * Sets if the content of this node is invalid. For example,
   2143      * a date is not well-formed.
   2144      * <p>
   2145      *   <strong>Note:</strong> Cannot be called from an
   2146      *   {@link android.accessibilityservice.AccessibilityService}.
   2147      *   This class is made immutable before being delivered to an AccessibilityService.
   2148      * </p>
   2149      *
   2150      * @param contentInvalid If the node content is invalid.
   2151      */
   2152     public void setContentInvalid(boolean contentInvalid) {
   2153         setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
   2154     }
   2155 
   2156     /**
   2157      * Gets whether this node is context clickable.
   2158      *
   2159      * @return True if the node is context clickable.
   2160      */
   2161     public boolean isContextClickable() {
   2162         return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE);
   2163     }
   2164 
   2165     /**
   2166      * Sets whether this node is context clickable.
   2167      * <p>
   2168      * <strong>Note:</strong> Cannot be called from an
   2169      * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
   2170      * before being delivered to an AccessibilityService.
   2171      * </p>
   2172      *
   2173      * @param contextClickable True if the node is context clickable.
   2174      * @throws IllegalStateException If called from an AccessibilityService.
   2175      */
   2176     public void setContextClickable(boolean contextClickable) {
   2177         setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable);
   2178     }
   2179 
   2180     /**
   2181      * Gets the node's live region mode.
   2182      * <p>
   2183      * A live region is a node that contains information that is important for
   2184      * the user and when it changes the user should be notified. For example,
   2185      * in a login screen with a TextView that displays an "incorrect password"
   2186      * notification, that view should be marked as a live region with mode
   2187      * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
   2188      * <p>
   2189      * It is the responsibility of the accessibility service to monitor
   2190      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
   2191      * changes to live region nodes and their children.
   2192      *
   2193      * @return The live region mode, or
   2194      *         {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
   2195      *         live region.
   2196      * @see android.view.View#getAccessibilityLiveRegion()
   2197      */
   2198     public int getLiveRegion() {
   2199         return mLiveRegion;
   2200     }
   2201 
   2202     /**
   2203      * Sets the node's live region mode.
   2204      * <p>
   2205      * <strong>Note:</strong> Cannot be called from an
   2206      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2207      * made immutable before being delivered to an AccessibilityService.
   2208      *
   2209      * @param mode The live region mode, or
   2210      *        {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
   2211      *        live region.
   2212      * @see android.view.View#setAccessibilityLiveRegion(int)
   2213      */
   2214     public void setLiveRegion(int mode) {
   2215         enforceNotSealed();
   2216         mLiveRegion = mode;
   2217     }
   2218 
   2219     /**
   2220      * Gets if the node is a multi line editable text.
   2221      *
   2222      * @return True if the node is multi line.
   2223      */
   2224     public boolean isMultiLine() {
   2225         return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
   2226     }
   2227 
   2228     /**
   2229      * Sets if the node is a multi line editable text.
   2230      * <p>
   2231      *   <strong>Note:</strong> Cannot be called from an
   2232      *   {@link android.accessibilityservice.AccessibilityService}.
   2233      *   This class is made immutable before being delivered to an AccessibilityService.
   2234      * </p>
   2235      *
   2236      * @param multiLine True if the node is multi line.
   2237      */
   2238     public void setMultiLine(boolean multiLine) {
   2239         setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
   2240     }
   2241 
   2242     /**
   2243      * Gets if this node opens a popup or a dialog.
   2244      *
   2245      * @return If the the node opens a popup.
   2246      */
   2247     public boolean canOpenPopup() {
   2248         return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
   2249     }
   2250 
   2251     /**
   2252      * Sets if this node opens a popup or a dialog.
   2253      * <p>
   2254      *   <strong>Note:</strong> Cannot be called from an
   2255      *   {@link android.accessibilityservice.AccessibilityService}.
   2256      *   This class is made immutable before being delivered to an AccessibilityService.
   2257      * </p>
   2258      *
   2259      * @param opensPopup If the the node opens a popup.
   2260      */
   2261     public void setCanOpenPopup(boolean opensPopup) {
   2262         enforceNotSealed();
   2263         setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
   2264     }
   2265 
   2266     /**
   2267      * Gets if the node can be dismissed.
   2268      *
   2269      * @return If the node can be dismissed.
   2270      */
   2271     public boolean isDismissable() {
   2272         return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
   2273     }
   2274 
   2275     /**
   2276      * Sets if the node can be dismissed.
   2277      * <p>
   2278      *   <strong>Note:</strong> Cannot be called from an
   2279      *   {@link android.accessibilityservice.AccessibilityService}.
   2280      *   This class is made immutable before being delivered to an AccessibilityService.
   2281      * </p>
   2282      *
   2283      * @param dismissable If the node can be dismissed.
   2284      */
   2285     public void setDismissable(boolean dismissable) {
   2286         setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
   2287     }
   2288 
   2289     /**
   2290      * Returns whether the node originates from a view considered important for accessibility.
   2291      *
   2292      * @return {@code true} if the node originates from a view considered important for
   2293      *         accessibility, {@code false} otherwise
   2294      *
   2295      * @see View#isImportantForAccessibility()
   2296      */
   2297     public boolean isImportantForAccessibility() {
   2298         return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE);
   2299     }
   2300 
   2301     /**
   2302      * Sets whether the node is considered important for accessibility.
   2303      * <p>
   2304      *   <strong>Note:</strong> Cannot be called from an
   2305      *   {@link android.accessibilityservice.AccessibilityService}.
   2306      *   This class is made immutable before being delivered to an AccessibilityService.
   2307      * </p>
   2308      *
   2309      * @param important {@code true} if the node is considered important for accessibility,
   2310      *                  {@code false} otherwise
   2311      */
   2312     public void setImportantForAccessibility(boolean important) {
   2313         setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important);
   2314     }
   2315 
   2316     /**
   2317      * Returns whether the node's text represents a hint for the user to enter text. It should only
   2318      * be {@code true} if the node has editable text.
   2319      *
   2320      * @return {@code true} if the text in the node represents a hint to the user, {@code false}
   2321      * otherwise.
   2322      */
   2323     public boolean isShowingHintText() {
   2324         return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
   2325     }
   2326 
   2327     /**
   2328      * Sets whether the node's text represents a hint for the user to enter text. It should only
   2329      * be {@code true} if the node has editable text.
   2330      * <p>
   2331      *   <strong>Note:</strong> Cannot be called from an
   2332      *   {@link android.accessibilityservice.AccessibilityService}.
   2333      *   This class is made immutable before being delivered to an AccessibilityService.
   2334      * </p>
   2335      *
   2336      * @param showingHintText {@code true} if the text in the node represents a hint to the user,
   2337      * {@code false} otherwise.
   2338      */
   2339     public void setShowingHintText(boolean showingHintText) {
   2340         setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
   2341     }
   2342 
   2343     /**
   2344      * Gets the package this node comes from.
   2345      *
   2346      * @return The package name.
   2347      */
   2348     public CharSequence getPackageName() {
   2349         return mPackageName;
   2350     }
   2351 
   2352     /**
   2353      * Sets the package this node comes from.
   2354      * <p>
   2355      *   <strong>Note:</strong> Cannot be called from an
   2356      *   {@link android.accessibilityservice.AccessibilityService}.
   2357      *   This class is made immutable before being delivered to an AccessibilityService.
   2358      * </p>
   2359      *
   2360      * @param packageName The package name.
   2361      *
   2362      * @throws IllegalStateException If called from an AccessibilityService.
   2363      */
   2364     public void setPackageName(CharSequence packageName) {
   2365         enforceNotSealed();
   2366         mPackageName = packageName;
   2367     }
   2368 
   2369     /**
   2370      * Gets the class this node comes from.
   2371      *
   2372      * @return The class name.
   2373      */
   2374     public CharSequence getClassName() {
   2375         return mClassName;
   2376     }
   2377 
   2378     /**
   2379      * Sets the class this node comes from.
   2380      * <p>
   2381      *   <strong>Note:</strong> Cannot be called from an
   2382      *   {@link android.accessibilityservice.AccessibilityService}.
   2383      *   This class is made immutable before being delivered to an AccessibilityService.
   2384      * </p>
   2385      *
   2386      * @param className The class name.
   2387      *
   2388      * @throws IllegalStateException If called from an AccessibilityService.
   2389      */
   2390     public void setClassName(CharSequence className) {
   2391         enforceNotSealed();
   2392         mClassName = className;
   2393     }
   2394 
   2395     /**
   2396      * Gets the text of this node.
   2397      * <p>
   2398      *   <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s,
   2399      *   these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)}
   2400      *   can be called from an {@link AccessibilityService}. When called from a service, the
   2401      *   {@link View} argument is ignored and the corresponding span will be found on the view that
   2402      *   this {@code AccessibilityNodeInfo} represents and called with that view as its argument.
   2403      *   <p>
   2404      *   This treatment of {@link ClickableSpan}s means that the text returned from this method may
   2405      *   different slightly one passed to {@link #setText(CharSequence)}, although they will be
   2406      *   equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The
   2407      *   {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside
   2408      *   of an accessibility service.
   2409      * </p>
   2410      *
   2411      * @return The text.
   2412      */
   2413     public CharSequence getText() {
   2414         // Attach this node to any spans that need it
   2415         if (mText instanceof Spanned) {
   2416             Spanned spanned = (Spanned) mText;
   2417             AccessibilityClickableSpan[] clickableSpans =
   2418                     spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class);
   2419             for (int i = 0; i < clickableSpans.length; i++) {
   2420                 clickableSpans[i].copyConnectionDataFrom(this);
   2421             }
   2422             AccessibilityURLSpan[] urlSpans =
   2423                     spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class);
   2424             for (int i = 0; i < urlSpans.length; i++) {
   2425                 urlSpans[i].copyConnectionDataFrom(this);
   2426             }
   2427         }
   2428         return mText;
   2429     }
   2430 
   2431     /**
   2432      * Get the text passed to setText before any changes to the spans.
   2433      * @hide
   2434      */
   2435     public CharSequence getOriginalText() {
   2436         return mOriginalText;
   2437     }
   2438 
   2439     /**
   2440      * Sets the text of this node.
   2441      * <p>
   2442      *   <strong>Note:</strong> Cannot be called from an
   2443      *   {@link android.accessibilityservice.AccessibilityService}.
   2444      *   This class is made immutable before being delivered to an AccessibilityService.
   2445      * </p>
   2446      *
   2447      * @param text The text.
   2448      *
   2449      * @throws IllegalStateException If called from an AccessibilityService.
   2450      */
   2451     public void setText(CharSequence text) {
   2452         enforceNotSealed();
   2453         mOriginalText = text;
   2454         // Replace any ClickableSpans in mText with placeholders
   2455         if (text instanceof Spanned) {
   2456             ClickableSpan[] spans =
   2457                     ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
   2458             if (spans.length > 0) {
   2459                 Spannable spannable = new SpannableStringBuilder(text);
   2460                 for (int i = 0; i < spans.length; i++) {
   2461                     ClickableSpan span = spans[i];
   2462                     if ((span instanceof AccessibilityClickableSpan)
   2463                             || (span instanceof AccessibilityURLSpan)) {
   2464                         // We've already done enough
   2465                         break;
   2466                     }
   2467                     int spanToReplaceStart = spannable.getSpanStart(span);
   2468                     int spanToReplaceEnd = spannable.getSpanEnd(span);
   2469                     int spanToReplaceFlags = spannable.getSpanFlags(span);
   2470                     spannable.removeSpan(span);
   2471                     ClickableSpan replacementSpan = (span instanceof URLSpan)
   2472                             ? new AccessibilityURLSpan((URLSpan) span)
   2473                             : new AccessibilityClickableSpan(span.getId());
   2474                     spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
   2475                             spanToReplaceFlags);
   2476                 }
   2477                 mText = spannable;
   2478                 return;
   2479             }
   2480         }
   2481         mText = (text == null) ? null : text.subSequence(0, text.length());
   2482     }
   2483 
   2484     /**
   2485      * Gets the hint text of this node. Only applies to nodes where text can be entered.
   2486      *
   2487      * @return The hint text.
   2488      */
   2489     public CharSequence getHintText() {
   2490         return mHintText;
   2491     }
   2492 
   2493     /**
   2494      * Sets the hint text of this node. Only applies to nodes where text can be entered.
   2495      * <p>
   2496      *   <strong>Note:</strong> Cannot be called from an
   2497      *   {@link android.accessibilityservice.AccessibilityService}.
   2498      *   This class is made immutable before being delivered to an AccessibilityService.
   2499      * </p>
   2500      *
   2501      * @param hintText The hint text for this mode.
   2502      *
   2503      * @throws IllegalStateException If called from an AccessibilityService.
   2504      */
   2505     public void setHintText(CharSequence hintText) {
   2506         enforceNotSealed();
   2507         mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length());
   2508     }
   2509 
   2510     /**
   2511      * Sets the error text of this node.
   2512      * <p>
   2513      *   <strong>Note:</strong> Cannot be called from an
   2514      *   {@link android.accessibilityservice.AccessibilityService}.
   2515      *   This class is made immutable before being delivered to an AccessibilityService.
   2516      * </p>
   2517      *
   2518      * @param error The error text.
   2519      *
   2520      * @throws IllegalStateException If called from an AccessibilityService.
   2521      */
   2522     public void setError(CharSequence error) {
   2523         enforceNotSealed();
   2524         mError = (error == null) ? null : error.subSequence(0, error.length());
   2525     }
   2526 
   2527     /**
   2528      * Gets the error text of this node.
   2529      *
   2530      * @return The error text.
   2531      */
   2532     public CharSequence getError() {
   2533         return mError;
   2534     }
   2535 
   2536     /**
   2537      * Gets the content description of this node.
   2538      *
   2539      * @return The content description.
   2540      */
   2541     public CharSequence getContentDescription() {
   2542         return mContentDescription;
   2543     }
   2544 
   2545     /**
   2546      * Sets the content description of this node.
   2547      * <p>
   2548      *   <strong>Note:</strong> Cannot be called from an
   2549      *   {@link android.accessibilityservice.AccessibilityService}.
   2550      *   This class is made immutable before being delivered to an AccessibilityService.
   2551      * </p>
   2552      *
   2553      * @param contentDescription The content description.
   2554      *
   2555      * @throws IllegalStateException If called from an AccessibilityService.
   2556      */
   2557     public void setContentDescription(CharSequence contentDescription) {
   2558         enforceNotSealed();
   2559         mContentDescription = (contentDescription == null) ? null
   2560                 : contentDescription.subSequence(0, contentDescription.length());
   2561     }
   2562 
   2563     /**
   2564      * Sets the view for which the view represented by this info serves as a
   2565      * label for accessibility purposes.
   2566      *
   2567      * @param labeled The view for which this info serves as a label.
   2568      */
   2569     public void setLabelFor(View labeled) {
   2570         setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID);
   2571     }
   2572 
   2573     /**
   2574      * Sets the view for which the view represented by this info serves as a
   2575      * label for accessibility purposes. If <code>virtualDescendantId</code>
   2576      * is {@link View#NO_ID} the root is set as the labeled.
   2577      * <p>
   2578      * A virtual descendant is an imaginary View that is reported as a part of the view
   2579      * hierarchy for accessibility purposes. This enables custom views that draw complex
   2580      * content to report themselves as a tree of virtual views, thus conveying their
   2581      * logical structure.
   2582      * </p>
   2583      * <p>
   2584      *   <strong>Note:</strong> Cannot be called from an
   2585      *   {@link android.accessibilityservice.AccessibilityService}.
   2586      *   This class is made immutable before being delivered to an AccessibilityService.
   2587      * </p>
   2588      *
   2589      * @param root The root whose virtual descendant serves as a label.
   2590      * @param virtualDescendantId The id of the virtual descendant.
   2591      */
   2592     public void setLabelFor(View root, int virtualDescendantId) {
   2593         enforceNotSealed();
   2594         final int rootAccessibilityViewId = (root != null)
   2595                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   2596         mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   2597     }
   2598 
   2599     /**
   2600      * Gets the node info for which the view represented by this info serves as
   2601      * a label for accessibility purposes.
   2602      * <p>
   2603      *   <strong>Note:</strong> It is a client responsibility to recycle the
   2604      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   2605      *     to avoid creating of multiple instances.
   2606      * </p>
   2607      *
   2608      * @return The labeled info.
   2609      */
   2610     public AccessibilityNodeInfo getLabelFor() {
   2611         enforceSealed();
   2612         return getNodeForAccessibilityId(mLabelForId);
   2613     }
   2614 
   2615     /**
   2616      * Sets the view which serves as the label of the view represented by
   2617      * this info for accessibility purposes.
   2618      *
   2619      * @param label The view that labels this node's source.
   2620      */
   2621     public void setLabeledBy(View label) {
   2622         setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID);
   2623     }
   2624 
   2625     /**
   2626      * Sets the view which serves as the label of the view represented by
   2627      * this info for accessibility purposes. If <code>virtualDescendantId</code>
   2628      * is {@link View#NO_ID} the root is set as the label.
   2629      * <p>
   2630      * A virtual descendant is an imaginary View that is reported as a part of the view
   2631      * hierarchy for accessibility purposes. This enables custom views that draw complex
   2632      * content to report themselves as a tree of virtual views, thus conveying their
   2633      * logical structure.
   2634      * </p>
   2635      * <p>
   2636      *   <strong>Note:</strong> Cannot be called from an
   2637      *   {@link android.accessibilityservice.AccessibilityService}.
   2638      *   This class is made immutable before being delivered to an AccessibilityService.
   2639      * </p>
   2640      *
   2641      * @param root The root whose virtual descendant labels this node's source.
   2642      * @param virtualDescendantId The id of the virtual descendant.
   2643      */
   2644     public void setLabeledBy(View root, int virtualDescendantId) {
   2645         enforceNotSealed();
   2646         final int rootAccessibilityViewId = (root != null)
   2647                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
   2648         mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   2649     }
   2650 
   2651     /**
   2652      * Gets the node info which serves as the label of the view represented by
   2653      * this info for accessibility purposes.
   2654      * <p>
   2655      *   <strong>Note:</strong> It is a client responsibility to recycle the
   2656      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   2657      *     to avoid creating of multiple instances.
   2658      * </p>
   2659      *
   2660      * @return The label.
   2661      */
   2662     public AccessibilityNodeInfo getLabeledBy() {
   2663         enforceSealed();
   2664         return getNodeForAccessibilityId(mLabeledById);
   2665     }
   2666 
   2667     /**
   2668      * Sets the fully qualified resource name of the source view's id.
   2669      *
   2670      * <p>
   2671      *   <strong>Note:</strong> Cannot be called from an
   2672      *   {@link android.accessibilityservice.AccessibilityService}.
   2673      *   This class is made immutable before being delivered to an AccessibilityService.
   2674      * </p>
   2675      *
   2676      * @param viewIdResName The id resource name.
   2677      */
   2678     public void setViewIdResourceName(String viewIdResName) {
   2679         enforceNotSealed();
   2680         mViewIdResourceName = viewIdResName;
   2681     }
   2682 
   2683     /**
   2684      * Gets the fully qualified resource name of the source view's id.
   2685      *
   2686      * <p>
   2687      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   2688      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
   2689      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
   2690      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   2691      * </p>
   2692 
   2693      * @return The id resource name.
   2694      */
   2695     public String getViewIdResourceName() {
   2696         return mViewIdResourceName;
   2697     }
   2698 
   2699     /**
   2700      * Gets the text selection start or the cursor position.
   2701      * <p>
   2702      * If no text is selected, both this method and
   2703      * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
   2704      * the current location of the cursor.
   2705      * </p>
   2706      *
   2707      * @return The text selection start, the cursor location if there is no selection, or -1 if
   2708      *         there is no text selection and no cursor.
   2709      */
   2710     public int getTextSelectionStart() {
   2711         return mTextSelectionStart;
   2712     }
   2713 
   2714     /**
   2715      * Gets the text selection end if text is selected.
   2716      * <p>
   2717      * If no text is selected, both this method and
   2718      * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
   2719      * the current location of the cursor.
   2720      * </p>
   2721      *
   2722      * @return The text selection end, the cursor location if there is no selection, or -1 if
   2723      *         there is no text selection and no cursor.
   2724      */
   2725     public int getTextSelectionEnd() {
   2726         return mTextSelectionEnd;
   2727     }
   2728 
   2729     /**
   2730      * Sets the text selection start and end.
   2731      * <p>
   2732      *   <strong>Note:</strong> Cannot be called from an
   2733      *   {@link android.accessibilityservice.AccessibilityService}.
   2734      *   This class is made immutable before being delivered to an AccessibilityService.
   2735      * </p>
   2736      *
   2737      * @param start The text selection start.
   2738      * @param end The text selection end.
   2739      *
   2740      * @throws IllegalStateException If called from an AccessibilityService.
   2741      */
   2742     public void setTextSelection(int start, int end) {
   2743         enforceNotSealed();
   2744         mTextSelectionStart = start;
   2745         mTextSelectionEnd = end;
   2746     }
   2747 
   2748     /**
   2749      * Gets the input type of the source as defined by {@link InputType}.
   2750      *
   2751      * @return The input type.
   2752      */
   2753     public int getInputType() {
   2754         return mInputType;
   2755     }
   2756 
   2757     /**
   2758      * Sets the input type of the source as defined by {@link InputType}.
   2759      * <p>
   2760      *   <strong>Note:</strong> Cannot be called from an
   2761      *   {@link android.accessibilityservice.AccessibilityService}.
   2762      *   This class is made immutable before being delivered to an
   2763      *   AccessibilityService.
   2764      * </p>
   2765      *
   2766      * @param inputType The input type.
   2767      *
   2768      * @throws IllegalStateException If called from an AccessibilityService.
   2769      */
   2770     public void setInputType(int inputType) {
   2771         enforceNotSealed();
   2772         mInputType = inputType;
   2773     }
   2774 
   2775     /**
   2776      * Gets an optional bundle with extra data. The bundle
   2777      * is lazily created and never <code>null</code>.
   2778      * <p>
   2779      * <strong>Note:</strong> It is recommended to use the package
   2780      * name of your application as a prefix for the keys to avoid
   2781      * collisions which may confuse an accessibility service if the
   2782      * same key has different meaning when emitted from different
   2783      * applications.
   2784      * </p>
   2785      *
   2786      * @return The bundle.
   2787      */
   2788     public Bundle getExtras() {
   2789         if (mExtras == null) {
   2790             mExtras = new Bundle();
   2791         }
   2792         return mExtras;
   2793     }
   2794 
   2795     /**
   2796      * Check if a node has an extras bundle
   2797      * @hide
   2798      */
   2799     public boolean hasExtras() {
   2800         return mExtras != null;
   2801     }
   2802 
   2803     /**
   2804      * Gets the value of a boolean property.
   2805      *
   2806      * @param property The property.
   2807      * @return The value.
   2808      */
   2809     private boolean getBooleanProperty(int property) {
   2810         return (mBooleanProperties & property) != 0;
   2811     }
   2812 
   2813     /**
   2814      * Sets a boolean property.
   2815      *
   2816      * @param property The property.
   2817      * @param value The value.
   2818      *
   2819      * @throws IllegalStateException If called from an AccessibilityService.
   2820      */
   2821     private void setBooleanProperty(int property, boolean value) {
   2822         enforceNotSealed();
   2823         if (value) {
   2824             mBooleanProperties |= property;
   2825         } else {
   2826             mBooleanProperties &= ~property;
   2827         }
   2828     }
   2829 
   2830     /**
   2831      * Sets the unique id of the IAccessibilityServiceConnection over which
   2832      * this instance can send requests to the system.
   2833      *
   2834      * @param connectionId The connection id.
   2835      *
   2836      * @hide
   2837      */
   2838     public void setConnectionId(int connectionId) {
   2839         enforceNotSealed();
   2840         mConnectionId = connectionId;
   2841     }
   2842 
   2843     /**
   2844      * Get the connection ID.
   2845      *
   2846      * @return The connection id
   2847      *
   2848      * @hide
   2849      */
   2850     public int getConnectionId() {
   2851         return mConnectionId;
   2852     }
   2853 
   2854     /**
   2855      * {@inheritDoc}
   2856      */
   2857     @Override
   2858     public int describeContents() {
   2859         return 0;
   2860     }
   2861 
   2862     /**
   2863      * Sets the id of the source node.
   2864      *
   2865      * @param sourceId The id.
   2866      * @param windowId The window id.
   2867      *
   2868      * @hide
   2869      */
   2870     public void setSourceNodeId(long sourceId, int windowId) {
   2871         enforceNotSealed();
   2872         mSourceNodeId = sourceId;
   2873         mWindowId = windowId;
   2874     }
   2875 
   2876     /**
   2877      * Gets the id of the source node.
   2878      *
   2879      * @return The id.
   2880      *
   2881      * @hide
   2882      */
   2883     public long getSourceNodeId() {
   2884         return mSourceNodeId;
   2885     }
   2886 
   2887     /**
   2888      * Sets if this instance is sealed.
   2889      *
   2890      * @param sealed Whether is sealed.
   2891      *
   2892      * @hide
   2893      */
   2894     public void setSealed(boolean sealed) {
   2895         mSealed = sealed;
   2896     }
   2897 
   2898     /**
   2899      * Gets if this instance is sealed.
   2900      *
   2901      * @return Whether is sealed.
   2902      *
   2903      * @hide
   2904      */
   2905     public boolean isSealed() {
   2906         return mSealed;
   2907     }
   2908 
   2909     /**
   2910      * Enforces that this instance is sealed.
   2911      *
   2912      * @throws IllegalStateException If this instance is not sealed.
   2913      *
   2914      * @hide
   2915      */
   2916     protected void enforceSealed() {
   2917         if (!isSealed()) {
   2918             throw new IllegalStateException("Cannot perform this "
   2919                     + "action on a not sealed instance.");
   2920         }
   2921     }
   2922 
   2923     private void enforceValidFocusDirection(int direction) {
   2924         switch (direction) {
   2925             case View.FOCUS_DOWN:
   2926             case View.FOCUS_UP:
   2927             case View.FOCUS_LEFT:
   2928             case View.FOCUS_RIGHT:
   2929             case View.FOCUS_FORWARD:
   2930             case View.FOCUS_BACKWARD:
   2931                 return;
   2932             default:
   2933                 throw new IllegalArgumentException("Unknown direction: " + direction);
   2934         }
   2935     }
   2936 
   2937     private void enforceValidFocusType(int focusType) {
   2938         switch (focusType) {
   2939             case FOCUS_INPUT:
   2940             case FOCUS_ACCESSIBILITY:
   2941                 return;
   2942             default:
   2943                 throw new IllegalArgumentException("Unknown focus type: " + focusType);
   2944         }
   2945     }
   2946 
   2947     /**
   2948      * Enforces that this instance is not sealed.
   2949      *
   2950      * @throws IllegalStateException If this instance is sealed.
   2951      *
   2952      * @hide
   2953      */
   2954     protected void enforceNotSealed() {
   2955         if (isSealed()) {
   2956             throw new IllegalStateException("Cannot perform this "
   2957                     + "action on a sealed instance.");
   2958         }
   2959     }
   2960 
   2961     /**
   2962      * Returns a cached instance if such is available otherwise a new one
   2963      * and sets the source.
   2964      *
   2965      * @param source The source view.
   2966      * @return An instance.
   2967      *
   2968      * @see #setSource(View)
   2969      */
   2970     public static AccessibilityNodeInfo obtain(View source) {
   2971         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2972         info.setSource(source);
   2973         return info;
   2974     }
   2975 
   2976     /**
   2977      * Returns a cached instance if such is available otherwise a new one
   2978      * and sets the source.
   2979      *
   2980      * @param root The root of the virtual subtree.
   2981      * @param virtualDescendantId The id of the virtual descendant.
   2982      * @return An instance.
   2983      *
   2984      * @see #setSource(View, int)
   2985      */
   2986     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
   2987         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2988         info.setSource(root, virtualDescendantId);
   2989         return info;
   2990     }
   2991 
   2992     /**
   2993      * Returns a cached instance if such is available otherwise a new one.
   2994      *
   2995      * @return An instance.
   2996      */
   2997     public static AccessibilityNodeInfo obtain() {
   2998         AccessibilityNodeInfo info = sPool.acquire();
   2999         if (sNumInstancesInUse != null) {
   3000             sNumInstancesInUse.incrementAndGet();
   3001         }
   3002         return (info != null) ? info : new AccessibilityNodeInfo();
   3003     }
   3004 
   3005     /**
   3006      * Returns a cached instance if such is available or a new one is
   3007      * create. The returned instance is initialized from the given
   3008      * <code>info</code>.
   3009      *
   3010      * @param info The other info.
   3011      * @return An instance.
   3012      */
   3013     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
   3014         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
   3015         infoClone.init(info);
   3016         return infoClone;
   3017     }
   3018 
   3019     /**
   3020      * Return an instance back to be reused.
   3021      * <p>
   3022      * <strong>Note:</strong> You must not touch the object after calling this function.
   3023      *
   3024      * @throws IllegalStateException If the info is already recycled.
   3025      */
   3026     public void recycle() {
   3027         clear();
   3028         sPool.release(this);
   3029         if (sNumInstancesInUse != null) {
   3030             sNumInstancesInUse.decrementAndGet();
   3031         }
   3032     }
   3033 
   3034     /**
   3035      * Specify a counter that will be incremented on obtain() and decremented on recycle()
   3036      *
   3037      * @hide
   3038      */
   3039     @TestApi
   3040     public static void setNumInstancesInUseCounter(AtomicInteger counter) {
   3041         sNumInstancesInUse = counter;
   3042     }
   3043 
   3044     /**
   3045      * {@inheritDoc}
   3046      * <p>
   3047      *   <strong>Note:</strong> After the instance is written to a parcel it
   3048      *      is recycled. You must not touch the object after calling this function.
   3049      * </p>
   3050      */
   3051     @Override
   3052     public void writeToParcel(Parcel parcel, int flags) {
   3053         parcel.writeInt(isSealed() ? 1 : 0);
   3054         parcel.writeLong(mSourceNodeId);
   3055         parcel.writeInt(mWindowId);
   3056         parcel.writeLong(mParentNodeId);
   3057         parcel.writeLong(mLabelForId);
   3058         parcel.writeLong(mLabeledById);
   3059         parcel.writeLong(mTraversalBefore);
   3060         parcel.writeLong(mTraversalAfter);
   3061 
   3062         parcel.writeInt(mConnectionId);
   3063 
   3064         final LongArray childIds = mChildNodeIds;
   3065         if (childIds == null) {
   3066             parcel.writeInt(0);
   3067         } else {
   3068             final int childIdsSize = childIds.size();
   3069             parcel.writeInt(childIdsSize);
   3070             for (int i = 0; i < childIdsSize; i++) {
   3071                 parcel.writeLong(childIds.get(i));
   3072             }
   3073         }
   3074 
   3075         parcel.writeInt(mBoundsInParent.top);
   3076         parcel.writeInt(mBoundsInParent.bottom);
   3077         parcel.writeInt(mBoundsInParent.left);
   3078         parcel.writeInt(mBoundsInParent.right);
   3079 
   3080         parcel.writeInt(mBoundsInScreen.top);
   3081         parcel.writeInt(mBoundsInScreen.bottom);
   3082         parcel.writeInt(mBoundsInScreen.left);
   3083         parcel.writeInt(mBoundsInScreen.right);
   3084 
   3085         if (mActions != null && !mActions.isEmpty()) {
   3086             final int actionCount = mActions.size();
   3087 
   3088             int nonLegacyActionCount = 0;
   3089             int defaultLegacyStandardActions = 0;
   3090             for (int i = 0; i < actionCount; i++) {
   3091                 AccessibilityAction action = mActions.get(i);
   3092                 if (isDefaultLegacyStandardAction(action)) {
   3093                     defaultLegacyStandardActions |= action.getId();
   3094                 } else {
   3095                     nonLegacyActionCount++;
   3096                 }
   3097             }
   3098             parcel.writeInt(defaultLegacyStandardActions);
   3099             parcel.writeInt(nonLegacyActionCount);
   3100 
   3101             for (int i = 0; i < actionCount; i++) {
   3102                 AccessibilityAction action = mActions.get(i);
   3103                 if (!isDefaultLegacyStandardAction(action)) {
   3104                     parcel.writeInt(action.getId());
   3105                     parcel.writeCharSequence(action.getLabel());
   3106                 }
   3107             }
   3108         } else {
   3109             parcel.writeInt(0);
   3110             parcel.writeInt(0);
   3111         }
   3112 
   3113         parcel.writeInt(mMaxTextLength);
   3114         parcel.writeInt(mMovementGranularities);
   3115         parcel.writeInt(mBooleanProperties);
   3116 
   3117         parcel.writeCharSequence(mPackageName);
   3118         parcel.writeCharSequence(mClassName);
   3119         parcel.writeCharSequence(mText);
   3120         parcel.writeCharSequence(mHintText);
   3121         parcel.writeCharSequence(mError);
   3122         parcel.writeCharSequence(mContentDescription);
   3123         parcel.writeString(mViewIdResourceName);
   3124 
   3125         parcel.writeInt(mTextSelectionStart);
   3126         parcel.writeInt(mTextSelectionEnd);
   3127         parcel.writeInt(mInputType);
   3128         parcel.writeInt(mLiveRegion);
   3129         parcel.writeInt(mDrawingOrderInParent);
   3130         if (mExtraDataKeys != null) {
   3131             parcel.writeInt(1);
   3132             parcel.writeStringList(mExtraDataKeys);
   3133         } else {
   3134             parcel.writeInt(0);
   3135         }
   3136 
   3137         if (mExtras != null) {
   3138             parcel.writeInt(1);
   3139             parcel.writeBundle(mExtras);
   3140         } else {
   3141             parcel.writeInt(0);
   3142         }
   3143 
   3144         if (mRangeInfo != null) {
   3145             parcel.writeInt(1);
   3146             parcel.writeInt(mRangeInfo.getType());
   3147             parcel.writeFloat(mRangeInfo.getMin());
   3148             parcel.writeFloat(mRangeInfo.getMax());
   3149             parcel.writeFloat(mRangeInfo.getCurrent());
   3150         } else {
   3151             parcel.writeInt(0);
   3152         }
   3153 
   3154         if (mCollectionInfo != null) {
   3155             parcel.writeInt(1);
   3156             parcel.writeInt(mCollectionInfo.getRowCount());
   3157             parcel.writeInt(mCollectionInfo.getColumnCount());
   3158             parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
   3159             parcel.writeInt(mCollectionInfo.getSelectionMode());
   3160         } else {
   3161             parcel.writeInt(0);
   3162         }
   3163 
   3164         if (mCollectionItemInfo != null) {
   3165             parcel.writeInt(1);
   3166             parcel.writeInt(mCollectionItemInfo.getRowIndex());
   3167             parcel.writeInt(mCollectionItemInfo.getRowSpan());
   3168             parcel.writeInt(mCollectionItemInfo.getColumnIndex());
   3169             parcel.writeInt(mCollectionItemInfo.getColumnSpan());
   3170             parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
   3171             parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
   3172         } else {
   3173             parcel.writeInt(0);
   3174         }
   3175 
   3176         // Since instances of this class are fetched via synchronous i.e. blocking
   3177         // calls in IPCs we always recycle as soon as the instance is marshaled.
   3178         recycle();
   3179     }
   3180 
   3181     /**
   3182      * Initializes this instance from another one.
   3183      *
   3184      * @param other The other instance.
   3185      */
   3186     private void init(AccessibilityNodeInfo other) {
   3187         mSealed = other.mSealed;
   3188         mSourceNodeId = other.mSourceNodeId;
   3189         mParentNodeId = other.mParentNodeId;
   3190         mLabelForId = other.mLabelForId;
   3191         mLabeledById = other.mLabeledById;
   3192         mTraversalBefore = other.mTraversalBefore;
   3193         mTraversalAfter = other.mTraversalAfter;
   3194         mWindowId = other.mWindowId;
   3195         mConnectionId = other.mConnectionId;
   3196         mBoundsInParent.set(other.mBoundsInParent);
   3197         mBoundsInScreen.set(other.mBoundsInScreen);
   3198         mPackageName = other.mPackageName;
   3199         mClassName = other.mClassName;
   3200         mText = other.mText;
   3201         mHintText = other.mHintText;
   3202         mError = other.mError;
   3203         mContentDescription = other.mContentDescription;
   3204         mViewIdResourceName = other.mViewIdResourceName;
   3205 
   3206         final ArrayList<AccessibilityAction> otherActions = other.mActions;
   3207         if (otherActions != null && otherActions.size() > 0) {
   3208             if (mActions == null) {
   3209                 mActions = new ArrayList(otherActions);
   3210             } else {
   3211                 mActions.clear();
   3212                 mActions.addAll(other.mActions);
   3213             }
   3214         }
   3215 
   3216         mBooleanProperties = other.mBooleanProperties;
   3217         mMaxTextLength = other.mMaxTextLength;
   3218         mMovementGranularities = other.mMovementGranularities;
   3219 
   3220         final LongArray otherChildNodeIds = other.mChildNodeIds;
   3221         if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
   3222             if (mChildNodeIds == null) {
   3223                 mChildNodeIds = otherChildNodeIds.clone();
   3224             } else {
   3225                 mChildNodeIds.clear();
   3226                 mChildNodeIds.addAll(otherChildNodeIds);
   3227             }
   3228         }
   3229 
   3230         mTextSelectionStart = other.mTextSelectionStart;
   3231         mTextSelectionEnd = other.mTextSelectionEnd;
   3232         mInputType = other.mInputType;
   3233         mLiveRegion = other.mLiveRegion;
   3234         mDrawingOrderInParent = other.mDrawingOrderInParent;
   3235         mExtraDataKeys = other.mExtraDataKeys;
   3236 
   3237         if (other.mExtras != null) {
   3238             mExtras = new Bundle(other.mExtras);
   3239         } else {
   3240             mExtras = null;
   3241         }
   3242         mRangeInfo = (other.mRangeInfo != null)
   3243                 ? RangeInfo.obtain(other.mRangeInfo) : null;
   3244         mCollectionInfo = (other.mCollectionInfo != null)
   3245                 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
   3246         mCollectionItemInfo =  (other.mCollectionItemInfo != null)
   3247                 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
   3248     }
   3249 
   3250     /**
   3251      * Creates a new instance from a {@link Parcel}.
   3252      *
   3253      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
   3254      */
   3255     private void initFromParcel(Parcel parcel) {
   3256         final boolean sealed = (parcel.readInt()  == 1);
   3257         mSourceNodeId = parcel.readLong();
   3258         mWindowId = parcel.readInt();
   3259         mParentNodeId = parcel.readLong();
   3260         mLabelForId = parcel.readLong();
   3261         mLabeledById = parcel.readLong();
   3262         mTraversalBefore = parcel.readLong();
   3263         mTraversalAfter = parcel.readLong();
   3264 
   3265         mConnectionId = parcel.readInt();
   3266 
   3267         final int childrenSize = parcel.readInt();
   3268         if (childrenSize <= 0) {
   3269             mChildNodeIds = null;
   3270         } else {
   3271             mChildNodeIds = new LongArray(childrenSize);
   3272             for (int i = 0; i < childrenSize; i++) {
   3273                 final long childId = parcel.readLong();
   3274                 mChildNodeIds.add(childId);
   3275             }
   3276         }
   3277 
   3278         mBoundsInParent.top = parcel.readInt();
   3279         mBoundsInParent.bottom = parcel.readInt();
   3280         mBoundsInParent.left = parcel.readInt();
   3281         mBoundsInParent.right = parcel.readInt();
   3282 
   3283         mBoundsInScreen.top = parcel.readInt();
   3284         mBoundsInScreen.bottom = parcel.readInt();
   3285         mBoundsInScreen.left = parcel.readInt();
   3286         mBoundsInScreen.right = parcel.readInt();
   3287 
   3288         final int legacyStandardActions = parcel.readInt();
   3289         addLegacyStandardActions(legacyStandardActions);
   3290         final int nonLegacyActionCount = parcel.readInt();
   3291         for (int i = 0; i < nonLegacyActionCount; i++) {
   3292             final AccessibilityAction action = new AccessibilityAction(
   3293                     parcel.readInt(), parcel.readCharSequence());
   3294             addActionUnchecked(action);
   3295         }
   3296 
   3297         mMaxTextLength = parcel.readInt();
   3298         mMovementGranularities = parcel.readInt();
   3299         mBooleanProperties = parcel.readInt();
   3300 
   3301         mPackageName = parcel.readCharSequence();
   3302         mClassName = parcel.readCharSequence();
   3303         mText = parcel.readCharSequence();
   3304         mHintText = parcel.readCharSequence();
   3305         mError = parcel.readCharSequence();
   3306         mContentDescription = parcel.readCharSequence();
   3307         mViewIdResourceName = parcel.readString();
   3308 
   3309         mTextSelectionStart = parcel.readInt();
   3310         mTextSelectionEnd = parcel.readInt();
   3311 
   3312         mInputType = parcel.readInt();
   3313         mLiveRegion = parcel.readInt();
   3314         mDrawingOrderInParent = parcel.readInt();
   3315 
   3316         if (parcel.readInt() == 1) {
   3317             mExtraDataKeys = parcel.createStringArrayList();
   3318         } else {
   3319             mExtraDataKeys = null;
   3320         }
   3321 
   3322         if (parcel.readInt() == 1) {
   3323             mExtras = parcel.readBundle();
   3324         } else {
   3325             mExtras = null;
   3326         }
   3327 
   3328         if (parcel.readInt() == 1) {
   3329             mRangeInfo = RangeInfo.obtain(
   3330                     parcel.readInt(),
   3331                     parcel.readFloat(),
   3332                     parcel.readFloat(),
   3333                     parcel.readFloat());
   3334         }
   3335 
   3336         if (parcel.readInt() == 1) {
   3337             mCollectionInfo = CollectionInfo.obtain(
   3338                     parcel.readInt(),
   3339                     parcel.readInt(),
   3340                     parcel.readInt() == 1,
   3341                     parcel.readInt());
   3342         }
   3343 
   3344         if (parcel.readInt() == 1) {
   3345             mCollectionItemInfo = CollectionItemInfo.obtain(
   3346                     parcel.readInt(),
   3347                     parcel.readInt(),
   3348                     parcel.readInt(),
   3349                     parcel.readInt(),
   3350                     parcel.readInt() == 1,
   3351                     parcel.readInt() == 1);
   3352         }
   3353 
   3354         mSealed = sealed;
   3355     }
   3356 
   3357     /**
   3358      * Clears the state of this instance.
   3359      */
   3360     private void clear() {
   3361         mSealed = false;
   3362         mSourceNodeId = UNDEFINED_NODE_ID;
   3363         mParentNodeId = UNDEFINED_NODE_ID;
   3364         mLabelForId = UNDEFINED_NODE_ID;
   3365         mLabeledById = UNDEFINED_NODE_ID;
   3366         mTraversalBefore = UNDEFINED_NODE_ID;
   3367         mTraversalAfter = UNDEFINED_NODE_ID;
   3368         mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
   3369         mConnectionId = UNDEFINED_CONNECTION_ID;
   3370         mMaxTextLength = -1;
   3371         mMovementGranularities = 0;
   3372         if (mChildNodeIds != null) {
   3373             mChildNodeIds.clear();
   3374         }
   3375         mBoundsInParent.set(0, 0, 0, 0);
   3376         mBoundsInScreen.set(0, 0, 0, 0);
   3377         mBooleanProperties = 0;
   3378         mDrawingOrderInParent = 0;
   3379         mExtraDataKeys = null;
   3380         mPackageName = null;
   3381         mClassName = null;
   3382         mText = null;
   3383         mHintText = null;
   3384         mError = null;
   3385         mContentDescription = null;
   3386         mViewIdResourceName = null;
   3387         removeAllActions();
   3388         mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
   3389         mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
   3390         mInputType = InputType.TYPE_NULL;
   3391         mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
   3392         mExtras = null;
   3393         if (mRangeInfo != null) {
   3394             mRangeInfo.recycle();
   3395             mRangeInfo = null;
   3396         }
   3397         if (mCollectionInfo != null) {
   3398             mCollectionInfo.recycle();
   3399             mCollectionInfo = null;
   3400         }
   3401         if (mCollectionItemInfo != null) {
   3402             mCollectionItemInfo.recycle();
   3403             mCollectionItemInfo = null;
   3404         }
   3405     }
   3406 
   3407     private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
   3408         return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
   3409                 && TextUtils.isEmpty(action.getLabel()));
   3410     }
   3411 
   3412     private static AccessibilityAction getActionSingleton(int actionId) {
   3413         final int actions = AccessibilityAction.sStandardActions.size();
   3414         for (int i = 0; i < actions; i++) {
   3415             AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
   3416             if (actionId == currentAction.getId()) {
   3417                 return currentAction;
   3418             }
   3419         }
   3420 
   3421         return null;
   3422     }
   3423 
   3424     private void addLegacyStandardActions(int actionMask) {
   3425         int remainingIds = actionMask;
   3426         while (remainingIds > 0) {
   3427             final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
   3428             remainingIds &= ~id;
   3429             AccessibilityAction action = getActionSingleton(id);
   3430             addAction(action);
   3431         }
   3432     }
   3433 
   3434     /**
   3435      * Gets the human readable action symbolic name.
   3436      *
   3437      * @param action The action.
   3438      * @return The symbolic name.
   3439      */
   3440     private static String getActionSymbolicName(int action) {
   3441         switch (action) {
   3442             case ACTION_FOCUS:
   3443                 return "ACTION_FOCUS";
   3444             case ACTION_CLEAR_FOCUS:
   3445                 return "ACTION_CLEAR_FOCUS";
   3446             case ACTION_SELECT:
   3447                 return "ACTION_SELECT";
   3448             case ACTION_CLEAR_SELECTION:
   3449                 return "ACTION_CLEAR_SELECTION";
   3450             case ACTION_CLICK:
   3451                 return "ACTION_CLICK";
   3452             case ACTION_LONG_CLICK:
   3453                 return "ACTION_LONG_CLICK";
   3454             case ACTION_ACCESSIBILITY_FOCUS:
   3455                 return "ACTION_ACCESSIBILITY_FOCUS";
   3456             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
   3457                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
   3458             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
   3459                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
   3460             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
   3461                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
   3462             case ACTION_NEXT_HTML_ELEMENT:
   3463                 return "ACTION_NEXT_HTML_ELEMENT";
   3464             case ACTION_PREVIOUS_HTML_ELEMENT:
   3465                 return "ACTION_PREVIOUS_HTML_ELEMENT";
   3466             case ACTION_SCROLL_FORWARD:
   3467                 return "ACTION_SCROLL_FORWARD";
   3468             case ACTION_SCROLL_BACKWARD:
   3469                 return "ACTION_SCROLL_BACKWARD";
   3470             case ACTION_CUT:
   3471                 return "ACTION_CUT";
   3472             case ACTION_COPY:
   3473                 return "ACTION_COPY";
   3474             case ACTION_PASTE:
   3475                 return "ACTION_PASTE";
   3476             case ACTION_SET_SELECTION:
   3477                 return "ACTION_SET_SELECTION";
   3478             case ACTION_EXPAND:
   3479                 return "ACTION_EXPAND";
   3480             case ACTION_COLLAPSE:
   3481                 return "ACTION_COLLAPSE";
   3482             case ACTION_DISMISS:
   3483                 return "ACTION_DISMISS";
   3484             case ACTION_SET_TEXT:
   3485                 return "ACTION_SET_TEXT";
   3486             case R.id.accessibilityActionShowOnScreen:
   3487                 return "ACTION_SHOW_ON_SCREEN";
   3488             case R.id.accessibilityActionScrollToPosition:
   3489                 return "ACTION_SCROLL_TO_POSITION";
   3490             case R.id.accessibilityActionScrollUp:
   3491                 return "ACTION_SCROLL_UP";
   3492             case R.id.accessibilityActionScrollLeft:
   3493                 return "ACTION_SCROLL_LEFT";
   3494             case R.id.accessibilityActionScrollDown:
   3495                 return "ACTION_SCROLL_DOWN";
   3496             case R.id.accessibilityActionScrollRight:
   3497                 return "ACTION_SCROLL_RIGHT";
   3498             case R.id.accessibilityActionSetProgress:
   3499                 return "ACTION_SET_PROGRESS";
   3500             case R.id.accessibilityActionContextClick:
   3501                 return "ACTION_CONTEXT_CLICK";
   3502             default:
   3503                 return "ACTION_UNKNOWN";
   3504         }
   3505     }
   3506 
   3507     /**
   3508      * Gets the human readable movement granularity symbolic name.
   3509      *
   3510      * @param granularity The granularity.
   3511      * @return The symbolic name.
   3512      */
   3513     private static String getMovementGranularitySymbolicName(int granularity) {
   3514         switch (granularity) {
   3515             case MOVEMENT_GRANULARITY_CHARACTER:
   3516                 return "MOVEMENT_GRANULARITY_CHARACTER";
   3517             case MOVEMENT_GRANULARITY_WORD:
   3518                 return "MOVEMENT_GRANULARITY_WORD";
   3519             case MOVEMENT_GRANULARITY_LINE:
   3520                 return "MOVEMENT_GRANULARITY_LINE";
   3521             case MOVEMENT_GRANULARITY_PARAGRAPH:
   3522                 return "MOVEMENT_GRANULARITY_PARAGRAPH";
   3523             case MOVEMENT_GRANULARITY_PAGE:
   3524                 return "MOVEMENT_GRANULARITY_PAGE";
   3525             default:
   3526                 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
   3527         }
   3528     }
   3529 
   3530     private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
   3531         return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
   3532                 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
   3533                 && (mConnectionId != UNDEFINED_CONNECTION_ID));
   3534     }
   3535 
   3536     @Override
   3537     public boolean equals(Object object) {
   3538         if (this == object) {
   3539             return true;
   3540         }
   3541         if (object == null) {
   3542             return false;
   3543         }
   3544         if (getClass() != object.getClass()) {
   3545             return false;
   3546         }
   3547         AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
   3548         if (mSourceNodeId != other.mSourceNodeId) {
   3549             return false;
   3550         }
   3551         if (mWindowId != other.mWindowId) {
   3552             return false;
   3553         }
   3554         return true;
   3555     }
   3556 
   3557     @Override
   3558     public int hashCode() {
   3559         final int prime = 31;
   3560         int result = 1;
   3561         result = prime * result + getAccessibilityViewId(mSourceNodeId);
   3562         result = prime * result + getVirtualDescendantId(mSourceNodeId);
   3563         result = prime * result + mWindowId;
   3564         return result;
   3565     }
   3566 
   3567     @Override
   3568     public String toString() {
   3569         StringBuilder builder = new StringBuilder();
   3570         builder.append(super.toString());
   3571 
   3572         if (DEBUG) {
   3573             builder.append("; sourceNodeId: " + mSourceNodeId);
   3574             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
   3575             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
   3576             builder.append("; mParentNodeId: " + mParentNodeId);
   3577             builder.append("; traversalBefore: ").append(mTraversalBefore);
   3578             builder.append("; traversalAfter: ").append(mTraversalAfter);
   3579 
   3580             int granularities = mMovementGranularities;
   3581             builder.append("; MovementGranularities: [");
   3582             while (granularities != 0) {
   3583                 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
   3584                 granularities &= ~granularity;
   3585                 builder.append(getMovementGranularitySymbolicName(granularity));
   3586                 if (granularities != 0) {
   3587                     builder.append(", ");
   3588                 }
   3589             }
   3590             builder.append("]");
   3591 
   3592             builder.append("; childAccessibilityIds: [");
   3593             final LongArray childIds = mChildNodeIds;
   3594             if (childIds != null) {
   3595                 for (int i = 0, count = childIds.size(); i < count; i++) {
   3596                     builder.append(childIds.get(i));
   3597                     if (i < count - 1) {
   3598                         builder.append(", ");
   3599                     }
   3600                 }
   3601             }
   3602             builder.append("]");
   3603         }
   3604 
   3605         builder.append("; boundsInParent: " + mBoundsInParent);
   3606         builder.append("; boundsInScreen: " + mBoundsInScreen);
   3607 
   3608         builder.append("; packageName: ").append(mPackageName);
   3609         builder.append("; className: ").append(mClassName);
   3610         builder.append("; text: ").append(mText);
   3611         builder.append("; error: ").append(mError);
   3612         builder.append("; maxTextLength: ").append(mMaxTextLength);
   3613         builder.append("; contentDescription: ").append(mContentDescription);
   3614         builder.append("; viewIdResName: ").append(mViewIdResourceName);
   3615 
   3616         builder.append("; checkable: ").append(isCheckable());
   3617         builder.append("; checked: ").append(isChecked());
   3618         builder.append("; focusable: ").append(isFocusable());
   3619         builder.append("; focused: ").append(isFocused());
   3620         builder.append("; selected: ").append(isSelected());
   3621         builder.append("; clickable: ").append(isClickable());
   3622         builder.append("; longClickable: ").append(isLongClickable());
   3623         builder.append("; contextClickable: ").append(isContextClickable());
   3624         builder.append("; enabled: ").append(isEnabled());
   3625         builder.append("; password: ").append(isPassword());
   3626         builder.append("; scrollable: ").append(isScrollable());
   3627         builder.append("; importantForAccessibility: ").append(isImportantForAccessibility());
   3628         builder.append("; actions: ").append(mActions);
   3629 
   3630         return builder.toString();
   3631     }
   3632 
   3633     private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
   3634         if (!canPerformRequestOverConnection(accessibilityId)) {
   3635             return null;
   3636         }
   3637         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   3638         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
   3639                 mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
   3640                         | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
   3641     }
   3642 
   3643     /**
   3644      * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
   3645      * Each action has a unique id that is mandatory and optional data.
   3646      * <p>
   3647      * There are three categories of actions:
   3648      * <ul>
   3649      * <li><strong>Standard actions</strong> - These are actions that are reported and
   3650      * handled by the standard UI widgets in the platform. For each standard action
   3651      * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
   3652      * These actions will have {@code null} labels.
   3653      * </li>
   3654      * <li><strong>Custom actions action</strong> - These are actions that are reported
   3655      * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
   3656      * example, an application may define a custom action for clearing the user history.
   3657      * </li>
   3658      * <li><strong>Overriden standard actions</strong> - These are actions that override
   3659      * standard actions to customize them. For example, an app may add a label to the
   3660      * standard {@link #ACTION_CLICK} action to announce that this action clears browsing history.
   3661      * </ul>
   3662      * </p>
   3663      * <p>
   3664      * Actions are typically added to an {@link AccessibilityNodeInfo} by using
   3665      * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within
   3666      * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed
   3667      * within {@link View#performAccessibilityAction(int, Bundle)}.
   3668      * </p>
   3669      * <p class="note">
   3670      * <strong>Note:</strong> Views which support these actions should invoke
   3671      * {@link View#setImportantForAccessibility(int)} with
   3672      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService}
   3673      * can discover the set of supported actions.
   3674      * </p>
   3675      */
   3676     public static final class AccessibilityAction {
   3677 
   3678         /**
   3679          * Action that gives input focus to the node.
   3680          */
   3681         public static final AccessibilityAction ACTION_FOCUS =
   3682                 new AccessibilityAction(
   3683                         AccessibilityNodeInfo.ACTION_FOCUS, null);
   3684 
   3685         /**
   3686          * Action that clears input focus of the node.
   3687          */
   3688         public static final AccessibilityAction ACTION_CLEAR_FOCUS =
   3689                 new AccessibilityAction(
   3690                         AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
   3691 
   3692         /**
   3693          *  Action that selects the node.
   3694          */
   3695         public static final AccessibilityAction ACTION_SELECT =
   3696                 new AccessibilityAction(
   3697                         AccessibilityNodeInfo.ACTION_SELECT, null);
   3698 
   3699         /**
   3700          * Action that deselects the node.
   3701          */
   3702         public static final AccessibilityAction ACTION_CLEAR_SELECTION =
   3703                 new AccessibilityAction(
   3704                         AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
   3705 
   3706         /**
   3707          * Action that clicks on the node info.
   3708          */
   3709         public static final AccessibilityAction ACTION_CLICK =
   3710                 new AccessibilityAction(
   3711                         AccessibilityNodeInfo.ACTION_CLICK, null);
   3712 
   3713         /**
   3714          * Action that long clicks on the node.
   3715          */
   3716         public static final AccessibilityAction ACTION_LONG_CLICK =
   3717                 new AccessibilityAction(
   3718                         AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
   3719 
   3720         /**
   3721          * Action that gives accessibility focus to the node.
   3722          */
   3723         public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
   3724                 new AccessibilityAction(
   3725                         AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
   3726 
   3727         /**
   3728          * Action that clears accessibility focus of the node.
   3729          */
   3730         public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
   3731                 new AccessibilityAction(
   3732                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
   3733 
   3734         /**
   3735          * Action that requests to go to the next entity in this node's text
   3736          * at a given movement granularity. For example, move to the next character,
   3737          * word, etc.
   3738          * <p>
   3739          * <strong>Arguments:</strong>
   3740          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3741          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
   3742          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3743          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
   3744          * <strong>Example:</strong> Move to the previous character and do not extend selection.
   3745          * <code><pre><p>
   3746          *   Bundle arguments = new Bundle();
   3747          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
   3748          *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
   3749          *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
   3750          *           false);
   3751          *   info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
   3752          *           arguments);
   3753          * </code></pre></p>
   3754          * </p>
   3755          *
   3756          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3757          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3758          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3759          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3760          *
   3761          * @see AccessibilityNodeInfo#setMovementGranularities(int)
   3762          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3763          * @see AccessibilityNodeInfo#getMovementGranularities()
   3764          *  AccessibilityNodeInfo.getMovementGranularities()
   3765          *
   3766          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
   3767          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
   3768          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
   3769          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
   3770          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
   3771          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
   3772          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
   3773          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
   3774          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
   3775          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
   3776          */
   3777         public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
   3778                 new AccessibilityAction(
   3779                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
   3780 
   3781         /**
   3782          * Action that requests to go to the previous entity in this node's text
   3783          * at a given movement granularity. For example, move to the next character,
   3784          * word, etc.
   3785          * <p>
   3786          * <strong>Arguments:</strong>
   3787          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3788          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
   3789          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3790          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
   3791          * <strong>Example:</strong> Move to the next character and do not extend selection.
   3792          * <code><pre><p>
   3793          *   Bundle arguments = new Bundle();
   3794          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
   3795          *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
   3796          *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
   3797          *           false);
   3798          *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
   3799          *           arguments);
   3800          * </code></pre></p>
   3801          * </p>
   3802          *
   3803          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3804          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
   3805          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3806          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
   3807          *
   3808          * @see AccessibilityNodeInfo#setMovementGranularities(int)
   3809          *   AccessibilityNodeInfo.setMovementGranularities(int)
   3810          * @see AccessibilityNodeInfo#getMovementGranularities()
   3811          *  AccessibilityNodeInfo.getMovementGranularities()
   3812          *
   3813          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
   3814          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
   3815          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
   3816          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
   3817          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
   3818          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
   3819          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
   3820          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
   3821          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
   3822          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
   3823          */
   3824         public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
   3825                 new AccessibilityAction(
   3826                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
   3827 
   3828         /**
   3829          * Action to move to the next HTML element of a given type. For example, move
   3830          * to the BUTTON, INPUT, TABLE, etc.
   3831          * <p>
   3832          * <strong>Arguments:</strong>
   3833          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
   3834          *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
   3835          * <strong>Example:</strong>
   3836          * <code><pre><p>
   3837          *   Bundle arguments = new Bundle();
   3838          *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
   3839          *   info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
   3840          * </code></pre></p>
   3841          * </p>
   3842          */
   3843         public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
   3844                 new AccessibilityAction(
   3845                         AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
   3846 
   3847         /**
   3848          * Action to move to the previous HTML element of a given type. For example, move
   3849          * to the BUTTON, INPUT, TABLE, etc.
   3850          * <p>
   3851          * <strong>Arguments:</strong>
   3852          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
   3853          *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
   3854          * <strong>Example:</strong>
   3855          * <code><pre><p>
   3856          *   Bundle arguments = new Bundle();
   3857          *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
   3858          *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
   3859          * </code></pre></p>
   3860          * </p>
   3861          */
   3862         public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
   3863                 new AccessibilityAction(
   3864                         AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
   3865 
   3866         /**
   3867          * Action to scroll the node content forward.
   3868          */
   3869         public static final AccessibilityAction ACTION_SCROLL_FORWARD =
   3870                 new AccessibilityAction(
   3871                         AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
   3872 
   3873         /**
   3874          * Action to scroll the node content backward.
   3875          */
   3876         public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
   3877                 new AccessibilityAction(
   3878                         AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
   3879 
   3880         /**
   3881          * Action to copy the current selection to the clipboard.
   3882          */
   3883         public static final AccessibilityAction ACTION_COPY =
   3884                 new AccessibilityAction(
   3885                         AccessibilityNodeInfo.ACTION_COPY, null);
   3886 
   3887         /**
   3888          * Action to paste the current clipboard content.
   3889          */
   3890         public static final AccessibilityAction ACTION_PASTE =
   3891                 new AccessibilityAction(
   3892                         AccessibilityNodeInfo.ACTION_PASTE, null);
   3893 
   3894         /**
   3895          * Action to cut the current selection and place it to the clipboard.
   3896          */
   3897         public static final AccessibilityAction ACTION_CUT =
   3898                 new AccessibilityAction(
   3899                         AccessibilityNodeInfo.ACTION_CUT, null);
   3900 
   3901         /**
   3902          * Action to set the selection. Performing this action with no arguments
   3903          * clears the selection.
   3904          * <p>
   3905          * <strong>Arguments:</strong>
   3906          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
   3907          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
   3908          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
   3909          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
   3910          * <strong>Example:</strong>
   3911          * <code><pre><p>
   3912          *   Bundle arguments = new Bundle();
   3913          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
   3914          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
   3915          *   info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
   3916          * </code></pre></p>
   3917          * </p>
   3918          *
   3919          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
   3920          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
   3921          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
   3922          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
   3923          */
   3924         public static final AccessibilityAction ACTION_SET_SELECTION =
   3925                 new AccessibilityAction(
   3926                         AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
   3927 
   3928         /**
   3929          * Action to expand an expandable node.
   3930          */
   3931         public static final AccessibilityAction ACTION_EXPAND =
   3932                 new AccessibilityAction(
   3933                         AccessibilityNodeInfo.ACTION_EXPAND, null);
   3934 
   3935         /**
   3936          * Action to collapse an expandable node.
   3937          */
   3938         public static final AccessibilityAction ACTION_COLLAPSE =
   3939                 new AccessibilityAction(
   3940                         AccessibilityNodeInfo.ACTION_COLLAPSE, null);
   3941 
   3942         /**
   3943          * Action to dismiss a dismissable node.
   3944          */
   3945         public static final AccessibilityAction ACTION_DISMISS =
   3946                 new AccessibilityAction(
   3947                         AccessibilityNodeInfo.ACTION_DISMISS, null);
   3948 
   3949         /**
   3950          * Action that sets the text of the node. Performing the action without argument,
   3951          * using <code> null</code> or empty {@link CharSequence} will clear the text. This
   3952          * action will also put the cursor at the end of text.
   3953          * <p>
   3954          * <strong>Arguments:</strong>
   3955          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
   3956          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
   3957          * <strong>Example:</strong>
   3958          * <code><pre><p>
   3959          *   Bundle arguments = new Bundle();
   3960          *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
   3961          *       "android");
   3962          *   info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
   3963          * </code></pre></p>
   3964          */
   3965         public static final AccessibilityAction ACTION_SET_TEXT =
   3966                 new AccessibilityAction(
   3967                         AccessibilityNodeInfo.ACTION_SET_TEXT, null);
   3968 
   3969         /**
   3970          * Action that requests the node make its bounding rectangle visible
   3971          * on the screen, scrolling if necessary just enough.
   3972          *
   3973          * @see View#requestRectangleOnScreen(Rect)
   3974          */
   3975         public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
   3976                 new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
   3977 
   3978         /**
   3979          * Action that scrolls the node to make the specified collection
   3980          * position visible on screen.
   3981          * <p>
   3982          * <strong>Arguments:</strong>
   3983          * <ul>
   3984          *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
   3985          *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
   3986          * <ul>
   3987          *
   3988          * @see AccessibilityNodeInfo#getCollectionInfo()
   3989          */
   3990         public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
   3991                 new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
   3992 
   3993         /**
   3994          * Action to scroll the node content up.
   3995          */
   3996         public static final AccessibilityAction ACTION_SCROLL_UP =
   3997                 new AccessibilityAction(R.id.accessibilityActionScrollUp, null);
   3998 
   3999         /**
   4000          * Action to scroll the node content left.
   4001          */
   4002         public static final AccessibilityAction ACTION_SCROLL_LEFT =
   4003                 new AccessibilityAction(R.id.accessibilityActionScrollLeft, null);
   4004 
   4005         /**
   4006          * Action to scroll the node content down.
   4007          */
   4008         public static final AccessibilityAction ACTION_SCROLL_DOWN =
   4009                 new AccessibilityAction(R.id.accessibilityActionScrollDown, null);
   4010 
   4011         /**
   4012          * Action to scroll the node content right.
   4013          */
   4014         public static final AccessibilityAction ACTION_SCROLL_RIGHT =
   4015                 new AccessibilityAction(R.id.accessibilityActionScrollRight, null);
   4016 
   4017         /**
   4018          * Action that context clicks the node.
   4019          */
   4020         public static final AccessibilityAction ACTION_CONTEXT_CLICK =
   4021                 new AccessibilityAction(R.id.accessibilityActionContextClick, null);
   4022 
   4023         /**
   4024          * Action that sets progress between {@link  RangeInfo#getMin() RangeInfo.getMin()} and
   4025          * {@link  RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as
   4026          * {@link RangeInfo#getType() RangeInfo.getType()}
   4027          * <p>
   4028          * <strong>Arguments:</strong>
   4029          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE}
   4030          *
   4031          * @see RangeInfo
   4032          */
   4033         public static final AccessibilityAction ACTION_SET_PROGRESS =
   4034                 new AccessibilityAction(R.id.accessibilityActionSetProgress, null);
   4035 
   4036         /**
   4037          * Action to move a window to a new location.
   4038          * <p>
   4039          * <strong>Arguments:</strong>
   4040          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X}
   4041          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y}
   4042          */
   4043         public static final AccessibilityAction ACTION_MOVE_WINDOW =
   4044                 new AccessibilityAction(R.id.accessibilityActionMoveWindow, null);
   4045 
   4046         private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
   4047         static {
   4048             sStandardActions.add(ACTION_FOCUS);
   4049             sStandardActions.add(ACTION_CLEAR_FOCUS);
   4050             sStandardActions.add(ACTION_SELECT);
   4051             sStandardActions.add(ACTION_CLEAR_SELECTION);
   4052             sStandardActions.add(ACTION_CLICK);
   4053             sStandardActions.add(ACTION_LONG_CLICK);
   4054             sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
   4055             sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
   4056             sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
   4057             sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
   4058             sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
   4059             sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
   4060             sStandardActions.add(ACTION_SCROLL_FORWARD);
   4061             sStandardActions.add(ACTION_SCROLL_BACKWARD);
   4062             sStandardActions.add(ACTION_COPY);
   4063             sStandardActions.add(ACTION_PASTE);
   4064             sStandardActions.add(ACTION_CUT);
   4065             sStandardActions.add(ACTION_SET_SELECTION);
   4066             sStandardActions.add(ACTION_EXPAND);
   4067             sStandardActions.add(ACTION_COLLAPSE);
   4068             sStandardActions.add(ACTION_DISMISS);
   4069             sStandardActions.add(ACTION_SET_TEXT);
   4070             sStandardActions.add(ACTION_SHOW_ON_SCREEN);
   4071             sStandardActions.add(ACTION_SCROLL_TO_POSITION);
   4072             sStandardActions.add(ACTION_SCROLL_UP);
   4073             sStandardActions.add(ACTION_SCROLL_LEFT);
   4074             sStandardActions.add(ACTION_SCROLL_DOWN);
   4075             sStandardActions.add(ACTION_SCROLL_RIGHT);
   4076             sStandardActions.add(ACTION_SET_PROGRESS);
   4077             sStandardActions.add(ACTION_CONTEXT_CLICK);
   4078         }
   4079 
   4080         private final int mActionId;
   4081         private final CharSequence mLabel;
   4082 
   4083         /**
   4084          * Creates a new AccessibilityAction. For adding a standard action without a specific label,
   4085          * use the static constants.
   4086          *
   4087          * You can also override the description for one the standard actions. Below is an example
   4088          * how to override the standard click action by adding a custom label:
   4089          * <pre>
   4090          *   AccessibilityAction action = new AccessibilityAction(
   4091          *           AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel());
   4092          *   node.addAction(action);
   4093          * </pre>
   4094          *
   4095          * @param actionId The id for this action. This should either be one of the
   4096          *                 standard actions or a specific action for your app. In that case it is
   4097          *                 required to use a resource identifier.
   4098          * @param label The label for the new AccessibilityAction.
   4099          */
   4100         public AccessibilityAction(int actionId, @Nullable CharSequence label) {
   4101             if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
   4102                 throw new IllegalArgumentException("Invalid standard action id");
   4103             }
   4104 
   4105             mActionId = actionId;
   4106             mLabel = label;
   4107         }
   4108 
   4109         /**
   4110          * Gets the id for this action.
   4111          *
   4112          * @return The action id.
   4113          */
   4114         public int getId() {
   4115             return mActionId;
   4116         }
   4117 
   4118         /**
   4119          * Gets the label for this action. Its purpose is to describe the
   4120          * action to user.
   4121          *
   4122          * @return The label.
   4123          */
   4124         public CharSequence getLabel() {
   4125             return mLabel;
   4126         }
   4127 
   4128         @Override
   4129         public int hashCode() {
   4130             return mActionId;
   4131         }
   4132 
   4133         @Override
   4134         public boolean equals(Object other) {
   4135             if (other == null) {
   4136                 return false;
   4137             }
   4138 
   4139             if (other == this) {
   4140                 return true;
   4141             }
   4142 
   4143             if (getClass() != other.getClass()) {
   4144                 return false;
   4145             }
   4146 
   4147             return mActionId == ((AccessibilityAction)other).mActionId;
   4148         }
   4149 
   4150         @Override
   4151         public String toString() {
   4152             return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
   4153         }
   4154     }
   4155 
   4156     /**
   4157      * Class with information if a node is a range. Use
   4158      * {@link RangeInfo#obtain(int, float, float, float)} to get an instance. Recycling is
   4159      * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
   4160      */
   4161     public static final class RangeInfo {
   4162         private static final int MAX_POOL_SIZE = 10;
   4163 
   4164         /** Range type: integer. */
   4165         public static final int RANGE_TYPE_INT = 0;
   4166         /** Range type: float. */
   4167         public static final int RANGE_TYPE_FLOAT = 1;
   4168         /** Range type: percent with values from zero to one.*/
   4169         public static final int RANGE_TYPE_PERCENT = 2;
   4170 
   4171         private static final SynchronizedPool<RangeInfo> sPool =
   4172                 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
   4173 
   4174         private int mType;
   4175         private float mMin;
   4176         private float mMax;
   4177         private float mCurrent;
   4178 
   4179         /**
   4180          * Obtains a pooled instance that is a clone of another one.
   4181          *
   4182          * @param other The instance to clone.
   4183          *
   4184          * @hide
   4185          */
   4186         public static RangeInfo obtain(RangeInfo other) {
   4187             return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
   4188         }
   4189 
   4190         /**
   4191          * Obtains a pooled instance.
   4192          *
   4193          * @param type The type of the range.
   4194          * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
   4195          *            minimum.
   4196          * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
   4197          *            maximum.
   4198          * @param current The current value.
   4199          */
   4200         public static RangeInfo obtain(int type, float min, float max, float current) {
   4201             RangeInfo info = sPool.acquire();
   4202             if (info == null) {
   4203                 return new RangeInfo(type, min, max, current);
   4204             }
   4205 
   4206             info.mType = type;
   4207             info.mMin = min;
   4208             info.mMax = max;
   4209             info.mCurrent = current;
   4210             return info;
   4211         }
   4212 
   4213         /**
   4214          * Creates a new range.
   4215          *
   4216          * @param type The type of the range.
   4217          * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
   4218          *            minimum.
   4219          * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
   4220          *            maximum.
   4221          * @param current The current value.
   4222          */
   4223         private RangeInfo(int type, float min, float max, float current) {
   4224             mType = type;
   4225             mMin = min;
   4226             mMax = max;
   4227             mCurrent = current;
   4228         }
   4229 
   4230         /**
   4231          * Gets the range type.
   4232          *
   4233          * @return The range type.
   4234          *
   4235          * @see #RANGE_TYPE_INT
   4236          * @see #RANGE_TYPE_FLOAT
   4237          * @see #RANGE_TYPE_PERCENT
   4238          */
   4239         public int getType() {
   4240             return mType;
   4241         }
   4242 
   4243         /**
   4244          * Gets the minimum value.
   4245          *
   4246          * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists.
   4247          */
   4248         public float getMin() {
   4249             return mMin;
   4250         }
   4251 
   4252         /**
   4253          * Gets the maximum value.
   4254          *
   4255          * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists.
   4256          */
   4257         public float getMax() {
   4258             return mMax;
   4259         }
   4260 
   4261         /**
   4262          * Gets the current value.
   4263          *
   4264          * @return The current value.
   4265          */
   4266         public float getCurrent() {
   4267             return mCurrent;
   4268         }
   4269 
   4270         /**
   4271          * Recycles this instance.
   4272          */
   4273         void recycle() {
   4274             clear();
   4275             sPool.release(this);
   4276         }
   4277 
   4278         private void clear() {
   4279             mType = 0;
   4280             mMin = 0;
   4281             mMax = 0;
   4282             mCurrent = 0;
   4283         }
   4284     }
   4285 
   4286     /**
   4287      * Class with information if a node is a collection. Use
   4288      * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance. Recycling is
   4289      * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
   4290      * <p>
   4291      * A collection of items has rows and columns and may be hierarchical.
   4292      * For example, a horizontal list is a collection with one column, as
   4293      * many rows as the list items, and is not hierarchical; A table is a
   4294      * collection with several rows, several columns, and is not hierarchical;
   4295      * A vertical tree is a hierarchical collection with one column and
   4296      * as many rows as the first level children.
   4297      * </p>
   4298      */
   4299     public static final class CollectionInfo {
   4300         /** Selection mode where items are not selectable. */
   4301         public static final int SELECTION_MODE_NONE = 0;
   4302 
   4303         /** Selection mode where a single item may be selected. */
   4304         public static final int SELECTION_MODE_SINGLE = 1;
   4305 
   4306         /** Selection mode where multiple items may be selected. */
   4307         public static final int SELECTION_MODE_MULTIPLE = 2;
   4308 
   4309         private static final int MAX_POOL_SIZE = 20;
   4310 
   4311         private static final SynchronizedPool<CollectionInfo> sPool =
   4312                 new SynchronizedPool<>(MAX_POOL_SIZE);
   4313 
   4314         private int mRowCount;
   4315         private int mColumnCount;
   4316         private boolean mHierarchical;
   4317         private int mSelectionMode;
   4318 
   4319         /**
   4320          * Obtains a pooled instance that is a clone of another one.
   4321          *
   4322          * @param other The instance to clone.
   4323          * @hide
   4324          */
   4325         public static CollectionInfo obtain(CollectionInfo other) {
   4326             return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
   4327                     other.mSelectionMode);
   4328         }
   4329 
   4330         /**
   4331          * Obtains a pooled instance.
   4332          *
   4333          * @param rowCount The number of rows.
   4334          * @param columnCount The number of columns.
   4335          * @param hierarchical Whether the collection is hierarchical.
   4336          */
   4337         public static CollectionInfo obtain(int rowCount, int columnCount,
   4338                 boolean hierarchical) {
   4339             return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
   4340         }
   4341 
   4342         /**
   4343          * Obtains a pooled instance.
   4344          *
   4345          * @param rowCount The number of rows.
   4346          * @param columnCount The number of columns.
   4347          * @param hierarchical Whether the collection is hierarchical.
   4348          * @param selectionMode The collection's selection mode, one of:
   4349          *            <ul>
   4350          *            <li>{@link #SELECTION_MODE_NONE}
   4351          *            <li>{@link #SELECTION_MODE_SINGLE}
   4352          *            <li>{@link #SELECTION_MODE_MULTIPLE}
   4353          *            </ul>
   4354          */
   4355         public static CollectionInfo obtain(int rowCount, int columnCount,
   4356                 boolean hierarchical, int selectionMode) {
   4357            final CollectionInfo info = sPool.acquire();
   4358             if (info == null) {
   4359                 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
   4360             }
   4361 
   4362             info.mRowCount = rowCount;
   4363             info.mColumnCount = columnCount;
   4364             info.mHierarchical = hierarchical;
   4365             info.mSelectionMode = selectionMode;
   4366             return info;
   4367         }
   4368 
   4369         /**
   4370          * Creates a new instance.
   4371          *
   4372          * @param rowCount The number of rows.
   4373          * @param columnCount The number of columns.
   4374          * @param hierarchical Whether the collection is hierarchical.
   4375          * @param selectionMode The collection's selection mode.
   4376          */
   4377         private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
   4378                 int selectionMode) {
   4379             mRowCount = rowCount;
   4380             mColumnCount = columnCount;
   4381             mHierarchical = hierarchical;
   4382             mSelectionMode = selectionMode;
   4383         }
   4384 
   4385         /**
   4386          * Gets the number of rows.
   4387          *
   4388          * @return The row count.
   4389          */
   4390         public int getRowCount() {
   4391             return mRowCount;
   4392         }
   4393 
   4394         /**
   4395          * Gets the number of columns.
   4396          *
   4397          * @return The column count.
   4398          */
   4399         public int getColumnCount() {
   4400             return mColumnCount;
   4401         }
   4402 
   4403         /**
   4404          * Gets if the collection is a hierarchically ordered.
   4405          *
   4406          * @return Whether the collection is hierarchical.
   4407          */
   4408         public boolean isHierarchical() {
   4409             return mHierarchical;
   4410         }
   4411 
   4412         /**
   4413          * Gets the collection's selection mode.
   4414          *
   4415          * @return The collection's selection mode, one of:
   4416          *         <ul>
   4417          *         <li>{@link #SELECTION_MODE_NONE}
   4418          *         <li>{@link #SELECTION_MODE_SINGLE}
   4419          *         <li>{@link #SELECTION_MODE_MULTIPLE}
   4420          *         </ul>
   4421          */
   4422         public int getSelectionMode() {
   4423             return mSelectionMode;
   4424         }
   4425 
   4426         /**
   4427          * Recycles this instance.
   4428          */
   4429         void recycle() {
   4430             clear();
   4431             sPool.release(this);
   4432         }
   4433 
   4434         private void clear() {
   4435             mRowCount = 0;
   4436             mColumnCount = 0;
   4437             mHierarchical = false;
   4438             mSelectionMode = SELECTION_MODE_NONE;
   4439         }
   4440     }
   4441 
   4442     /**
   4443      * Class with information if a node is a collection item. Use
   4444      * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
   4445      * to get an instance. Recycling is handled by the {@link AccessibilityNodeInfo} to which this
   4446      * object is attached.
   4447      * <p>
   4448      * A collection item is contained in a collection, it starts at
   4449      * a given row and column in the collection, and spans one or
   4450      * more rows and columns. For example, a header of two related
   4451      * table columns starts at the first row and the first column,
   4452      * spans one row and two columns.
   4453      * </p>
   4454      */
   4455     public static final class CollectionItemInfo {
   4456         private static final int MAX_POOL_SIZE = 20;
   4457 
   4458         private static final SynchronizedPool<CollectionItemInfo> sPool =
   4459                 new SynchronizedPool<>(MAX_POOL_SIZE);
   4460 
   4461         /**
   4462          * Obtains a pooled instance that is a clone of another one.
   4463          *
   4464          * @param other The instance to clone.
   4465          * @hide
   4466          */
   4467         public static CollectionItemInfo obtain(CollectionItemInfo other) {
   4468             return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
   4469                     other.mColumnSpan, other.mHeading, other.mSelected);
   4470         }
   4471 
   4472         /**
   4473          * Obtains a pooled instance.
   4474          *
   4475          * @param rowIndex The row index at which the item is located.
   4476          * @param rowSpan The number of rows the item spans.
   4477          * @param columnIndex The column index at which the item is located.
   4478          * @param columnSpan The number of columns the item spans.
   4479          * @param heading Whether the item is a heading.
   4480          */
   4481         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
   4482                 int columnIndex, int columnSpan, boolean heading) {
   4483             return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
   4484         }
   4485 
   4486         /**
   4487          * Obtains a pooled instance.
   4488          *
   4489          * @param rowIndex The row index at which the item is located.
   4490          * @param rowSpan The number of rows the item spans.
   4491          * @param columnIndex The column index at which the item is located.
   4492          * @param columnSpan The number of columns the item spans.
   4493          * @param heading Whether the item is a heading.
   4494          * @param selected Whether the item is selected.
   4495          */
   4496         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
   4497                 int columnIndex, int columnSpan, boolean heading, boolean selected) {
   4498             final CollectionItemInfo info = sPool.acquire();
   4499             if (info == null) {
   4500                 return new CollectionItemInfo(
   4501                         rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
   4502             }
   4503 
   4504             info.mRowIndex = rowIndex;
   4505             info.mRowSpan = rowSpan;
   4506             info.mColumnIndex = columnIndex;
   4507             info.mColumnSpan = columnSpan;
   4508             info.mHeading = heading;
   4509             info.mSelected = selected;
   4510             return info;
   4511         }
   4512 
   4513         private boolean mHeading;
   4514         private int mColumnIndex;
   4515         private int mRowIndex;
   4516         private int mColumnSpan;
   4517         private int mRowSpan;
   4518         private boolean mSelected;
   4519 
   4520         /**
   4521          * Creates a new instance.
   4522          *
   4523          * @param rowIndex The row index at which the item is located.
   4524          * @param rowSpan The number of rows the item spans.
   4525          * @param columnIndex The column index at which the item is located.
   4526          * @param columnSpan The number of columns the item spans.
   4527          * @param heading Whether the item is a heading.
   4528          */
   4529         private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
   4530                 boolean heading, boolean selected) {
   4531             mRowIndex = rowIndex;
   4532             mRowSpan = rowSpan;
   4533             mColumnIndex = columnIndex;
   4534             mColumnSpan = columnSpan;
   4535             mHeading = heading;
   4536             mSelected = selected;
   4537         }
   4538 
   4539         /**
   4540          * Gets the column index at which the item is located.
   4541          *
   4542          * @return The column index.
   4543          */
   4544         public int getColumnIndex() {
   4545             return mColumnIndex;
   4546         }
   4547 
   4548         /**
   4549          * Gets the row index at which the item is located.
   4550          *
   4551          * @return The row index.
   4552          */
   4553         public int getRowIndex() {
   4554             return mRowIndex;
   4555         }
   4556 
   4557         /**
   4558          * Gets the number of columns the item spans.
   4559          *
   4560          * @return The column span.
   4561          */
   4562         public int getColumnSpan() {
   4563             return mColumnSpan;
   4564         }
   4565 
   4566         /**
   4567          * Gets the number of rows the item spans.
   4568          *
   4569          * @return The row span.
   4570          */
   4571         public int getRowSpan() {
   4572             return mRowSpan;
   4573         }
   4574 
   4575         /**
   4576          * Gets if the collection item is a heading. For example, section
   4577          * heading, table header, etc.
   4578          *
   4579          * @return If the item is a heading.
   4580          */
   4581         public boolean isHeading() {
   4582             return mHeading;
   4583         }
   4584 
   4585         /**
   4586          * Gets if the collection item is selected.
   4587          *
   4588          * @return If the item is selected.
   4589          */
   4590         public boolean isSelected() {
   4591             return mSelected;
   4592         }
   4593 
   4594         /**
   4595          * Recycles this instance.
   4596          */
   4597         void recycle() {
   4598             clear();
   4599             sPool.release(this);
   4600         }
   4601 
   4602         private void clear() {
   4603             mColumnIndex = 0;
   4604             mColumnSpan = 0;
   4605             mRowIndex = 0;
   4606             mRowSpan = 0;
   4607             mHeading = false;
   4608             mSelected = false;
   4609         }
   4610     }
   4611 
   4612     /**
   4613      * @see android.os.Parcelable.Creator
   4614      */
   4615     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
   4616             new Parcelable.Creator<AccessibilityNodeInfo>() {
   4617         @Override
   4618         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
   4619             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   4620             info.initFromParcel(parcel);
   4621             return info;
   4622         }
   4623 
   4624         @Override
   4625         public AccessibilityNodeInfo[] newArray(int size) {
   4626             return new AccessibilityNodeInfo[size];
   4627         }
   4628     };
   4629 }
   4630