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