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.graphics.Rect;
     21 import android.os.Bundle;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.text.InputType;
     25 import android.util.Pools.SynchronizedPool;
     26 import android.util.SparseLongArray;
     27 import android.view.View;
     28 
     29 import java.util.Collections;
     30 import java.util.List;
     31 
     32 /**
     33  * This class represents a node of the window content as well as actions that
     34  * can be requested from its source. From the point of view of an
     35  * {@link android.accessibilityservice.AccessibilityService} a window content is
     36  * presented as tree of accessibility node info which may or may not map one-to-one
     37  * to the view hierarchy. In other words, a custom view is free to report itself as
     38  * a tree of accessibility node info.
     39  * </p>
     40  * <p>
     41  * Once an accessibility node info is delivered to an accessibility service it is
     42  * made immutable and calling a state mutation method generates an error.
     43  * </p>
     44  * <p>
     45  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
     46  * details about how to obtain a handle to window content as a tree of accessibility
     47  * node info as well as familiarizing with the security model.
     48  * </p>
     49  * <div class="special reference">
     50  * <h3>Developer Guides</h3>
     51  * <p>For more information about making applications accessible, read the
     52  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     53  * developer guide.</p>
     54  * </div>
     55  *
     56  * @see android.accessibilityservice.AccessibilityService
     57  * @see AccessibilityEvent
     58  * @see AccessibilityManager
     59  */
     60 public class AccessibilityNodeInfo implements Parcelable {
     61 
     62     private static final boolean DEBUG = false;
     63 
     64     /** @hide */
     65     public static final int UNDEFINED = -1;
     66 
     67     /** @hide */
     68     public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
     69 
     70     /** @hide */
     71     public static final int ACTIVE_WINDOW_ID = UNDEFINED;
     72 
     73     /** @hide */
     74     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
     75 
     76     /** @hide */
     77     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
     78 
     79     /** @hide */
     80     public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
     81 
     82     /** @hide */
     83     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
     84 
     85     /** @hide */
     86     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
     87 
     88     // Actions.
     89 
     90     /**
     91      * Action that gives input focus to the node.
     92      */
     93     public static final int ACTION_FOCUS =  0x00000001;
     94 
     95     /**
     96      * Action that clears input focus of the node.
     97      */
     98     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
     99 
    100     /**
    101      * Action that selects the node.
    102      */
    103     public static final int ACTION_SELECT = 0x00000004;
    104 
    105     /**
    106      * Action that unselects the node.
    107      */
    108     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
    109 
    110     /**
    111      * Action that clicks on the node info.
    112      */
    113     public static final int ACTION_CLICK = 0x00000010;
    114 
    115     /**
    116      * Action that long clicks on the node.
    117      */
    118     public static final int ACTION_LONG_CLICK = 0x00000020;
    119 
    120     /**
    121      * Action that gives accessibility focus to the node.
    122      */
    123     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
    124 
    125     /**
    126      * Action that clears accessibility focus of the node.
    127      */
    128     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
    129 
    130     /**
    131      * Action that requests to go to the next entity in this node's text
    132      * at a given movement granularity. For example, move to the next character,
    133      * word, etc.
    134      * <p>
    135      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    136      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    137      * <strong>Example:</strong> Move to the previous character and do not extend selection.
    138      * <code><pre><p>
    139      *   Bundle arguments = new Bundle();
    140      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    141      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    142      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    143      *           false);
    144      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
    145      * </code></pre></p>
    146      * </p>
    147      *
    148      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    149      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    150      *
    151      * @see #setMovementGranularities(int)
    152      * @see #getMovementGranularities()
    153      *
    154      * @see #MOVEMENT_GRANULARITY_CHARACTER
    155      * @see #MOVEMENT_GRANULARITY_WORD
    156      * @see #MOVEMENT_GRANULARITY_LINE
    157      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    158      * @see #MOVEMENT_GRANULARITY_PAGE
    159      */
    160     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
    161 
    162     /**
    163      * Action that requests to go to the previous entity in this node's text
    164      * at a given movement granularity. For example, move to the next character,
    165      * word, etc.
    166      * <p>
    167      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    168      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    169      * <strong>Example:</strong> Move to the next character and do not extend selection.
    170      * <code><pre><p>
    171      *   Bundle arguments = new Bundle();
    172      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    173      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    174      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    175      *           false);
    176      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
    177      *           arguments);
    178      * </code></pre></p>
    179      * </p>
    180      *
    181      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    182      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    183      *
    184      * @see #setMovementGranularities(int)
    185      * @see #getMovementGranularities()
    186      *
    187      * @see #MOVEMENT_GRANULARITY_CHARACTER
    188      * @see #MOVEMENT_GRANULARITY_WORD
    189      * @see #MOVEMENT_GRANULARITY_LINE
    190      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    191      * @see #MOVEMENT_GRANULARITY_PAGE
    192      */
    193     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
    194 
    195     /**
    196      * Action to move to the next HTML element of a given type. For example, move
    197      * to the BUTTON, INPUT, TABLE, etc.
    198      * <p>
    199      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    200      * <strong>Example:</strong>
    201      * <code><pre><p>
    202      *   Bundle arguments = new Bundle();
    203      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    204      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
    205      * </code></pre></p>
    206      * </p>
    207      */
    208     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
    209 
    210     /**
    211      * Action to move to the previous 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_PREVIOUS_HTML_ELEMENT, arguments);
    220      * </code></pre></p>
    221      * </p>
    222      */
    223     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
    224 
    225     /**
    226      * Action to scroll the node content forward.
    227      */
    228     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
    229 
    230     /**
    231      * Action to scroll the node content backward.
    232      */
    233     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
    234 
    235     /**
    236      * Action to copy the current selection to the clipboard.
    237      */
    238     public static final int ACTION_COPY = 0x00004000;
    239 
    240     /**
    241      * Action to paste the current clipboard content.
    242      */
    243     public static final int ACTION_PASTE = 0x00008000;
    244 
    245     /**
    246      * Action to cut the current selection and place it to the clipboard.
    247      */
    248     public static final int ACTION_CUT = 0x00010000;
    249 
    250     /**
    251      * Action to set the selection. Performing this action with no arguments
    252      * clears the selection.
    253      * <p>
    254      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
    255      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
    256      * <strong>Example:</strong>
    257      * <code><pre><p>
    258      *   Bundle arguments = new Bundle();
    259      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
    260      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
    261      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
    262      * </code></pre></p>
    263      * </p>
    264      *
    265      * @see #ACTION_ARGUMENT_SELECTION_START_INT
    266      * @see #ACTION_ARGUMENT_SELECTION_END_INT
    267      */
    268     public static final int ACTION_SET_SELECTION = 0x00020000;
    269 
    270     /**
    271      * Action to expand an expandable node.
    272      */
    273     public static final int ACTION_EXPAND = 0x00040000;
    274 
    275     /**
    276      * Action to collapse an expandable node.
    277      */
    278     public static final int ACTION_COLLAPSE = 0x00080000;
    279 
    280     /**
    281      * Action to dismiss a dismissable node.
    282      */
    283     public static final int ACTION_DISMISS = 0x00100000;
    284 
    285     // Action arguments
    286 
    287     /**
    288      * Argument for which movement granularity to be used when traversing the node text.
    289      * <p>
    290      * <strong>Type:</strong> int<br>
    291      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
    292      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
    293      * </p>
    294      *
    295      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    296      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    297      */
    298     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
    299             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
    300 
    301     /**
    302      * Argument for which HTML element to get moving to the next/previous HTML element.
    303      * <p>
    304      * <strong>Type:</strong> String<br>
    305      * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
    306      *         {@link #ACTION_PREVIOUS_HTML_ELEMENT}
    307      * </p>
    308      *
    309      * @see #ACTION_NEXT_HTML_ELEMENT
    310      * @see #ACTION_PREVIOUS_HTML_ELEMENT
    311      */
    312     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
    313             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
    314 
    315     /**
    316      * Argument for whether when moving at granularity to extend the selection
    317      * or to move it otherwise.
    318      * <p>
    319      * <strong>Type:</strong> boolean<br>
    320      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
    321      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
    322      * </p>
    323      *
    324      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    325      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    326      */
    327     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
    328             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
    329 
    330     /**
    331      * Argument for specifying the selection start.
    332      * <p>
    333      * <strong>Type:</strong> int<br>
    334      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
    335      * </p>
    336      *
    337      * @see #ACTION_SET_SELECTION
    338      */
    339     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
    340             "ACTION_ARGUMENT_SELECTION_START_INT";
    341 
    342     /**
    343      * Argument for specifying the selection end.
    344      * <p>
    345      * <strong>Type:</strong> int<br>
    346      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
    347      * </p>
    348      *
    349      * @see #ACTION_SET_SELECTION
    350      */
    351     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
    352             "ACTION_ARGUMENT_SELECTION_END_INT";
    353 
    354     // Focus types
    355 
    356     /**
    357      * The input focus.
    358      */
    359     public static final int FOCUS_INPUT = 1;
    360 
    361     /**
    362      * The accessibility focus.
    363      */
    364     public static final int FOCUS_ACCESSIBILITY = 2;
    365 
    366     // Movement granularities
    367 
    368     /**
    369      * Movement granularity bit for traversing the text of a node by character.
    370      */
    371     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
    372 
    373     /**
    374      * Movement granularity bit for traversing the text of a node by word.
    375      */
    376     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
    377 
    378     /**
    379      * Movement granularity bit for traversing the text of a node by line.
    380      */
    381     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
    382 
    383     /**
    384      * Movement granularity bit for traversing the text of a node by paragraph.
    385      */
    386     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
    387 
    388     /**
    389      * Movement granularity bit for traversing the text of a node by page.
    390      */
    391     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
    392 
    393     // Boolean attributes.
    394 
    395     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
    396 
    397     private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
    398 
    399     private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
    400 
    401     private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
    402 
    403     private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
    404 
    405     private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
    406 
    407     private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
    408 
    409     private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
    410 
    411     private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
    412 
    413     private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
    414 
    415     private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
    416 
    417     private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
    418 
    419     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
    420 
    421     private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
    422 
    423     private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
    424 
    425     private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
    426 
    427     private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
    428 
    429     /**
    430      * Bits that provide the id of a virtual descendant of a view.
    431      */
    432     private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
    433 
    434     /**
    435      * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
    436      * virtual descendant of a view. Such a descendant does not exist in the view
    437      * hierarchy and is only reported via the accessibility APIs.
    438      */
    439     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
    440 
    441     /**
    442      * Gets the accessibility view id which identifies a View in the view three.
    443      *
    444      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    445      * @return The accessibility view id part of the node id.
    446      *
    447      * @hide
    448      */
    449     public static int getAccessibilityViewId(long accessibilityNodeId) {
    450         return (int) accessibilityNodeId;
    451     }
    452 
    453     /**
    454      * Gets the virtual descendant id which identifies an imaginary view in a
    455      * containing View.
    456      *
    457      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    458      * @return The virtual view id part of the node id.
    459      *
    460      * @hide
    461      */
    462     public static int getVirtualDescendantId(long accessibilityNodeId) {
    463         return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
    464                 >> VIRTUAL_DESCENDANT_ID_SHIFT);
    465     }
    466 
    467     /**
    468      * Makes a node id by shifting the <code>virtualDescendantId</code>
    469      * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
    470      * the bitwise or with the <code>accessibilityViewId</code>.
    471      *
    472      * @param accessibilityViewId A View accessibility id.
    473      * @param virtualDescendantId A virtual descendant id.
    474      * @return The node id.
    475      *
    476      * @hide
    477      */
    478     public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
    479         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
    480     }
    481 
    482     // Housekeeping.
    483     private static final int MAX_POOL_SIZE = 50;
    484     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
    485             new SynchronizedPool<AccessibilityNodeInfo>(MAX_POOL_SIZE);
    486 
    487     private boolean mSealed;
    488 
    489     // Data.
    490     private int mWindowId = UNDEFINED;
    491     private long mSourceNodeId = ROOT_NODE_ID;
    492     private long mParentNodeId = ROOT_NODE_ID;
    493     private long mLabelForId = ROOT_NODE_ID;
    494     private long mLabeledById = ROOT_NODE_ID;
    495 
    496     private int mBooleanProperties;
    497     private final Rect mBoundsInParent = new Rect();
    498     private final Rect mBoundsInScreen = new Rect();
    499 
    500     private CharSequence mPackageName;
    501     private CharSequence mClassName;
    502     private CharSequence mText;
    503     private CharSequence mContentDescription;
    504     private String mViewIdResourceName;
    505 
    506     private final SparseLongArray mChildNodeIds = new SparseLongArray();
    507     private int mActions;
    508 
    509     private int mMovementGranularities;
    510 
    511     private int mTextSelectionStart = UNDEFINED;
    512     private int mTextSelectionEnd = UNDEFINED;
    513     private int mInputType = InputType.TYPE_NULL;
    514     private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
    515 
    516     private Bundle mExtras;
    517 
    518     private int mConnectionId = UNDEFINED;
    519 
    520     private RangeInfo mRangeInfo;
    521     private CollectionInfo mCollectionInfo;
    522     private CollectionItemInfo mCollectionItemInfo;
    523 
    524     /**
    525      * Hide constructor from clients.
    526      */
    527     private AccessibilityNodeInfo() {
    528         /* do nothing */
    529     }
    530 
    531     /**
    532      * Sets the source.
    533      * <p>
    534      *   <strong>Note:</strong> Cannot be called from an
    535      *   {@link android.accessibilityservice.AccessibilityService}.
    536      *   This class is made immutable before being delivered to an AccessibilityService.
    537      * </p>
    538      *
    539      * @param source The info source.
    540      */
    541     public void setSource(View source) {
    542         setSource(source, UNDEFINED);
    543     }
    544 
    545     /**
    546      * Sets the source to be a virtual descendant of the given <code>root</code>.
    547      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
    548      * is set as the source.
    549      * <p>
    550      * A virtual descendant is an imaginary View that is reported as a part of the view
    551      * hierarchy for accessibility purposes. This enables custom views that draw complex
    552      * content to report themselves as a tree of virtual views, thus conveying their
    553      * logical structure.
    554      * </p>
    555      * <p>
    556      *   <strong>Note:</strong> Cannot be called from an
    557      *   {@link android.accessibilityservice.AccessibilityService}.
    558      *   This class is made immutable before being delivered to an AccessibilityService.
    559      * </p>
    560      *
    561      * @param root The root of the virtual subtree.
    562      * @param virtualDescendantId The id of the virtual descendant.
    563      */
    564     public void setSource(View root, int virtualDescendantId) {
    565         enforceNotSealed();
    566         mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
    567         final int rootAccessibilityViewId =
    568             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    569         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    570     }
    571 
    572     /**
    573      * Find the view that has the specified focus type. The search starts from
    574      * the view represented by this node info.
    575      *
    576      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
    577      *         {@link #FOCUS_ACCESSIBILITY}.
    578      * @return The node info of the focused view or null.
    579      *
    580      * @see #FOCUS_INPUT
    581      * @see #FOCUS_ACCESSIBILITY
    582      */
    583     public AccessibilityNodeInfo findFocus(int focus) {
    584         enforceSealed();
    585         enforceValidFocusType(focus);
    586         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    587             return null;
    588         }
    589         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
    590                 mSourceNodeId, focus);
    591     }
    592 
    593     /**
    594      * Searches for the nearest view in the specified direction that can take
    595      * the input focus.
    596      *
    597      * @param direction The direction. Can be one of:
    598      *     {@link View#FOCUS_DOWN},
    599      *     {@link View#FOCUS_UP},
    600      *     {@link View#FOCUS_LEFT},
    601      *     {@link View#FOCUS_RIGHT},
    602      *     {@link View#FOCUS_FORWARD},
    603      *     {@link View#FOCUS_BACKWARD}.
    604      *
    605      * @return The node info for the view that can take accessibility focus.
    606      */
    607     public AccessibilityNodeInfo focusSearch(int direction) {
    608         enforceSealed();
    609         enforceValidFocusDirection(direction);
    610         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    611             return null;
    612         }
    613         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
    614                 mSourceNodeId, direction);
    615     }
    616 
    617     /**
    618      * Gets the id of the window from which the info comes from.
    619      *
    620      * @return The window id.
    621      */
    622     public int getWindowId() {
    623         return mWindowId;
    624     }
    625 
    626     /**
    627      * Refreshes this info with the latest state of the view it represents.
    628      * <p>
    629      * <strong>Note:</strong> If this method returns false this info is obsolete
    630      * since it represents a view that is no longer in the view tree and should
    631      * be recycled.
    632      * </p>
    633      *
    634      * @param bypassCache Whether to bypass the cache.
    635      * @return Whether the refresh succeeded.
    636      *
    637      * @hide
    638      */
    639     public boolean refresh(boolean bypassCache) {
    640         enforceSealed();
    641         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    642             return false;
    643         }
    644         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    645         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
    646                 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
    647         if (refreshedInfo == null) {
    648             return false;
    649         }
    650         init(refreshedInfo);
    651         refreshedInfo.recycle();
    652         return true;
    653     }
    654 
    655     /**
    656      * Refreshes this info with the latest state of the view it represents.
    657      * <p>
    658      * <strong>Note:</strong> If this method returns false this info is obsolete
    659      * since it represents a view that is no longer in the view tree and should
    660      * be recycled.
    661      * </p>
    662      * @return Whether the refresh succeeded.
    663      */
    664     public boolean refresh() {
    665         return refresh(false);
    666     }
    667 
    668     /**
    669      * @return The ids of the children.
    670      *
    671      * @hide
    672      */
    673     public SparseLongArray getChildNodeIds() {
    674         return mChildNodeIds;
    675     }
    676 
    677     /**
    678      * Gets the number of children.
    679      *
    680      * @return The child count.
    681      */
    682     public int getChildCount() {
    683         return mChildNodeIds.size();
    684     }
    685 
    686     /**
    687      * Get the child at given index.
    688      * <p>
    689      *   <strong>Note:</strong> It is a client responsibility to recycle the
    690      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    691      *     to avoid creating of multiple instances.
    692      * </p>
    693      *
    694      * @param index The child index.
    695      * @return The child node.
    696      *
    697      * @throws IllegalStateException If called outside of an AccessibilityService.
    698      *
    699      */
    700     public AccessibilityNodeInfo getChild(int index) {
    701         enforceSealed();
    702         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    703             return null;
    704         }
    705         final long childId = mChildNodeIds.get(index);
    706         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    707         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
    708                 childId, false, FLAG_PREFETCH_DESCENDANTS);
    709     }
    710 
    711     /**
    712      * Adds a child.
    713      * <p>
    714      * <strong>Note:</strong> Cannot be called from an
    715      * {@link android.accessibilityservice.AccessibilityService}.
    716      * This class is made immutable before being delivered to an AccessibilityService.
    717      * </p>
    718      *
    719      * @param child The child.
    720      *
    721      * @throws IllegalStateException If called from an AccessibilityService.
    722      */
    723     public void addChild(View child) {
    724         addChild(child, UNDEFINED);
    725     }
    726 
    727     /**
    728      * Adds a virtual child which is a descendant of the given <code>root</code>.
    729      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
    730      * is added as a child.
    731      * <p>
    732      * A virtual descendant is an imaginary View that is reported as a part of the view
    733      * hierarchy for accessibility purposes. This enables custom views that draw complex
    734      * content to report them selves as a tree of virtual views, thus conveying their
    735      * logical structure.
    736      * </p>
    737      *
    738      * @param root The root of the virtual subtree.
    739      * @param virtualDescendantId The id of the virtual child.
    740      */
    741     public void addChild(View root, int virtualDescendantId) {
    742         enforceNotSealed();
    743         final int index = mChildNodeIds.size();
    744         final int rootAccessibilityViewId =
    745             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    746         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    747         mChildNodeIds.put(index, childNodeId);
    748     }
    749 
    750     /**
    751      * Gets the actions that can be performed on the node.
    752      *
    753      * @return The bit mask of with actions.
    754      *
    755      * @see AccessibilityNodeInfo#ACTION_FOCUS
    756      * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
    757      * @see AccessibilityNodeInfo#ACTION_SELECT
    758      * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
    759      * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
    760      * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
    761      * @see AccessibilityNodeInfo#ACTION_CLICK
    762      * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
    763      * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    764      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    765      * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
    766      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
    767      * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
    768      * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
    769      */
    770     public int getActions() {
    771         return mActions;
    772     }
    773 
    774     /**
    775      * Adds an action that can be performed on the node.
    776      * <p>
    777      *   <strong>Note:</strong> Cannot be called from an
    778      *   {@link android.accessibilityservice.AccessibilityService}.
    779      *   This class is made immutable before being delivered to an AccessibilityService.
    780      * </p>
    781      *
    782      * @param action The action.
    783      *
    784      * @throws IllegalStateException If called from an AccessibilityService.
    785      */
    786     public void addAction(int action) {
    787         enforceNotSealed();
    788         mActions |= action;
    789     }
    790 
    791     /**
    792      * Sets the movement granularities for traversing the text of this node.
    793      * <p>
    794      *   <strong>Note:</strong> Cannot be called from an
    795      *   {@link android.accessibilityservice.AccessibilityService}.
    796      *   This class is made immutable before being delivered to an AccessibilityService.
    797      * </p>
    798      *
    799      * @param granularities The bit mask with granularities.
    800      *
    801      * @throws IllegalStateException If called from an AccessibilityService.
    802      */
    803     public void setMovementGranularities(int granularities) {
    804         enforceNotSealed();
    805         mMovementGranularities = granularities;
    806     }
    807 
    808     /**
    809      * Gets the movement granularities for traversing the text of this node.
    810      *
    811      * @return The bit mask with granularities.
    812      */
    813     public int getMovementGranularities() {
    814         return mMovementGranularities;
    815     }
    816 
    817     /**
    818      * Performs an action on the node.
    819      * <p>
    820      *   <strong>Note:</strong> An action can be performed only if the request is made
    821      *   from an {@link android.accessibilityservice.AccessibilityService}.
    822      * </p>
    823      *
    824      * @param action The action to perform.
    825      * @return True if the action was performed.
    826      *
    827      * @throws IllegalStateException If called outside of an AccessibilityService.
    828      */
    829     public boolean performAction(int action) {
    830         enforceSealed();
    831         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    832             return false;
    833         }
    834         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    835         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
    836                 action, null);
    837     }
    838 
    839     /**
    840      * Performs an action on the node.
    841      * <p>
    842      *   <strong>Note:</strong> An action can be performed only if the request is made
    843      *   from an {@link android.accessibilityservice.AccessibilityService}.
    844      * </p>
    845      *
    846      * @param action The action to perform.
    847      * @param arguments A bundle with additional arguments.
    848      * @return True if the action was performed.
    849      *
    850      * @throws IllegalStateException If called outside of an AccessibilityService.
    851      */
    852     public boolean performAction(int action, Bundle arguments) {
    853         enforceSealed();
    854         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    855             return false;
    856         }
    857         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    858         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
    859                 action, arguments);
    860     }
    861 
    862     /**
    863      * Finds {@link AccessibilityNodeInfo}s by text. The match is case
    864      * insensitive containment. The search is relative to this info i.e.
    865      * this info is the root of the traversed tree.
    866      *
    867      * <p>
    868      *   <strong>Note:</strong> It is a client responsibility to recycle the
    869      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    870      *     to avoid creating of multiple instances.
    871      * </p>
    872      *
    873      * @param text The searched text.
    874      * @return A list of node info.
    875      */
    876     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
    877         enforceSealed();
    878         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    879             return Collections.emptyList();
    880         }
    881         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    882         return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
    883                 text);
    884     }
    885 
    886     /**
    887      * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
    888      * name where a fully qualified id is of the from "package:id/id_resource_name".
    889      * For example, if the target application's package is "foo.bar" and the id
    890      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
    891      *
    892      * <p>
    893      *   <strong>Note:</strong> It is a client responsibility to recycle the
    894      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    895      *     to avoid creating of multiple instances.
    896      * </p>
    897      * <p>
    898      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
    899      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
    900      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
    901      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
    902      * </p>
    903      *
    904      * @param viewId The fully qualified resource name of the view id to find.
    905      * @return A list of node info.
    906      */
    907     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
    908         enforceSealed();
    909         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    910             return Collections.emptyList();
    911         }
    912         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    913         return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
    914                 viewId);
    915     }
    916 
    917     /**
    918      * Gets the parent.
    919      * <p>
    920      *   <strong>Note:</strong> It is a client responsibility to recycle the
    921      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    922      *     to avoid creating of multiple instances.
    923      * </p>
    924      *
    925      * @return The parent.
    926      */
    927     public AccessibilityNodeInfo getParent() {
    928         enforceSealed();
    929         if (!canPerformRequestOverConnection(mParentNodeId)) {
    930             return null;
    931         }
    932         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    933         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
    934                 mWindowId, mParentNodeId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
    935     }
    936 
    937     /**
    938      * @return The parent node id.
    939      *
    940      * @hide
    941      */
    942     public long getParentNodeId() {
    943         return mParentNodeId;
    944     }
    945 
    946     /**
    947      * Sets the parent.
    948      * <p>
    949      *   <strong>Note:</strong> Cannot be called from an
    950      *   {@link android.accessibilityservice.AccessibilityService}.
    951      *   This class is made immutable before being delivered to an AccessibilityService.
    952      * </p>
    953      *
    954      * @param parent The parent.
    955      *
    956      * @throws IllegalStateException If called from an AccessibilityService.
    957      */
    958     public void setParent(View parent) {
    959         setParent(parent, UNDEFINED);
    960     }
    961 
    962     /**
    963      * Sets the parent to be a virtual descendant of the given <code>root</code>.
    964      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
    965      * is set as the parent.
    966      * <p>
    967      * A virtual descendant is an imaginary View that is reported as a part of the view
    968      * hierarchy for accessibility purposes. This enables custom views that draw complex
    969      * content to report them selves as a tree of virtual views, thus conveying their
    970      * logical structure.
    971      * </p>
    972      * <p>
    973      *   <strong>Note:</strong> Cannot be called from an
    974      *   {@link android.accessibilityservice.AccessibilityService}.
    975      *   This class is made immutable before being delivered to an AccessibilityService.
    976      * </p>
    977      *
    978      * @param root The root of the virtual subtree.
    979      * @param virtualDescendantId The id of the virtual descendant.
    980      */
    981     public void setParent(View root, int virtualDescendantId) {
    982         enforceNotSealed();
    983         final int rootAccessibilityViewId =
    984             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    985         mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    986     }
    987 
    988     /**
    989      * Gets the node bounds in parent coordinates.
    990      *
    991      * @param outBounds The output node bounds.
    992      */
    993     public void getBoundsInParent(Rect outBounds) {
    994         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
    995                 mBoundsInParent.right, mBoundsInParent.bottom);
    996     }
    997 
    998     /**
    999      * Sets the node bounds in parent coordinates.
   1000      * <p>
   1001      *   <strong>Note:</strong> Cannot be called from an
   1002      *   {@link android.accessibilityservice.AccessibilityService}.
   1003      *   This class is made immutable before being delivered to an AccessibilityService.
   1004      * </p>
   1005      *
   1006      * @param bounds The node bounds.
   1007      *
   1008      * @throws IllegalStateException If called from an AccessibilityService.
   1009      */
   1010     public void setBoundsInParent(Rect bounds) {
   1011         enforceNotSealed();
   1012         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1013     }
   1014 
   1015     /**
   1016      * Gets the node bounds in screen coordinates.
   1017      *
   1018      * @param outBounds The output node bounds.
   1019      */
   1020     public void getBoundsInScreen(Rect outBounds) {
   1021         outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
   1022                 mBoundsInScreen.right, mBoundsInScreen.bottom);
   1023     }
   1024 
   1025     /**
   1026      * Sets the node bounds in screen coordinates.
   1027      * <p>
   1028      *   <strong>Note:</strong> Cannot be called from an
   1029      *   {@link android.accessibilityservice.AccessibilityService}.
   1030      *   This class is made immutable before being delivered to an AccessibilityService.
   1031      * </p>
   1032      *
   1033      * @param bounds The node bounds.
   1034      *
   1035      * @throws IllegalStateException If called from an AccessibilityService.
   1036      */
   1037     public void setBoundsInScreen(Rect bounds) {
   1038         enforceNotSealed();
   1039         mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
   1040     }
   1041 
   1042     /**
   1043      * Gets whether this node is checkable.
   1044      *
   1045      * @return True if the node is checkable.
   1046      */
   1047     public boolean isCheckable() {
   1048         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
   1049     }
   1050 
   1051     /**
   1052      * Sets whether this node is checkable.
   1053      * <p>
   1054      *   <strong>Note:</strong> Cannot be called from an
   1055      *   {@link android.accessibilityservice.AccessibilityService}.
   1056      *   This class is made immutable before being delivered to an AccessibilityService.
   1057      * </p>
   1058      *
   1059      * @param checkable True if the node is checkable.
   1060      *
   1061      * @throws IllegalStateException If called from an AccessibilityService.
   1062      */
   1063     public void setCheckable(boolean checkable) {
   1064         setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
   1065     }
   1066 
   1067     /**
   1068      * Gets whether this node is checked.
   1069      *
   1070      * @return True if the node is checked.
   1071      */
   1072     public boolean isChecked() {
   1073         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
   1074     }
   1075 
   1076     /**
   1077      * Sets whether this node is checked.
   1078      * <p>
   1079      *   <strong>Note:</strong> Cannot be called from an
   1080      *   {@link android.accessibilityservice.AccessibilityService}.
   1081      *   This class is made immutable before being delivered to an AccessibilityService.
   1082      * </p>
   1083      *
   1084      * @param checked True if the node is checked.
   1085      *
   1086      * @throws IllegalStateException If called from an AccessibilityService.
   1087      */
   1088     public void setChecked(boolean checked) {
   1089         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
   1090     }
   1091 
   1092     /**
   1093      * Gets whether this node is focusable.
   1094      *
   1095      * @return True if the node is focusable.
   1096      */
   1097     public boolean isFocusable() {
   1098         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
   1099     }
   1100 
   1101     /**
   1102      * Sets whether this node is focusable.
   1103      * <p>
   1104      *   <strong>Note:</strong> Cannot be called from an
   1105      *   {@link android.accessibilityservice.AccessibilityService}.
   1106      *   This class is made immutable before being delivered to an AccessibilityService.
   1107      * </p>
   1108      *
   1109      * @param focusable True if the node is focusable.
   1110      *
   1111      * @throws IllegalStateException If called from an AccessibilityService.
   1112      */
   1113     public void setFocusable(boolean focusable) {
   1114         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
   1115     }
   1116 
   1117     /**
   1118      * Gets whether this node is focused.
   1119      *
   1120      * @return True if the node is focused.
   1121      */
   1122     public boolean isFocused() {
   1123         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
   1124     }
   1125 
   1126     /**
   1127      * Sets whether this node is focused.
   1128      * <p>
   1129      *   <strong>Note:</strong> Cannot be called from an
   1130      *   {@link android.accessibilityservice.AccessibilityService}.
   1131      *   This class is made immutable before being delivered to an AccessibilityService.
   1132      * </p>
   1133      *
   1134      * @param focused True if the node is focused.
   1135      *
   1136      * @throws IllegalStateException If called from an AccessibilityService.
   1137      */
   1138     public void setFocused(boolean focused) {
   1139         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
   1140     }
   1141 
   1142     /**
   1143      * Sets whether this node is visible to the user.
   1144      *
   1145      * @return Whether the node is visible to the user.
   1146      */
   1147     public boolean isVisibleToUser() {
   1148         return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
   1149     }
   1150 
   1151     /**
   1152      * Sets whether this node is visible to the user.
   1153      * <p>
   1154      *   <strong>Note:</strong> Cannot be called from an
   1155      *   {@link android.accessibilityservice.AccessibilityService}.
   1156      *   This class is made immutable before being delivered to an AccessibilityService.
   1157      * </p>
   1158      *
   1159      * @param visibleToUser Whether the node is visible to the user.
   1160      *
   1161      * @throws IllegalStateException If called from an AccessibilityService.
   1162      */
   1163     public void setVisibleToUser(boolean visibleToUser) {
   1164         setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
   1165     }
   1166 
   1167     /**
   1168      * Gets whether this node is accessibility focused.
   1169      *
   1170      * @return True if the node is accessibility focused.
   1171      */
   1172     public boolean isAccessibilityFocused() {
   1173         return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
   1174     }
   1175 
   1176     /**
   1177      * Sets whether this node is accessibility focused.
   1178      * <p>
   1179      *   <strong>Note:</strong> Cannot be called from an
   1180      *   {@link android.accessibilityservice.AccessibilityService}.
   1181      *   This class is made immutable before being delivered to an AccessibilityService.
   1182      * </p>
   1183      *
   1184      * @param focused True if the node is accessibility focused.
   1185      *
   1186      * @throws IllegalStateException If called from an AccessibilityService.
   1187      */
   1188     public void setAccessibilityFocused(boolean focused) {
   1189         setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
   1190     }
   1191 
   1192     /**
   1193      * Gets whether this node is selected.
   1194      *
   1195      * @return True if the node is selected.
   1196      */
   1197     public boolean isSelected() {
   1198         return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
   1199     }
   1200 
   1201     /**
   1202      * Sets whether this node is selected.
   1203      * <p>
   1204      *   <strong>Note:</strong> Cannot be called from an
   1205      *   {@link android.accessibilityservice.AccessibilityService}.
   1206      *   This class is made immutable before being delivered to an AccessibilityService.
   1207      * </p>
   1208      *
   1209      * @param selected True if the node is selected.
   1210      *
   1211      * @throws IllegalStateException If called from an AccessibilityService.
   1212      */
   1213     public void setSelected(boolean selected) {
   1214         setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
   1215     }
   1216 
   1217     /**
   1218      * Gets whether this node is clickable.
   1219      *
   1220      * @return True if the node is clickable.
   1221      */
   1222     public boolean isClickable() {
   1223         return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
   1224     }
   1225 
   1226     /**
   1227      * Sets whether this node is clickable.
   1228      * <p>
   1229      *   <strong>Note:</strong> Cannot be called from an
   1230      *   {@link android.accessibilityservice.AccessibilityService}.
   1231      *   This class is made immutable before being delivered to an AccessibilityService.
   1232      * </p>
   1233      *
   1234      * @param clickable True if the node is clickable.
   1235      *
   1236      * @throws IllegalStateException If called from an AccessibilityService.
   1237      */
   1238     public void setClickable(boolean clickable) {
   1239         setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
   1240     }
   1241 
   1242     /**
   1243      * Gets whether this node is long clickable.
   1244      *
   1245      * @return True if the node is long clickable.
   1246      */
   1247     public boolean isLongClickable() {
   1248         return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
   1249     }
   1250 
   1251     /**
   1252      * Sets whether this node is long clickable.
   1253      * <p>
   1254      *   <strong>Note:</strong> Cannot be called from an
   1255      *   {@link android.accessibilityservice.AccessibilityService}.
   1256      *   This class is made immutable before being delivered to an AccessibilityService.
   1257      * </p>
   1258      *
   1259      * @param longClickable True if the node is long clickable.
   1260      *
   1261      * @throws IllegalStateException If called from an AccessibilityService.
   1262      */
   1263     public void setLongClickable(boolean longClickable) {
   1264         setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
   1265     }
   1266 
   1267     /**
   1268      * Gets whether this node is enabled.
   1269      *
   1270      * @return True if the node is enabled.
   1271      */
   1272     public boolean isEnabled() {
   1273         return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
   1274     }
   1275 
   1276     /**
   1277      * Sets whether this node is enabled.
   1278      * <p>
   1279      *   <strong>Note:</strong> Cannot be called from an
   1280      *   {@link android.accessibilityservice.AccessibilityService}.
   1281      *   This class is made immutable before being delivered to an AccessibilityService.
   1282      * </p>
   1283      *
   1284      * @param enabled True if the node is enabled.
   1285      *
   1286      * @throws IllegalStateException If called from an AccessibilityService.
   1287      */
   1288     public void setEnabled(boolean enabled) {
   1289         setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
   1290     }
   1291 
   1292     /**
   1293      * Gets whether this node is a password.
   1294      *
   1295      * @return True if the node is a password.
   1296      */
   1297     public boolean isPassword() {
   1298         return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
   1299     }
   1300 
   1301     /**
   1302      * Sets whether this node is a password.
   1303      * <p>
   1304      *   <strong>Note:</strong> Cannot be called from an
   1305      *   {@link android.accessibilityservice.AccessibilityService}.
   1306      *   This class is made immutable before being delivered to an AccessibilityService.
   1307      * </p>
   1308      *
   1309      * @param password True if the node is a password.
   1310      *
   1311      * @throws IllegalStateException If called from an AccessibilityService.
   1312      */
   1313     public void setPassword(boolean password) {
   1314         setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
   1315     }
   1316 
   1317     /**
   1318      * Gets if the node is scrollable.
   1319      *
   1320      * @return True if the node is scrollable, false otherwise.
   1321      */
   1322     public boolean isScrollable() {
   1323         return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
   1324     }
   1325 
   1326     /**
   1327      * Sets if the node is scrollable.
   1328      * <p>
   1329      *   <strong>Note:</strong> Cannot be called from an
   1330      *   {@link android.accessibilityservice.AccessibilityService}.
   1331      *   This class is made immutable before being delivered to an AccessibilityService.
   1332      * </p>
   1333      *
   1334      * @param scrollable True if the node is scrollable, false otherwise.
   1335      *
   1336      * @throws IllegalStateException If called from an AccessibilityService.
   1337      */
   1338     public void setScrollable(boolean scrollable) {
   1339         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
   1340     }
   1341 
   1342     /**
   1343      * Gets if the node is editable.
   1344      *
   1345      * @return True if the node is editable, false otherwise.
   1346      */
   1347     public boolean isEditable() {
   1348         return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
   1349     }
   1350 
   1351     /**
   1352      * Sets whether this node is editable.
   1353      * <p>
   1354      *   <strong>Note:</strong> Cannot be called from an
   1355      *   {@link android.accessibilityservice.AccessibilityService}.
   1356      *   This class is made immutable before being delivered to an AccessibilityService.
   1357      * </p>
   1358      *
   1359      * @param editable True if the node is editable.
   1360      *
   1361      * @throws IllegalStateException If called from an AccessibilityService.
   1362      */
   1363     public void setEditable(boolean editable) {
   1364         setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
   1365     }
   1366 
   1367     /**
   1368      * Gets the collection info if the node is a collection. A collection
   1369      * child is always a collection item.
   1370      *
   1371      * @return The collection info.
   1372      */
   1373     public CollectionInfo getCollectionInfo() {
   1374         return mCollectionInfo;
   1375     }
   1376 
   1377     /**
   1378      * Sets the collection info if the node is a collection. A collection
   1379      * child is always a collection item.
   1380      * <p>
   1381      *   <strong>Note:</strong> Cannot be called from an
   1382      *   {@link android.accessibilityservice.AccessibilityService}.
   1383      *   This class is made immutable before being delivered to an AccessibilityService.
   1384      * </p>
   1385      *
   1386      * @param collectionInfo The collection info.
   1387      */
   1388     public void setCollectionInfo(CollectionInfo collectionInfo) {
   1389         enforceNotSealed();
   1390         mCollectionInfo = collectionInfo;
   1391     }
   1392 
   1393     /**
   1394      * Gets the collection item info if the node is a collection item. A collection
   1395      * item is always a child of a collection.
   1396      *
   1397      * @return The collection item info.
   1398      */
   1399     public CollectionItemInfo getCollectionItemInfo() {
   1400         return mCollectionItemInfo;
   1401     }
   1402 
   1403     /**
   1404      * Sets the collection item info if the node is a collection item. A collection
   1405      * item is always a child of a collection.
   1406      * <p>
   1407      *   <strong>Note:</strong> Cannot be called from an
   1408      *   {@link android.accessibilityservice.AccessibilityService}.
   1409      *   This class is made immutable before being delivered to an AccessibilityService.
   1410      * </p>
   1411      *
   1412      * @return collectionItem True if the node is an item.
   1413      */
   1414     public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
   1415         enforceNotSealed();
   1416         mCollectionItemInfo = collectionItemInfo;
   1417     }
   1418 
   1419     /**
   1420      * Gets the range info if this node is a range.
   1421      *
   1422      * @return The range.
   1423      */
   1424     public RangeInfo getRangeInfo() {
   1425         return mRangeInfo;
   1426     }
   1427 
   1428     /**
   1429      * Sets the range info if this node is a range.
   1430      * <p>
   1431      *   <strong>Note:</strong> Cannot be called from an
   1432      *   {@link android.accessibilityservice.AccessibilityService}.
   1433      *   This class is made immutable before being delivered to an AccessibilityService.
   1434      * </p>
   1435      *
   1436      * @param rangeInfo The range info.
   1437      */
   1438     public void setRangeInfo(RangeInfo rangeInfo) {
   1439         enforceNotSealed();
   1440         mRangeInfo = rangeInfo;
   1441     }
   1442 
   1443     /**
   1444      * Gets if the content of this node is invalid. For example,
   1445      * a date is not well-formed.
   1446      *
   1447      * @return If the node content is invalid.
   1448      */
   1449     public boolean isContentInvalid() {
   1450         return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
   1451     }
   1452 
   1453     /**
   1454      * Sets if the content of this node is invalid. For example,
   1455      * a date is not well-formed.
   1456      * <p>
   1457      *   <strong>Note:</strong> Cannot be called from an
   1458      *   {@link android.accessibilityservice.AccessibilityService}.
   1459      *   This class is made immutable before being delivered to an AccessibilityService.
   1460      * </p>
   1461      *
   1462      * @param contentInvalid If the node content is invalid.
   1463      */
   1464     public void setContentInvalid(boolean contentInvalid) {
   1465         setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
   1466     }
   1467 
   1468     /**
   1469      * Gets the node's live region mode.
   1470      * <p>
   1471      * A live region is a node that contains information that is important for
   1472      * the user and when it changes the user should be notified. For example,
   1473      * in a login screen with a TextView that displays an "incorrect password"
   1474      * notification, that view should be marked as a live region with mode
   1475      * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
   1476      * <p>
   1477      * It is the responsibility of the accessibility service to monitor
   1478      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
   1479      * changes to live region nodes and their children.
   1480      *
   1481      * @return The live region mode, or
   1482      *         {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
   1483      *         live region.
   1484      * @see android.view.View#getAccessibilityLiveRegion()
   1485      */
   1486     public int getLiveRegion() {
   1487         return mLiveRegion;
   1488     }
   1489 
   1490     /**
   1491      * Sets the node's live region mode.
   1492      * <p>
   1493      * <strong>Note:</strong> Cannot be called from an
   1494      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1495      * made immutable before being delivered to an AccessibilityService.
   1496      *
   1497      * @param mode The live region mode, or
   1498      *        {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
   1499      *        live region.
   1500      * @see android.view.View#setAccessibilityLiveRegion(int)
   1501      */
   1502     public void setLiveRegion(int mode) {
   1503         enforceNotSealed();
   1504         mLiveRegion = mode;
   1505     }
   1506 
   1507     /**
   1508      * Gets if the node is a multi line editable text.
   1509      *
   1510      * @return True if the node is multi line.
   1511      */
   1512     public boolean isMultiLine() {
   1513         return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
   1514     }
   1515 
   1516     /**
   1517      * Sets if the node is a multi line editable text.
   1518      * <p>
   1519      *   <strong>Note:</strong> Cannot be called from an
   1520      *   {@link android.accessibilityservice.AccessibilityService}.
   1521      *   This class is made immutable before being delivered to an AccessibilityService.
   1522      * </p>
   1523      *
   1524      * @param multiLine True if the node is multi line.
   1525      */
   1526     public void setMultiLine(boolean multiLine) {
   1527         setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
   1528     }
   1529 
   1530     /**
   1531      * Gets if this node opens a popup or a dialog.
   1532      *
   1533      * @return If the the node opens a popup.
   1534      */
   1535     public boolean canOpenPopup() {
   1536         return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
   1537     }
   1538 
   1539     /**
   1540      * Sets if this node opens a popup or a dialog.
   1541      * <p>
   1542      *   <strong>Note:</strong> Cannot be called from an
   1543      *   {@link android.accessibilityservice.AccessibilityService}.
   1544      *   This class is made immutable before being delivered to an AccessibilityService.
   1545      * </p>
   1546      *
   1547      * @param opensPopup If the the node opens a popup.
   1548      */
   1549     public void setCanOpenPopup(boolean opensPopup) {
   1550         enforceNotSealed();
   1551         setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
   1552     }
   1553 
   1554     /**
   1555      * Gets if the node can be dismissed.
   1556      *
   1557      * @return If the node can be dismissed.
   1558      */
   1559     public boolean isDismissable() {
   1560         return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
   1561     }
   1562 
   1563     /**
   1564      * Sets if the node can be dismissed.
   1565      * <p>
   1566      *   <strong>Note:</strong> Cannot be called from an
   1567      *   {@link android.accessibilityservice.AccessibilityService}.
   1568      *   This class is made immutable before being delivered to an AccessibilityService.
   1569      * </p>
   1570      *
   1571      * @param dismissable If the node can be dismissed.
   1572      */
   1573     public void setDismissable(boolean dismissable) {
   1574         setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
   1575     }
   1576 
   1577     /**
   1578      * Gets the package this node comes from.
   1579      *
   1580      * @return The package name.
   1581      */
   1582     public CharSequence getPackageName() {
   1583         return mPackageName;
   1584     }
   1585 
   1586     /**
   1587      * Sets the package this node comes from.
   1588      * <p>
   1589      *   <strong>Note:</strong> Cannot be called from an
   1590      *   {@link android.accessibilityservice.AccessibilityService}.
   1591      *   This class is made immutable before being delivered to an AccessibilityService.
   1592      * </p>
   1593      *
   1594      * @param packageName The package name.
   1595      *
   1596      * @throws IllegalStateException If called from an AccessibilityService.
   1597      */
   1598     public void setPackageName(CharSequence packageName) {
   1599         enforceNotSealed();
   1600         mPackageName = packageName;
   1601     }
   1602 
   1603     /**
   1604      * Gets the class this node comes from.
   1605      *
   1606      * @return The class name.
   1607      */
   1608     public CharSequence getClassName() {
   1609         return mClassName;
   1610     }
   1611 
   1612     /**
   1613      * Sets the class this node comes from.
   1614      * <p>
   1615      *   <strong>Note:</strong> Cannot be called from an
   1616      *   {@link android.accessibilityservice.AccessibilityService}.
   1617      *   This class is made immutable before being delivered to an AccessibilityService.
   1618      * </p>
   1619      *
   1620      * @param className The class name.
   1621      *
   1622      * @throws IllegalStateException If called from an AccessibilityService.
   1623      */
   1624     public void setClassName(CharSequence className) {
   1625         enforceNotSealed();
   1626         mClassName = className;
   1627     }
   1628 
   1629     /**
   1630      * Gets the text of this node.
   1631      *
   1632      * @return The text.
   1633      */
   1634     public CharSequence getText() {
   1635         return mText;
   1636     }
   1637 
   1638     /**
   1639      * Sets the text of this node.
   1640      * <p>
   1641      *   <strong>Note:</strong> Cannot be called from an
   1642      *   {@link android.accessibilityservice.AccessibilityService}.
   1643      *   This class is made immutable before being delivered to an AccessibilityService.
   1644      * </p>
   1645      *
   1646      * @param text The text.
   1647      *
   1648      * @throws IllegalStateException If called from an AccessibilityService.
   1649      */
   1650     public void setText(CharSequence text) {
   1651         enforceNotSealed();
   1652         mText = text;
   1653     }
   1654 
   1655     /**
   1656      * Gets the content description of this node.
   1657      *
   1658      * @return The content description.
   1659      */
   1660     public CharSequence getContentDescription() {
   1661         return mContentDescription;
   1662     }
   1663 
   1664     /**
   1665      * Sets the content description of this node.
   1666      * <p>
   1667      *   <strong>Note:</strong> Cannot be called from an
   1668      *   {@link android.accessibilityservice.AccessibilityService}.
   1669      *   This class is made immutable before being delivered to an AccessibilityService.
   1670      * </p>
   1671      *
   1672      * @param contentDescription The content description.
   1673      *
   1674      * @throws IllegalStateException If called from an AccessibilityService.
   1675      */
   1676     public void setContentDescription(CharSequence contentDescription) {
   1677         enforceNotSealed();
   1678         mContentDescription = contentDescription;
   1679     }
   1680 
   1681     /**
   1682      * Sets the view for which the view represented by this info serves as a
   1683      * label for accessibility purposes.
   1684      *
   1685      * @param labeled The view for which this info serves as a label.
   1686      */
   1687     public void setLabelFor(View labeled) {
   1688         setLabelFor(labeled, UNDEFINED);
   1689     }
   1690 
   1691     /**
   1692      * Sets the view for which the view represented by this info serves as a
   1693      * label for accessibility purposes. If <code>virtualDescendantId</code>
   1694      * is {@link View#NO_ID} the root is set as the labeled.
   1695      * <p>
   1696      * A virtual descendant is an imaginary View that is reported as a part of the view
   1697      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1698      * content to report themselves as a tree of virtual views, thus conveying their
   1699      * logical structure.
   1700      * </p>
   1701      * <p>
   1702      *   <strong>Note:</strong> Cannot be called from an
   1703      *   {@link android.accessibilityservice.AccessibilityService}.
   1704      *   This class is made immutable before being delivered to an AccessibilityService.
   1705      * </p>
   1706      *
   1707      * @param root The root whose virtual descendant serves as a label.
   1708      * @param virtualDescendantId The id of the virtual descendant.
   1709      */
   1710     public void setLabelFor(View root, int virtualDescendantId) {
   1711         enforceNotSealed();
   1712         final int rootAccessibilityViewId = (root != null)
   1713                 ? root.getAccessibilityViewId() : UNDEFINED;
   1714         mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1715     }
   1716 
   1717     /**
   1718      * Gets the node info for which the view represented by this info serves as
   1719      * a label for accessibility purposes.
   1720      * <p>
   1721      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1722      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1723      *     to avoid creating of multiple instances.
   1724      * </p>
   1725      *
   1726      * @return The labeled info.
   1727      */
   1728     public AccessibilityNodeInfo getLabelFor() {
   1729         enforceSealed();
   1730         if (!canPerformRequestOverConnection(mLabelForId)) {
   1731             return null;
   1732         }
   1733         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1734         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
   1735                 mWindowId, mLabelForId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
   1736     }
   1737 
   1738     /**
   1739      * Sets the view which serves as the label of the view represented by
   1740      * this info for accessibility purposes.
   1741      *
   1742      * @param label The view that labels this node's source.
   1743      */
   1744     public void setLabeledBy(View label) {
   1745         setLabeledBy(label, UNDEFINED);
   1746     }
   1747 
   1748     /**
   1749      * Sets the view which serves as the label of the view represented by
   1750      * this info for accessibility purposes. If <code>virtualDescendantId</code>
   1751      * is {@link View#NO_ID} the root is set as the label.
   1752      * <p>
   1753      * A virtual descendant is an imaginary View that is reported as a part of the view
   1754      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1755      * content to report themselves as a tree of virtual views, thus conveying their
   1756      * logical structure.
   1757      * </p>
   1758      * <p>
   1759      *   <strong>Note:</strong> Cannot be called from an
   1760      *   {@link android.accessibilityservice.AccessibilityService}.
   1761      *   This class is made immutable before being delivered to an AccessibilityService.
   1762      * </p>
   1763      *
   1764      * @param root The root whose virtual descendant labels this node's source.
   1765      * @param virtualDescendantId The id of the virtual descendant.
   1766      */
   1767     public void setLabeledBy(View root, int virtualDescendantId) {
   1768         enforceNotSealed();
   1769         final int rootAccessibilityViewId = (root != null)
   1770                 ? root.getAccessibilityViewId() : UNDEFINED;
   1771         mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1772     }
   1773 
   1774     /**
   1775      * Gets the node info which serves as the label of the view represented by
   1776      * this info for accessibility purposes.
   1777      * <p>
   1778      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1779      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1780      *     to avoid creating of multiple instances.
   1781      * </p>
   1782      *
   1783      * @return The label.
   1784      */
   1785     public AccessibilityNodeInfo getLabeledBy() {
   1786         enforceSealed();
   1787         if (!canPerformRequestOverConnection(mLabeledById)) {
   1788             return null;
   1789         }
   1790         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1791         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
   1792                 mWindowId, mLabeledById, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
   1793     }
   1794 
   1795     /**
   1796      * Sets the fully qualified resource name of the source view's id.
   1797      *
   1798      * <p>
   1799      *   <strong>Note:</strong> Cannot be called from an
   1800      *   {@link android.accessibilityservice.AccessibilityService}.
   1801      *   This class is made immutable before being delivered to an AccessibilityService.
   1802      * </p>
   1803      *
   1804      * @param viewIdResName The id resource name.
   1805      */
   1806     public void setViewIdResourceName(String viewIdResName) {
   1807         enforceNotSealed();
   1808         mViewIdResourceName = viewIdResName;
   1809     }
   1810 
   1811     /**
   1812      * Gets the fully qualified resource name of the source view's id.
   1813      *
   1814      * <p>
   1815      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   1816      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
   1817      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
   1818      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   1819      * </p>
   1820 
   1821      * @return The id resource name.
   1822      */
   1823     public String getViewIdResourceName() {
   1824         return mViewIdResourceName;
   1825     }
   1826 
   1827     /**
   1828      * Gets the text selection start.
   1829      *
   1830      * @return The text selection start if there is selection or -1.
   1831      */
   1832     public int getTextSelectionStart() {
   1833         return mTextSelectionStart;
   1834     }
   1835 
   1836     /**
   1837      * Gets the text selection end.
   1838      *
   1839      * @return The text selection end if there is selection or -1.
   1840      */
   1841     public int getTextSelectionEnd() {
   1842         return mTextSelectionEnd;
   1843     }
   1844 
   1845     /**
   1846      * Sets the text selection start and end.
   1847      * <p>
   1848      *   <strong>Note:</strong> Cannot be called from an
   1849      *   {@link android.accessibilityservice.AccessibilityService}.
   1850      *   This class is made immutable before being delivered to an AccessibilityService.
   1851      * </p>
   1852      *
   1853      * @param start The text selection start.
   1854      * @param end The text selection end.
   1855      *
   1856      * @throws IllegalStateException If called from an AccessibilityService.
   1857      */
   1858     public void setTextSelection(int start, int end) {
   1859         enforceNotSealed();
   1860         mTextSelectionStart = start;
   1861         mTextSelectionEnd = end;
   1862     }
   1863 
   1864     /**
   1865      * Gets the input type of the source as defined by {@link InputType}.
   1866      *
   1867      * @return The input type.
   1868      */
   1869     public int getInputType() {
   1870         return mInputType;
   1871     }
   1872 
   1873     /**
   1874      * Sets the input type of the source as defined by {@link InputType}.
   1875      * <p>
   1876      *   <strong>Note:</strong> Cannot be called from an
   1877      *   {@link android.accessibilityservice.AccessibilityService}.
   1878      *   This class is made immutable before being delivered to an
   1879      *   AccessibilityService.
   1880      * </p>
   1881      *
   1882      * @param inputType The input type.
   1883      *
   1884      * @throws IllegalStateException If called from an AccessibilityService.
   1885      */
   1886     public void setInputType(int inputType) {
   1887         enforceNotSealed();
   1888         mInputType = inputType;
   1889     }
   1890 
   1891     /**
   1892      * Gets an optional bundle with extra data. The bundle
   1893      * is lazily created and never <code>null</code>.
   1894      * <p>
   1895      * <strong>Note:</strong> It is recommended to use the package
   1896      * name of your application as a prefix for the keys to avoid
   1897      * collisions which may confuse an accessibility service if the
   1898      * same key has different meaning when emitted from different
   1899      * applications.
   1900      * </p>
   1901      *
   1902      * @return The bundle.
   1903      */
   1904     public Bundle getExtras() {
   1905         if (mExtras == null) {
   1906             mExtras = new Bundle();
   1907         }
   1908         return mExtras;
   1909     }
   1910 
   1911     /**
   1912      * Gets the value of a boolean property.
   1913      *
   1914      * @param property The property.
   1915      * @return The value.
   1916      */
   1917     private boolean getBooleanProperty(int property) {
   1918         return (mBooleanProperties & property) != 0;
   1919     }
   1920 
   1921     /**
   1922      * Sets a boolean property.
   1923      *
   1924      * @param property The property.
   1925      * @param value The value.
   1926      *
   1927      * @throws IllegalStateException If called from an AccessibilityService.
   1928      */
   1929     private void setBooleanProperty(int property, boolean value) {
   1930         enforceNotSealed();
   1931         if (value) {
   1932             mBooleanProperties |= property;
   1933         } else {
   1934             mBooleanProperties &= ~property;
   1935         }
   1936     }
   1937 
   1938     /**
   1939      * Sets the unique id of the IAccessibilityServiceConnection over which
   1940      * this instance can send requests to the system.
   1941      *
   1942      * @param connectionId The connection id.
   1943      *
   1944      * @hide
   1945      */
   1946     public void setConnectionId(int connectionId) {
   1947         enforceNotSealed();
   1948         mConnectionId = connectionId;
   1949     }
   1950 
   1951     /**
   1952      * {@inheritDoc}
   1953      */
   1954     public int describeContents() {
   1955         return 0;
   1956     }
   1957 
   1958     /**
   1959      * Gets the id of the source node.
   1960      *
   1961      * @return The id.
   1962      *
   1963      * @hide
   1964      */
   1965     public long getSourceNodeId() {
   1966         return mSourceNodeId;
   1967     }
   1968 
   1969     /**
   1970      * Sets if this instance is sealed.
   1971      *
   1972      * @param sealed Whether is sealed.
   1973      *
   1974      * @hide
   1975      */
   1976     public void setSealed(boolean sealed) {
   1977         mSealed = sealed;
   1978     }
   1979 
   1980     /**
   1981      * Gets if this instance is sealed.
   1982      *
   1983      * @return Whether is sealed.
   1984      *
   1985      * @hide
   1986      */
   1987     public boolean isSealed() {
   1988         return mSealed;
   1989     }
   1990 
   1991     /**
   1992      * Enforces that this instance is sealed.
   1993      *
   1994      * @throws IllegalStateException If this instance is not sealed.
   1995      *
   1996      * @hide
   1997      */
   1998     protected void enforceSealed() {
   1999         if (!isSealed()) {
   2000             throw new IllegalStateException("Cannot perform this "
   2001                     + "action on a not sealed instance.");
   2002         }
   2003     }
   2004 
   2005     private void enforceValidFocusDirection(int direction) {
   2006         switch (direction) {
   2007             case View.FOCUS_DOWN:
   2008             case View.FOCUS_UP:
   2009             case View.FOCUS_LEFT:
   2010             case View.FOCUS_RIGHT:
   2011             case View.FOCUS_FORWARD:
   2012             case View.FOCUS_BACKWARD:
   2013                 return;
   2014             default:
   2015                 throw new IllegalArgumentException("Unknown direction: " + direction);
   2016         }
   2017     }
   2018 
   2019     private void enforceValidFocusType(int focusType) {
   2020         switch (focusType) {
   2021             case FOCUS_INPUT:
   2022             case FOCUS_ACCESSIBILITY:
   2023                 return;
   2024             default:
   2025                 throw new IllegalArgumentException("Unknown focus type: " + focusType);
   2026         }
   2027     }
   2028 
   2029     /**
   2030      * Enforces that this instance is not sealed.
   2031      *
   2032      * @throws IllegalStateException If this instance is sealed.
   2033      *
   2034      * @hide
   2035      */
   2036     protected void enforceNotSealed() {
   2037         if (isSealed()) {
   2038             throw new IllegalStateException("Cannot perform this "
   2039                     + "action on a sealed instance.");
   2040         }
   2041     }
   2042 
   2043     /**
   2044      * Returns a cached instance if such is available otherwise a new one
   2045      * and sets the source.
   2046      *
   2047      * @param source The source view.
   2048      * @return An instance.
   2049      *
   2050      * @see #setSource(View)
   2051      */
   2052     public static AccessibilityNodeInfo obtain(View source) {
   2053         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2054         info.setSource(source);
   2055         return info;
   2056     }
   2057 
   2058     /**
   2059      * Returns a cached instance if such is available otherwise a new one
   2060      * and sets the source.
   2061      *
   2062      * @param root The root of the virtual subtree.
   2063      * @param virtualDescendantId The id of the virtual descendant.
   2064      * @return An instance.
   2065      *
   2066      * @see #setSource(View, int)
   2067      */
   2068     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
   2069         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2070         info.setSource(root, virtualDescendantId);
   2071         return info;
   2072     }
   2073 
   2074     /**
   2075      * Returns a cached instance if such is available otherwise a new one.
   2076      *
   2077      * @return An instance.
   2078      */
   2079     public static AccessibilityNodeInfo obtain() {
   2080         AccessibilityNodeInfo info = sPool.acquire();
   2081         return (info != null) ? info : new AccessibilityNodeInfo();
   2082     }
   2083 
   2084     /**
   2085      * Returns a cached instance if such is available or a new one is
   2086      * create. The returned instance is initialized from the given
   2087      * <code>info</code>.
   2088      *
   2089      * @param info The other info.
   2090      * @return An instance.
   2091      */
   2092     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
   2093         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
   2094         infoClone.init(info);
   2095         return infoClone;
   2096     }
   2097 
   2098     /**
   2099      * Return an instance back to be reused.
   2100      * <p>
   2101      * <strong>Note:</strong> You must not touch the object after calling this function.
   2102      *
   2103      * @throws IllegalStateException If the info is already recycled.
   2104      */
   2105     public void recycle() {
   2106         clear();
   2107         sPool.release(this);
   2108     }
   2109 
   2110     /**
   2111      * {@inheritDoc}
   2112      * <p>
   2113      *   <strong>Note:</strong> After the instance is written to a parcel it
   2114      *      is recycled. You must not touch the object after calling this function.
   2115      * </p>
   2116      */
   2117     public void writeToParcel(Parcel parcel, int flags) {
   2118         parcel.writeInt(isSealed() ? 1 : 0);
   2119         parcel.writeLong(mSourceNodeId);
   2120         parcel.writeInt(mWindowId);
   2121         parcel.writeLong(mParentNodeId);
   2122         parcel.writeLong(mLabelForId);
   2123         parcel.writeLong(mLabeledById);
   2124         parcel.writeInt(mConnectionId);
   2125 
   2126         SparseLongArray childIds = mChildNodeIds;
   2127         final int childIdsSize = childIds.size();
   2128         parcel.writeInt(childIdsSize);
   2129         for (int i = 0; i < childIdsSize; i++) {
   2130             parcel.writeLong(childIds.valueAt(i));
   2131         }
   2132 
   2133         parcel.writeInt(mBoundsInParent.top);
   2134         parcel.writeInt(mBoundsInParent.bottom);
   2135         parcel.writeInt(mBoundsInParent.left);
   2136         parcel.writeInt(mBoundsInParent.right);
   2137 
   2138         parcel.writeInt(mBoundsInScreen.top);
   2139         parcel.writeInt(mBoundsInScreen.bottom);
   2140         parcel.writeInt(mBoundsInScreen.left);
   2141         parcel.writeInt(mBoundsInScreen.right);
   2142 
   2143         parcel.writeInt(mActions);
   2144 
   2145         parcel.writeInt(mMovementGranularities);
   2146 
   2147         parcel.writeInt(mBooleanProperties);
   2148 
   2149         parcel.writeCharSequence(mPackageName);
   2150         parcel.writeCharSequence(mClassName);
   2151         parcel.writeCharSequence(mText);
   2152         parcel.writeCharSequence(mContentDescription);
   2153         parcel.writeString(mViewIdResourceName);
   2154 
   2155         parcel.writeInt(mTextSelectionStart);
   2156         parcel.writeInt(mTextSelectionEnd);
   2157         parcel.writeInt(mInputType);
   2158         parcel.writeInt(mLiveRegion);
   2159 
   2160         if (mExtras != null) {
   2161             parcel.writeInt(1);
   2162             parcel.writeBundle(mExtras);
   2163         } else {
   2164             parcel.writeInt(0);
   2165         }
   2166 
   2167         if (mRangeInfo != null) {
   2168             parcel.writeInt(1);
   2169             parcel.writeInt(mRangeInfo.getType());
   2170             parcel.writeFloat(mRangeInfo.getMin());
   2171             parcel.writeFloat(mRangeInfo.getMax());
   2172             parcel.writeFloat(mRangeInfo.getCurrent());
   2173         } else {
   2174             parcel.writeInt(0);
   2175         }
   2176 
   2177         if (mCollectionInfo != null) {
   2178             parcel.writeInt(1);
   2179             parcel.writeInt(mCollectionInfo.getRowCount());
   2180             parcel.writeInt(mCollectionInfo.getColumnCount());
   2181             parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
   2182         } else {
   2183             parcel.writeInt(0);
   2184         }
   2185 
   2186         if (mCollectionItemInfo != null) {
   2187             parcel.writeInt(1);
   2188             parcel.writeInt(mCollectionItemInfo.getColumnIndex());
   2189             parcel.writeInt(mCollectionItemInfo.getColumnSpan());
   2190             parcel.writeInt(mCollectionItemInfo.getRowIndex());
   2191             parcel.writeInt(mCollectionItemInfo.getRowSpan());
   2192             parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
   2193         } else {
   2194             parcel.writeInt(0);
   2195         }
   2196 
   2197         // Since instances of this class are fetched via synchronous i.e. blocking
   2198         // calls in IPCs we always recycle as soon as the instance is marshaled.
   2199         recycle();
   2200     }
   2201 
   2202     /**
   2203      * Initializes this instance from another one.
   2204      *
   2205      * @param other The other instance.
   2206      */
   2207     private void init(AccessibilityNodeInfo other) {
   2208         mSealed = other.mSealed;
   2209         mSourceNodeId = other.mSourceNodeId;
   2210         mParentNodeId = other.mParentNodeId;
   2211         mLabelForId = other.mLabelForId;
   2212         mLabeledById = other.mLabeledById;
   2213         mWindowId = other.mWindowId;
   2214         mConnectionId = other.mConnectionId;
   2215         mBoundsInParent.set(other.mBoundsInParent);
   2216         mBoundsInScreen.set(other.mBoundsInScreen);
   2217         mPackageName = other.mPackageName;
   2218         mClassName = other.mClassName;
   2219         mText = other.mText;
   2220         mContentDescription = other.mContentDescription;
   2221         mViewIdResourceName = other.mViewIdResourceName;
   2222         mActions= other.mActions;
   2223         mBooleanProperties = other.mBooleanProperties;
   2224         mMovementGranularities = other.mMovementGranularities;
   2225         final int otherChildIdCount = other.mChildNodeIds.size();
   2226         for (int i = 0; i < otherChildIdCount; i++) {
   2227             mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
   2228         }
   2229         mTextSelectionStart = other.mTextSelectionStart;
   2230         mTextSelectionEnd = other.mTextSelectionEnd;
   2231         mInputType = other.mInputType;
   2232         mLiveRegion = other.mLiveRegion;
   2233         if (other.mExtras != null && !other.mExtras.isEmpty()) {
   2234             getExtras().putAll(other.mExtras);
   2235         }
   2236         mRangeInfo = (other.mRangeInfo != null)
   2237                 ? RangeInfo.obtain(other.mRangeInfo) : null;
   2238         mCollectionInfo = (other.mCollectionInfo != null)
   2239                 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
   2240         mCollectionItemInfo =  (other.mCollectionItemInfo != null)
   2241                 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
   2242     }
   2243 
   2244     /**
   2245      * Creates a new instance from a {@link Parcel}.
   2246      *
   2247      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
   2248      */
   2249     private void initFromParcel(Parcel parcel) {
   2250         mSealed = (parcel.readInt()  == 1);
   2251         mSourceNodeId = parcel.readLong();
   2252         mWindowId = parcel.readInt();
   2253         mParentNodeId = parcel.readLong();
   2254         mLabelForId = parcel.readLong();
   2255         mLabeledById = parcel.readLong();
   2256         mConnectionId = parcel.readInt();
   2257 
   2258         SparseLongArray childIds = mChildNodeIds;
   2259         final int childrenSize = parcel.readInt();
   2260         for (int i = 0; i < childrenSize; i++) {
   2261             final long childId = parcel.readLong();
   2262             childIds.put(i, childId);
   2263         }
   2264 
   2265         mBoundsInParent.top = parcel.readInt();
   2266         mBoundsInParent.bottom = parcel.readInt();
   2267         mBoundsInParent.left = parcel.readInt();
   2268         mBoundsInParent.right = parcel.readInt();
   2269 
   2270         mBoundsInScreen.top = parcel.readInt();
   2271         mBoundsInScreen.bottom = parcel.readInt();
   2272         mBoundsInScreen.left = parcel.readInt();
   2273         mBoundsInScreen.right = parcel.readInt();
   2274 
   2275         mActions = parcel.readInt();
   2276 
   2277         mMovementGranularities = parcel.readInt();
   2278 
   2279         mBooleanProperties = parcel.readInt();
   2280 
   2281         mPackageName = parcel.readCharSequence();
   2282         mClassName = parcel.readCharSequence();
   2283         mText = parcel.readCharSequence();
   2284         mContentDescription = parcel.readCharSequence();
   2285         mViewIdResourceName = parcel.readString();
   2286 
   2287         mTextSelectionStart = parcel.readInt();
   2288         mTextSelectionEnd = parcel.readInt();
   2289 
   2290         mInputType = parcel.readInt();
   2291         mLiveRegion = parcel.readInt();
   2292 
   2293         if (parcel.readInt() == 1) {
   2294             getExtras().putAll(parcel.readBundle());
   2295         }
   2296 
   2297         if (parcel.readInt() == 1) {
   2298             mRangeInfo = RangeInfo.obtain(
   2299                     parcel.readInt(),
   2300                     parcel.readFloat(),
   2301                     parcel.readFloat(),
   2302                     parcel.readFloat());
   2303         }
   2304 
   2305         if (parcel.readInt() == 1) {
   2306             mCollectionInfo = CollectionInfo.obtain(
   2307                     parcel.readInt(),
   2308                     parcel.readInt(),
   2309                     parcel.readInt() == 1);
   2310         }
   2311 
   2312         if (parcel.readInt() == 1) {
   2313             mCollectionItemInfo = CollectionItemInfo.obtain(
   2314                     parcel.readInt(),
   2315                     parcel.readInt(),
   2316                     parcel.readInt(),
   2317                     parcel.readInt(),
   2318                     parcel.readInt() == 1);
   2319         }
   2320     }
   2321 
   2322     /**
   2323      * Clears the state of this instance.
   2324      */
   2325     private void clear() {
   2326         mSealed = false;
   2327         mSourceNodeId = ROOT_NODE_ID;
   2328         mParentNodeId = ROOT_NODE_ID;
   2329         mLabelForId = ROOT_NODE_ID;
   2330         mLabeledById = ROOT_NODE_ID;
   2331         mWindowId = UNDEFINED;
   2332         mConnectionId = UNDEFINED;
   2333         mMovementGranularities = 0;
   2334         mChildNodeIds.clear();
   2335         mBoundsInParent.set(0, 0, 0, 0);
   2336         mBoundsInScreen.set(0, 0, 0, 0);
   2337         mBooleanProperties = 0;
   2338         mPackageName = null;
   2339         mClassName = null;
   2340         mText = null;
   2341         mContentDescription = null;
   2342         mViewIdResourceName = null;
   2343         mActions = 0;
   2344         mTextSelectionStart = UNDEFINED;
   2345         mTextSelectionEnd = UNDEFINED;
   2346         mInputType = InputType.TYPE_NULL;
   2347         mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
   2348         if (mExtras != null) {
   2349             mExtras.clear();
   2350         }
   2351         if (mRangeInfo != null) {
   2352             mRangeInfo.recycle();
   2353             mRangeInfo = null;
   2354         }
   2355         if (mCollectionInfo != null) {
   2356             mCollectionInfo.recycle();
   2357             mCollectionInfo = null;
   2358         }
   2359         if (mCollectionItemInfo != null) {
   2360             mCollectionItemInfo.recycle();
   2361             mCollectionItemInfo = null;
   2362         }
   2363     }
   2364 
   2365     /**
   2366      * Gets the human readable action symbolic name.
   2367      *
   2368      * @param action The action.
   2369      * @return The symbolic name.
   2370      */
   2371     private static String getActionSymbolicName(int action) {
   2372         switch (action) {
   2373             case ACTION_FOCUS:
   2374                 return "ACTION_FOCUS";
   2375             case ACTION_CLEAR_FOCUS:
   2376                 return "ACTION_CLEAR_FOCUS";
   2377             case ACTION_SELECT:
   2378                 return "ACTION_SELECT";
   2379             case ACTION_CLEAR_SELECTION:
   2380                 return "ACTION_CLEAR_SELECTION";
   2381             case ACTION_CLICK:
   2382                 return "ACTION_CLICK";
   2383             case ACTION_LONG_CLICK:
   2384                 return "ACTION_LONG_CLICK";
   2385             case ACTION_ACCESSIBILITY_FOCUS:
   2386                 return "ACTION_ACCESSIBILITY_FOCUS";
   2387             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
   2388                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
   2389             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
   2390                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
   2391             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
   2392                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
   2393             case ACTION_NEXT_HTML_ELEMENT:
   2394                 return "ACTION_NEXT_HTML_ELEMENT";
   2395             case ACTION_PREVIOUS_HTML_ELEMENT:
   2396                 return "ACTION_PREVIOUS_HTML_ELEMENT";
   2397             case ACTION_SCROLL_FORWARD:
   2398                 return "ACTION_SCROLL_FORWARD";
   2399             case ACTION_SCROLL_BACKWARD:
   2400                 return "ACTION_SCROLL_BACKWARD";
   2401             case ACTION_CUT:
   2402                 return "ACTION_CUT";
   2403             case ACTION_COPY:
   2404                 return "ACTION_COPY";
   2405             case ACTION_PASTE:
   2406                 return "ACTION_PASTE";
   2407             case ACTION_SET_SELECTION:
   2408                 return "ACTION_SET_SELECTION";
   2409             default:
   2410                 return"ACTION_UNKNOWN";
   2411         }
   2412     }
   2413 
   2414     /**
   2415      * Gets the human readable movement granularity symbolic name.
   2416      *
   2417      * @param granularity The granularity.
   2418      * @return The symbolic name.
   2419      */
   2420     private static String getMovementGranularitySymbolicName(int granularity) {
   2421         switch (granularity) {
   2422             case MOVEMENT_GRANULARITY_CHARACTER:
   2423                 return "MOVEMENT_GRANULARITY_CHARACTER";
   2424             case MOVEMENT_GRANULARITY_WORD:
   2425                 return "MOVEMENT_GRANULARITY_WORD";
   2426             case MOVEMENT_GRANULARITY_LINE:
   2427                 return "MOVEMENT_GRANULARITY_LINE";
   2428             case MOVEMENT_GRANULARITY_PARAGRAPH:
   2429                 return "MOVEMENT_GRANULARITY_PARAGRAPH";
   2430             case MOVEMENT_GRANULARITY_PAGE:
   2431                 return "MOVEMENT_GRANULARITY_PAGE";
   2432             default:
   2433                 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
   2434         }
   2435     }
   2436 
   2437     private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
   2438         return (mWindowId != UNDEFINED
   2439                 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED
   2440                 && mConnectionId != UNDEFINED);
   2441     }
   2442 
   2443     @Override
   2444     public boolean equals(Object object) {
   2445         if (this == object) {
   2446             return true;
   2447         }
   2448         if (object == null) {
   2449             return false;
   2450         }
   2451         if (getClass() != object.getClass()) {
   2452             return false;
   2453         }
   2454         AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
   2455         if (mSourceNodeId != other.mSourceNodeId) {
   2456             return false;
   2457         }
   2458         if (mWindowId != other.mWindowId) {
   2459             return false;
   2460         }
   2461         return true;
   2462     }
   2463 
   2464     @Override
   2465     public int hashCode() {
   2466         final int prime = 31;
   2467         int result = 1;
   2468         result = prime * result + getAccessibilityViewId(mSourceNodeId);
   2469         result = prime * result + getVirtualDescendantId(mSourceNodeId);
   2470         result = prime * result + mWindowId;
   2471         return result;
   2472     }
   2473 
   2474     @Override
   2475     public String toString() {
   2476         StringBuilder builder = new StringBuilder();
   2477         builder.append(super.toString());
   2478 
   2479         if (DEBUG) {
   2480             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
   2481             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
   2482             builder.append("; mParentNodeId: " + mParentNodeId);
   2483 
   2484             int granularities = mMovementGranularities;
   2485             builder.append("; MovementGranularities: [");
   2486             while (granularities != 0) {
   2487                 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
   2488                 granularities &= ~granularity;
   2489                 builder.append(getMovementGranularitySymbolicName(granularity));
   2490                 if (granularities != 0) {
   2491                     builder.append(", ");
   2492                 }
   2493             }
   2494             builder.append("]");
   2495 
   2496             SparseLongArray childIds = mChildNodeIds;
   2497             builder.append("; childAccessibilityIds: [");
   2498             for (int i = 0, count = childIds.size(); i < count; i++) {
   2499                 builder.append(childIds.valueAt(i));
   2500                 if (i < count - 1) {
   2501                     builder.append(", ");
   2502                 }
   2503             }
   2504             builder.append("]");
   2505         }
   2506 
   2507         builder.append("; boundsInParent: " + mBoundsInParent);
   2508         builder.append("; boundsInScreen: " + mBoundsInScreen);
   2509 
   2510         builder.append("; packageName: ").append(mPackageName);
   2511         builder.append("; className: ").append(mClassName);
   2512         builder.append("; text: ").append(mText);
   2513         builder.append("; contentDescription: ").append(mContentDescription);
   2514         builder.append("; viewIdResName: ").append(mViewIdResourceName);
   2515 
   2516         builder.append("; checkable: ").append(isCheckable());
   2517         builder.append("; checked: ").append(isChecked());
   2518         builder.append("; focusable: ").append(isFocusable());
   2519         builder.append("; focused: ").append(isFocused());
   2520         builder.append("; selected: ").append(isSelected());
   2521         builder.append("; clickable: ").append(isClickable());
   2522         builder.append("; longClickable: ").append(isLongClickable());
   2523         builder.append("; enabled: ").append(isEnabled());
   2524         builder.append("; password: ").append(isPassword());
   2525         builder.append("; scrollable: " + isScrollable());
   2526 
   2527         builder.append("; [");
   2528         for (int actionBits = mActions; actionBits != 0;) {
   2529             final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
   2530             actionBits &= ~action;
   2531             builder.append(getActionSymbolicName(action));
   2532             if (actionBits != 0) {
   2533                 builder.append(", ");
   2534             }
   2535         }
   2536         builder.append("]");
   2537 
   2538         return builder.toString();
   2539     }
   2540 
   2541     /**
   2542      * Class with information if a node is a range. Use
   2543      * {@link RangeInfo#obtain(int, float, float, float) to get an instance.
   2544      */
   2545     public static final class RangeInfo {
   2546         private static final int MAX_POOL_SIZE = 10;
   2547 
   2548         /** Range type: integer. */
   2549         public static final int RANGE_TYPE_INT = 0;
   2550         /** Range type: float. */
   2551         public static final int RANGE_TYPE_FLOAT = 1;
   2552         /** Range type: percent with values from zero to one.*/
   2553         public static final int RANGE_TYPE_PERCENT = 2;
   2554 
   2555         private static final SynchronizedPool<RangeInfo> sPool =
   2556                 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
   2557 
   2558         private int mType;
   2559         private float mMin;
   2560         private float mMax;
   2561         private float mCurrent;
   2562 
   2563         /**
   2564          * Obtains a pooled instance that is a clone of another one.
   2565          *
   2566          * @param other The instance to clone.
   2567          *
   2568          * @hide
   2569          */
   2570         public static RangeInfo obtain(RangeInfo other) {
   2571             return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
   2572         }
   2573 
   2574         /**
   2575          * Obtains a pooled instance.
   2576          *
   2577          * @param type The type of the range.
   2578          * @param min The min value.
   2579          * @param max The max value.
   2580          * @param current The current value.
   2581          */
   2582         public static RangeInfo obtain(int type, float min, float max, float current) {
   2583             RangeInfo info = sPool.acquire();
   2584             return (info != null) ? info : new RangeInfo(type, min, max, current);
   2585         }
   2586 
   2587         /**
   2588          * Creates a new range.
   2589          *
   2590          * @param type The type of the range.
   2591          * @param min The min value.
   2592          * @param max The max value.
   2593          * @param current The current value.
   2594          */
   2595         private RangeInfo(int type, float min, float max, float current) {
   2596             mType = type;
   2597             mMin = min;
   2598             mMax = max;
   2599             mCurrent = current;
   2600         }
   2601 
   2602         /**
   2603          * Gets the range type.
   2604          *
   2605          * @return The range type.
   2606          *
   2607          * @see #RANGE_TYPE_INT
   2608          * @see #RANGE_TYPE_FLOAT
   2609          * @see #RANGE_TYPE_PERCENT
   2610          */
   2611         public int getType() {
   2612             return mType;
   2613         }
   2614 
   2615         /**
   2616          * Gets the min value.
   2617          *
   2618          * @return The min value.
   2619          */
   2620         public float getMin() {
   2621             return mMin;
   2622         }
   2623 
   2624         /**
   2625          * Gets the max value.
   2626          *
   2627          * @return The max value.
   2628          */
   2629         public float getMax() {
   2630             return mMax;
   2631         }
   2632 
   2633         /**
   2634          * Gets the current value.
   2635          *
   2636          * @return The current value.
   2637          */
   2638         public float getCurrent() {
   2639             return mCurrent;
   2640         }
   2641 
   2642         /**
   2643          * Recycles this instance.
   2644          */
   2645         void recycle() {
   2646             clear();
   2647             sPool.release(this);
   2648         }
   2649 
   2650         private void clear() {
   2651             mType = 0;
   2652             mMin = 0;
   2653             mMax = 0;
   2654             mCurrent = 0;
   2655         }
   2656     }
   2657 
   2658     /**
   2659      * Class with information if a node is a collection. Use
   2660      * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance.
   2661      * <p>
   2662      * A collection of items has rows and columns and may be hierarchical.
   2663      * For example, a horizontal list is a collection with one column, as
   2664      * many rows as the list items, and is not hierarchical; A table is a
   2665      * collection with several rows, several columns, and is not hierarchical;
   2666      * A vertical tree is a hierarchical collection with one column and
   2667      * as many rows as the first level children.
   2668      * </p>
   2669      */
   2670     public static final class CollectionInfo {
   2671         private static final int MAX_POOL_SIZE = 20;
   2672 
   2673         private static final SynchronizedPool<CollectionInfo> sPool =
   2674                 new SynchronizedPool<CollectionInfo>(MAX_POOL_SIZE);
   2675 
   2676         private int mRowCount;
   2677         private int mColumnCount;
   2678         private boolean mHierarchical;
   2679 
   2680         /**
   2681          * Obtains a pooled instance that is a clone of another one.
   2682          *
   2683          * @param other The instance to clone.
   2684          *
   2685          * @hide
   2686          */
   2687         public static CollectionInfo obtain(CollectionInfo other) {
   2688             return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
   2689                     other.mHierarchical);
   2690         }
   2691 
   2692         /**
   2693          * Obtains a pooled instance.
   2694          *
   2695          * @param rowCount The number of rows.
   2696          * @param columnCount The number of columns.
   2697          * @param hierarchical Whether the collection is hierarchical.
   2698          */
   2699         public static CollectionInfo obtain(int rowCount, int columnCount,
   2700                 boolean hierarchical) {
   2701             CollectionInfo info = sPool.acquire();
   2702             return (info != null) ? info : new CollectionInfo(rowCount,
   2703                     columnCount, hierarchical);
   2704         }
   2705 
   2706         /**
   2707          * Creates a new instance.
   2708          *
   2709          * @param rowCount The number of rows.
   2710          * @param columnCount The number of columns.
   2711          * @param hierarchical Whether the collection is hierarchical.
   2712          */
   2713         private CollectionInfo(int rowCount, int columnCount,
   2714                 boolean hierarchical) {
   2715             mRowCount = rowCount;
   2716             mColumnCount = columnCount;
   2717             mHierarchical = hierarchical;
   2718         }
   2719 
   2720         /**
   2721          * Gets the number of rows.
   2722          *
   2723          * @return The row count.
   2724          */
   2725         public int getRowCount() {
   2726             return mRowCount;
   2727         }
   2728 
   2729         /**
   2730          * Gets the number of columns.
   2731          *
   2732          * @return The column count.
   2733          */
   2734         public int getColumnCount() {
   2735             return mColumnCount;
   2736         }
   2737 
   2738         /**
   2739          * Gets if the collection is a hierarchically ordered.
   2740          *
   2741          * @return Whether the collection is hierarchical.
   2742          */
   2743         public boolean isHierarchical() {
   2744             return mHierarchical;
   2745         }
   2746 
   2747         /**
   2748          * Recycles this instance.
   2749          */
   2750         void recycle() {
   2751             clear();
   2752             sPool.release(this);
   2753         }
   2754 
   2755         private void clear() {
   2756             mRowCount = 0;
   2757             mColumnCount = 0;
   2758             mHierarchical = false;
   2759         }
   2760     }
   2761 
   2762     /**
   2763      * Class with information if a node is a collection item. Use
   2764      * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
   2765      * to get an instance.
   2766      * <p>
   2767      * A collection item is contained in a collection, it starts at
   2768      * a given row and column in the collection, and spans one or
   2769      * more rows and columns. For example, a header of two related
   2770      * table columns starts at the first row and the first column,
   2771      * spans one row and two columns.
   2772      * </p>
   2773      */
   2774     public static final class CollectionItemInfo {
   2775         private static final int MAX_POOL_SIZE = 20;
   2776 
   2777         private static final SynchronizedPool<CollectionItemInfo> sPool =
   2778                 new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
   2779 
   2780         /**
   2781          * Obtains a pooled instance that is a clone of another one.
   2782          *
   2783          * @param other The instance to clone.
   2784          *
   2785          * @hide
   2786          */
   2787         public static CollectionItemInfo obtain(CollectionItemInfo other) {
   2788             return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
   2789                     other.mColumnIndex, other.mColumnSpan, other.mHeading);
   2790         }
   2791 
   2792         /**
   2793          * Obtains a pooled instance.
   2794          *
   2795          * @param rowIndex The row index at which the item is located.
   2796          * @param rowSpan The number of rows the item spans.
   2797          * @param columnIndex The column index at which the item is located.
   2798          * @param columnSpan The number of columns the item spans.
   2799          * @param heading Whether the item is a heading.
   2800          */
   2801         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
   2802                 int columnIndex, int columnSpan, boolean heading) {
   2803             CollectionItemInfo info = sPool.acquire();
   2804             return (info != null) ? info : new CollectionItemInfo(rowIndex,
   2805                     rowSpan, columnIndex, columnSpan, heading);
   2806         }
   2807 
   2808         private boolean mHeading;
   2809         private int mColumnIndex;
   2810         private int mRowIndex;
   2811         private int mColumnSpan;
   2812         private int mRowSpan;
   2813 
   2814         /**
   2815          * Creates a new instance.
   2816          *
   2817          * @param rowIndex The row index at which the item is located.
   2818          * @param rowSpan The number of rows the item spans.
   2819          * @param columnIndex The column index at which the item is located.
   2820          * @param columnSpan The number of columns the item spans.
   2821          * @param heading Whether the item is a heading.
   2822          */
   2823         private CollectionItemInfo(int rowIndex, int rowSpan,
   2824                 int columnIndex, int columnSpan, boolean heading) {
   2825             mRowIndex = rowIndex;
   2826             mRowSpan = rowSpan;
   2827             mColumnIndex = columnIndex;
   2828             mColumnSpan = columnSpan;
   2829             mHeading = heading;
   2830         }
   2831 
   2832         /**
   2833          * Gets the column index at which the item is located.
   2834          *
   2835          * @return The column index.
   2836          */
   2837         public int getColumnIndex() {
   2838             return mColumnIndex;
   2839         }
   2840 
   2841         /**
   2842          * Gets the row index at which the item is located.
   2843          *
   2844          * @return The row index.
   2845          */
   2846         public int getRowIndex() {
   2847             return mRowIndex;
   2848         }
   2849 
   2850         /**
   2851          * Gets the number of columns the item spans.
   2852          *
   2853          * @return The column span.
   2854          */
   2855         public int getColumnSpan() {
   2856             return mColumnSpan;
   2857         }
   2858 
   2859         /**
   2860          * Gets the number of rows the item spans.
   2861          *
   2862          * @return The row span.
   2863          */
   2864         public int getRowSpan() {
   2865             return mRowSpan;
   2866         }
   2867 
   2868         /**
   2869          * Gets if the collection item is a heading. For example, section
   2870          * heading, table header, etc.
   2871          *
   2872          * @return If the item is a heading.
   2873          */
   2874         public boolean isHeading() {
   2875             return mHeading;
   2876         }
   2877 
   2878         /**
   2879          * Recycles this instance.
   2880          */
   2881         void recycle() {
   2882             clear();
   2883             sPool.release(this);
   2884         }
   2885 
   2886         private void clear() {
   2887             mColumnIndex = 0;
   2888             mColumnSpan = 0;
   2889             mRowIndex = 0;
   2890             mRowSpan = 0;
   2891             mHeading = false;
   2892         }
   2893     }
   2894 
   2895     /**
   2896      * @see Parcelable.Creator
   2897      */
   2898     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
   2899             new Parcelable.Creator<AccessibilityNodeInfo>() {
   2900         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
   2901             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2902             info.initFromParcel(parcel);
   2903             return info;
   2904         }
   2905 
   2906         public AccessibilityNodeInfo[] newArray(int size) {
   2907             return new AccessibilityNodeInfo[size];
   2908         }
   2909     };
   2910 }
   2911