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