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.util.Pools.SynchronizedPool;
     25 import android.util.SparseLongArray;
     26 import android.view.View;
     27 
     28 import java.util.Collections;
     29 import java.util.List;
     30 
     31 /**
     32  * This class represents a node of the window content as well as actions that
     33  * can be requested from its source. From the point of view of an
     34  * {@link android.accessibilityservice.AccessibilityService} a window content is
     35  * presented as tree of accessibility node info which may or may not map one-to-one
     36  * to the view hierarchy. In other words, a custom view is free to report itself as
     37  * a tree of accessibility node info.
     38  * </p>
     39  * <p>
     40  * Once an accessibility node info is delivered to an accessibility service it is
     41  * made immutable and calling a state mutation method generates an error.
     42  * </p>
     43  * <p>
     44  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
     45  * details about how to obtain a handle to window content as a tree of accessibility
     46  * node info as well as familiarizing with the security model.
     47  * </p>
     48  * <div class="special reference">
     49  * <h3>Developer Guides</h3>
     50  * <p>For more information about making applications accessible, read the
     51  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     52  * developer guide.</p>
     53  * </div>
     54  *
     55  * @see android.accessibilityservice.AccessibilityService
     56  * @see AccessibilityEvent
     57  * @see AccessibilityManager
     58  */
     59 public class AccessibilityNodeInfo implements Parcelable {
     60 
     61     private static final boolean DEBUG = false;
     62 
     63     /** @hide */
     64     public static final int UNDEFINED = -1;
     65 
     66     /** @hide */
     67     public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
     68 
     69     /** @hide */
     70     public static final int ACTIVE_WINDOW_ID = UNDEFINED;
     71 
     72     /** @hide */
     73     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
     74 
     75     /** @hide */
     76     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
     77 
     78     /** @hide */
     79     public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
     80 
     81     /** @hide */
     82     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
     83 
     84     /** @hide */
     85     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
     86 
     87     // Actions.
     88 
     89     /**
     90      * Action that gives input focus to the node.
     91      */
     92     public static final int ACTION_FOCUS =  0x00000001;
     93 
     94     /**
     95      * Action that clears input focus of the node.
     96      */
     97     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
     98 
     99     /**
    100      * Action that selects the node.
    101      */
    102     public static final int ACTION_SELECT = 0x00000004;
    103 
    104     /**
    105      * Action that unselects the node.
    106      */
    107     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
    108 
    109     /**
    110      * Action that clicks on the node info.
    111      */
    112     public static final int ACTION_CLICK = 0x00000010;
    113 
    114     /**
    115      * Action that long clicks on the node.
    116      */
    117     public static final int ACTION_LONG_CLICK = 0x00000020;
    118 
    119     /**
    120      * Action that gives accessibility focus to the node.
    121      */
    122     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
    123 
    124     /**
    125      * Action that clears accessibility focus of the node.
    126      */
    127     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
    128 
    129     /**
    130      * Action that requests to go to the next entity in this node's text
    131      * at a given movement granularity. For example, move to the next character,
    132      * word, etc.
    133      * <p>
    134      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    135      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    136      * <strong>Example:</strong> Move to the previous character and do not extend selection.
    137      * <code><pre><p>
    138      *   Bundle arguments = new Bundle();
    139      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    140      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    141      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    142      *           false);
    143      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
    144      * </code></pre></p>
    145      * </p>
    146      *
    147      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    148      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    149      *
    150      * @see #setMovementGranularities(int)
    151      * @see #getMovementGranularities()
    152      *
    153      * @see #MOVEMENT_GRANULARITY_CHARACTER
    154      * @see #MOVEMENT_GRANULARITY_WORD
    155      * @see #MOVEMENT_GRANULARITY_LINE
    156      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    157      * @see #MOVEMENT_GRANULARITY_PAGE
    158      */
    159     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
    160 
    161     /**
    162      * Action that requests to go to the previous entity in this node's text
    163      * at a given movement granularity. For example, move to the next character,
    164      * word, etc.
    165      * <p>
    166      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    167      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    168      * <strong>Example:</strong> Move to the next character and do not extend selection.
    169      * <code><pre><p>
    170      *   Bundle arguments = new Bundle();
    171      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    172      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    173      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    174      *           false);
    175      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
    176      *           arguments);
    177      * </code></pre></p>
    178      * </p>
    179      *
    180      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    181      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    182      *
    183      * @see #setMovementGranularities(int)
    184      * @see #getMovementGranularities()
    185      *
    186      * @see #MOVEMENT_GRANULARITY_CHARACTER
    187      * @see #MOVEMENT_GRANULARITY_WORD
    188      * @see #MOVEMENT_GRANULARITY_LINE
    189      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    190      * @see #MOVEMENT_GRANULARITY_PAGE
    191      */
    192     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
    193 
    194     /**
    195      * Action to move to the next HTML element of a given type. For example, move
    196      * to the BUTTON, INPUT, TABLE, etc.
    197      * <p>
    198      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    199      * <strong>Example:</strong>
    200      * <code><pre><p>
    201      *   Bundle arguments = new Bundle();
    202      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    203      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
    204      * </code></pre></p>
    205      * </p>
    206      */
    207     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
    208 
    209     /**
    210      * Action to move to the previous HTML element of a given type. For example, move
    211      * to the BUTTON, INPUT, TABLE, etc.
    212      * <p>
    213      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    214      * <strong>Example:</strong>
    215      * <code><pre><p>
    216      *   Bundle arguments = new Bundle();
    217      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    218      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
    219      * </code></pre></p>
    220      * </p>
    221      */
    222     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
    223 
    224     /**
    225      * Action to scroll the node content forward.
    226      */
    227     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
    228 
    229     /**
    230      * Action to scroll the node content backward.
    231      */
    232     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
    233 
    234     /**
    235      * Action to copy the current selection to the clipboard.
    236      */
    237     public static final int ACTION_COPY = 0x00004000;
    238 
    239     /**
    240      * Action to paste the current clipboard content.
    241      */
    242     public static final int ACTION_PASTE = 0x00008000;
    243 
    244     /**
    245      * Action to cut the current selection and place it to the clipboard.
    246      */
    247     public static final int ACTION_CUT = 0x00010000;
    248 
    249     /**
    250      * Action to set the selection. Performing this action with no arguments
    251      * clears the selection.
    252      * <p>
    253      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
    254      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
    255      * <strong>Example:</strong>
    256      * <code><pre><p>
    257      *   Bundle arguments = new Bundle();
    258      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
    259      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
    260      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
    261      * </code></pre></p>
    262      * </p>
    263      *
    264      * @see #ACTION_ARGUMENT_SELECTION_START_INT
    265      * @see #ACTION_ARGUMENT_SELECTION_END_INT
    266      */
    267     public static final int ACTION_SET_SELECTION = 0x00020000;
    268 
    269     /**
    270      * Argument for which movement granularity to be used when traversing the node text.
    271      * <p>
    272      * <strong>Type:</strong> int<br>
    273      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
    274      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
    275      * </p>
    276      *
    277      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    278      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    279      */
    280     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
    281             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
    282 
    283     /**
    284      * Argument for which HTML element to get moving to the next/previous HTML element.
    285      * <p>
    286      * <strong>Type:</strong> String<br>
    287      * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
    288      *         {@link #ACTION_PREVIOUS_HTML_ELEMENT}
    289      * </p>
    290      *
    291      * @see #ACTION_NEXT_HTML_ELEMENT
    292      * @see #ACTION_PREVIOUS_HTML_ELEMENT
    293      */
    294     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
    295             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
    296 
    297     /**
    298      * Argument for whether when moving at granularity to extend the selection
    299      * or to move it otherwise.
    300      * <p>
    301      * <strong>Type:</strong> boolean<br>
    302      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
    303      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
    304      * </p>
    305      *
    306      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    307      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    308      */
    309     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
    310             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
    311 
    312     /**
    313      * Argument for specifying the selection start.
    314      * <p>
    315      * <strong>Type:</strong> int<br>
    316      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
    317      * </p>
    318      *
    319      * @see #ACTION_SET_SELECTION
    320      */
    321     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
    322             "ACTION_ARGUMENT_SELECTION_START_INT";
    323 
    324     /**
    325      * Argument for specifying the selection end.
    326      * <p>
    327      * <strong>Type:</strong> int<br>
    328      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
    329      * </p>
    330      *
    331      * @see #ACTION_SET_SELECTION
    332      */
    333     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
    334             "ACTION_ARGUMENT_SELECTION_END_INT";
    335 
    336     /**
    337      * The input focus.
    338      */
    339     public static final int FOCUS_INPUT = 1;
    340 
    341     /**
    342      * The accessibility focus.
    343      */
    344     public static final int FOCUS_ACCESSIBILITY = 2;
    345 
    346     // Movement granularities
    347 
    348     /**
    349      * Movement granularity bit for traversing the text of a node by character.
    350      */
    351     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
    352 
    353     /**
    354      * Movement granularity bit for traversing the text of a node by word.
    355      */
    356     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
    357 
    358     /**
    359      * Movement granularity bit for traversing the text of a node by line.
    360      */
    361     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
    362 
    363     /**
    364      * Movement granularity bit for traversing the text of a node by paragraph.
    365      */
    366     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
    367 
    368     /**
    369      * Movement granularity bit for traversing the text of a node by page.
    370      */
    371     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
    372 
    373     // Boolean attributes.
    374 
    375     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
    376 
    377     private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
    378 
    379     private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
    380 
    381     private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
    382 
    383     private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
    384 
    385     private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
    386 
    387     private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
    388 
    389     private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
    390 
    391     private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
    392 
    393     private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
    394 
    395     private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
    396 
    397     private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
    398 
    399     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
    400 
    401     /**
    402      * Bits that provide the id of a virtual descendant of a view.
    403      */
    404     private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
    405 
    406     /**
    407      * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
    408      * virtual descendant of a view. Such a descendant does not exist in the view
    409      * hierarchy and is only reported via the accessibility APIs.
    410      */
    411     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
    412 
    413     /**
    414      * Gets the accessibility view id which identifies a View in the view three.
    415      *
    416      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    417      * @return The accessibility view id part of the node id.
    418      *
    419      * @hide
    420      */
    421     public static int getAccessibilityViewId(long accessibilityNodeId) {
    422         return (int) accessibilityNodeId;
    423     }
    424 
    425     /**
    426      * Gets the virtual descendant id which identifies an imaginary view in a
    427      * containing View.
    428      *
    429      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
    430      * @return The virtual view id part of the node id.
    431      *
    432      * @hide
    433      */
    434     public static int getVirtualDescendantId(long accessibilityNodeId) {
    435         return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
    436                 >> VIRTUAL_DESCENDANT_ID_SHIFT);
    437     }
    438 
    439     /**
    440      * Makes a node id by shifting the <code>virtualDescendantId</code>
    441      * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
    442      * the bitwise or with the <code>accessibilityViewId</code>.
    443      *
    444      * @param accessibilityViewId A View accessibility id.
    445      * @param virtualDescendantId A virtual descendant id.
    446      * @return The node id.
    447      *
    448      * @hide
    449      */
    450     public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
    451         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
    452     }
    453 
    454     // Housekeeping.
    455     private static final int MAX_POOL_SIZE = 50;
    456     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
    457             new SynchronizedPool<AccessibilityNodeInfo>(MAX_POOL_SIZE);
    458 
    459     private boolean mSealed;
    460 
    461     // Data.
    462     private int mWindowId = UNDEFINED;
    463     private long mSourceNodeId = ROOT_NODE_ID;
    464     private long mParentNodeId = ROOT_NODE_ID;
    465     private long mLabelForId = ROOT_NODE_ID;
    466     private long mLabeledById = ROOT_NODE_ID;
    467 
    468     private int mBooleanProperties;
    469     private final Rect mBoundsInParent = new Rect();
    470     private final Rect mBoundsInScreen = new Rect();
    471 
    472     private CharSequence mPackageName;
    473     private CharSequence mClassName;
    474     private CharSequence mText;
    475     private CharSequence mContentDescription;
    476     private String mViewIdResourceName;
    477 
    478     private final SparseLongArray mChildNodeIds = new SparseLongArray();
    479     private int mActions;
    480 
    481     private int mMovementGranularities;
    482 
    483     private int mTextSelectionStart = UNDEFINED;
    484     private int mTextSelectionEnd = UNDEFINED;
    485 
    486     private int mConnectionId = UNDEFINED;
    487 
    488     /**
    489      * Hide constructor from clients.
    490      */
    491     private AccessibilityNodeInfo() {
    492         /* do nothing */
    493     }
    494 
    495     /**
    496      * Sets the source.
    497      * <p>
    498      *   <strong>Note:</strong> Cannot be called from an
    499      *   {@link android.accessibilityservice.AccessibilityService}.
    500      *   This class is made immutable before being delivered to an AccessibilityService.
    501      * </p>
    502      *
    503      * @param source The info source.
    504      */
    505     public void setSource(View source) {
    506         setSource(source, UNDEFINED);
    507     }
    508 
    509     /**
    510      * Sets the source to be a virtual descendant of the given <code>root</code>.
    511      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
    512      * is set as the source.
    513      * <p>
    514      * A virtual descendant is an imaginary View that is reported as a part of the view
    515      * hierarchy for accessibility purposes. This enables custom views that draw complex
    516      * content to report themselves as a tree of virtual views, thus conveying their
    517      * logical structure.
    518      * </p>
    519      * <p>
    520      *   <strong>Note:</strong> Cannot be called from an
    521      *   {@link android.accessibilityservice.AccessibilityService}.
    522      *   This class is made immutable before being delivered to an AccessibilityService.
    523      * </p>
    524      *
    525      * @param root The root of the virtual subtree.
    526      * @param virtualDescendantId The id of the virtual descendant.
    527      */
    528     public void setSource(View root, int virtualDescendantId) {
    529         enforceNotSealed();
    530         mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
    531         final int rootAccessibilityViewId =
    532             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    533         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    534     }
    535 
    536     /**
    537      * Find the view that has the specified focus type. The search starts from
    538      * the view represented by this node info.
    539      *
    540      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
    541      *         {@link #FOCUS_ACCESSIBILITY}.
    542      * @return The node info of the focused view or null.
    543      *
    544      * @see #FOCUS_INPUT
    545      * @see #FOCUS_ACCESSIBILITY
    546      */
    547     public AccessibilityNodeInfo findFocus(int focus) {
    548         enforceSealed();
    549         enforceValidFocusType(focus);
    550         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    551             return null;
    552         }
    553         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
    554                 mSourceNodeId, focus);
    555     }
    556 
    557     /**
    558      * Searches for the nearest view in the specified direction that can take
    559      * the input focus.
    560      *
    561      * @param direction The direction. Can be one of:
    562      *     {@link View#FOCUS_DOWN},
    563      *     {@link View#FOCUS_UP},
    564      *     {@link View#FOCUS_LEFT},
    565      *     {@link View#FOCUS_RIGHT},
    566      *     {@link View#FOCUS_FORWARD},
    567      *     {@link View#FOCUS_BACKWARD}.
    568      *
    569      * @return The node info for the view that can take accessibility focus.
    570      */
    571     public AccessibilityNodeInfo focusSearch(int direction) {
    572         enforceSealed();
    573         enforceValidFocusDirection(direction);
    574         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    575             return null;
    576         }
    577         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
    578                 mSourceNodeId, direction);
    579     }
    580 
    581     /**
    582      * Gets the id of the window from which the info comes from.
    583      *
    584      * @return The window id.
    585      */
    586     public int getWindowId() {
    587         return mWindowId;
    588     }
    589 
    590     /**
    591      * Refreshes this info with the latest state of the view it represents.
    592      * <p>
    593      * <strong>Note:</strong> If this method returns false this info is obsolete
    594      * since it represents a view that is no longer in the view tree and should
    595      * be recycled.
    596      * </p>
    597      * @return Whether the refresh succeeded.
    598      */
    599     public boolean refresh() {
    600         enforceSealed();
    601         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    602             return false;
    603         }
    604         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    605         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
    606                 mConnectionId, mWindowId, mSourceNodeId, 0);
    607         if (refreshedInfo == null) {
    608             return false;
    609         }
    610         init(refreshedInfo);
    611         refreshedInfo.recycle();
    612         return true;
    613     }
    614 
    615     /**
    616      * @return The ids of the children.
    617      *
    618      * @hide
    619      */
    620     public SparseLongArray getChildNodeIds() {
    621         return mChildNodeIds;
    622     }
    623 
    624     /**
    625      * Gets the number of children.
    626      *
    627      * @return The child count.
    628      */
    629     public int getChildCount() {
    630         return mChildNodeIds.size();
    631     }
    632 
    633     /**
    634      * Get the child at given index.
    635      * <p>
    636      *   <strong>Note:</strong> It is a client responsibility to recycle the
    637      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    638      *     to avoid creating of multiple instances.
    639      * </p>
    640      *
    641      * @param index The child index.
    642      * @return The child node.
    643      *
    644      * @throws IllegalStateException If called outside of an AccessibilityService.
    645      *
    646      */
    647     public AccessibilityNodeInfo getChild(int index) {
    648         enforceSealed();
    649         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    650             return null;
    651         }
    652         final long childId = mChildNodeIds.get(index);
    653         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    654         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
    655                 childId, FLAG_PREFETCH_DESCENDANTS);
    656     }
    657 
    658     /**
    659      * Adds a child.
    660      * <p>
    661      * <strong>Note:</strong> Cannot be called from an
    662      * {@link android.accessibilityservice.AccessibilityService}.
    663      * This class is made immutable before being delivered to an AccessibilityService.
    664      * </p>
    665      *
    666      * @param child The child.
    667      *
    668      * @throws IllegalStateException If called from an AccessibilityService.
    669      */
    670     public void addChild(View child) {
    671         addChild(child, UNDEFINED);
    672     }
    673 
    674     /**
    675      * Adds a virtual child which is a descendant of the given <code>root</code>.
    676      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
    677      * is added as a child.
    678      * <p>
    679      * A virtual descendant is an imaginary View that is reported as a part of the view
    680      * hierarchy for accessibility purposes. This enables custom views that draw complex
    681      * content to report them selves as a tree of virtual views, thus conveying their
    682      * logical structure.
    683      * </p>
    684      *
    685      * @param root The root of the virtual subtree.
    686      * @param virtualDescendantId The id of the virtual child.
    687      */
    688     public void addChild(View root, int virtualDescendantId) {
    689         enforceNotSealed();
    690         final int index = mChildNodeIds.size();
    691         final int rootAccessibilityViewId =
    692             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    693         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    694         mChildNodeIds.put(index, childNodeId);
    695     }
    696 
    697     /**
    698      * Gets the actions that can be performed on the node.
    699      *
    700      * @return The bit mask of with actions.
    701      *
    702      * @see AccessibilityNodeInfo#ACTION_FOCUS
    703      * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
    704      * @see AccessibilityNodeInfo#ACTION_SELECT
    705      * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
    706      * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
    707      * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
    708      * @see AccessibilityNodeInfo#ACTION_CLICK
    709      * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
    710      * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
    711      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
    712      * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
    713      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
    714      * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
    715      * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
    716      */
    717     public int getActions() {
    718         return mActions;
    719     }
    720 
    721     /**
    722      * Adds an action that can be performed on the node.
    723      * <p>
    724      *   <strong>Note:</strong> Cannot be called from an
    725      *   {@link android.accessibilityservice.AccessibilityService}.
    726      *   This class is made immutable before being delivered to an AccessibilityService.
    727      * </p>
    728      *
    729      * @param action The action.
    730      *
    731      * @throws IllegalStateException If called from an AccessibilityService.
    732      */
    733     public void addAction(int action) {
    734         enforceNotSealed();
    735         mActions |= action;
    736     }
    737 
    738     /**
    739      * Sets the movement granularities for traversing the text of this node.
    740      * <p>
    741      *   <strong>Note:</strong> Cannot be called from an
    742      *   {@link android.accessibilityservice.AccessibilityService}.
    743      *   This class is made immutable before being delivered to an AccessibilityService.
    744      * </p>
    745      *
    746      * @param granularities The bit mask with granularities.
    747      *
    748      * @throws IllegalStateException If called from an AccessibilityService.
    749      */
    750     public void setMovementGranularities(int granularities) {
    751         enforceNotSealed();
    752         mMovementGranularities = granularities;
    753     }
    754 
    755     /**
    756      * Gets the movement granularities for traversing the text of this node.
    757      *
    758      * @return The bit mask with granularities.
    759      */
    760     public int getMovementGranularities() {
    761         return mMovementGranularities;
    762     }
    763 
    764     /**
    765      * Performs an action on the node.
    766      * <p>
    767      *   <strong>Note:</strong> An action can be performed only if the request is made
    768      *   from an {@link android.accessibilityservice.AccessibilityService}.
    769      * </p>
    770      *
    771      * @param action The action to perform.
    772      * @return True if the action was performed.
    773      *
    774      * @throws IllegalStateException If called outside of an AccessibilityService.
    775      */
    776     public boolean performAction(int action) {
    777         enforceSealed();
    778         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    779             return false;
    780         }
    781         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    782         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
    783                 action, null);
    784     }
    785 
    786     /**
    787      * Performs an action on the node.
    788      * <p>
    789      *   <strong>Note:</strong> An action can be performed only if the request is made
    790      *   from an {@link android.accessibilityservice.AccessibilityService}.
    791      * </p>
    792      *
    793      * @param action The action to perform.
    794      * @param arguments A bundle with additional arguments.
    795      * @return True if the action was performed.
    796      *
    797      * @throws IllegalStateException If called outside of an AccessibilityService.
    798      */
    799     public boolean performAction(int action, Bundle arguments) {
    800         enforceSealed();
    801         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    802             return false;
    803         }
    804         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    805         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
    806                 action, arguments);
    807     }
    808 
    809     /**
    810      * Finds {@link AccessibilityNodeInfo}s by text. The match is case
    811      * insensitive containment. The search is relative to this info i.e.
    812      * this info is the root of the traversed tree.
    813      *
    814      * <p>
    815      *   <strong>Note:</strong> It is a client responsibility to recycle the
    816      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    817      *     to avoid creating of multiple instances.
    818      * </p>
    819      *
    820      * @param text The searched text.
    821      * @return A list of node info.
    822      */
    823     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
    824         enforceSealed();
    825         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    826             return Collections.emptyList();
    827         }
    828         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    829         return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
    830                 text);
    831     }
    832 
    833     /**
    834      * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
    835      * name where a fully qualified id is of the from "package:id/id_resource_name".
    836      * For example, if the target application's package is "foo.bar" and the id
    837      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
    838      *
    839      * <p>
    840      *   <strong>Note:</strong> It is a client responsibility to recycle the
    841      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    842      *     to avoid creating of multiple instances.
    843      * </p>
    844      * <p>
    845      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
    846      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
    847      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
    848      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
    849      * </p>
    850      *
    851      * @param viewId The fully qualified resource name of the view id to find.
    852      * @return A list of node info.
    853      */
    854     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
    855         enforceSealed();
    856         if (!canPerformRequestOverConnection(mSourceNodeId)) {
    857             return Collections.emptyList();
    858         }
    859         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    860         return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
    861                 viewId);
    862     }
    863 
    864     /**
    865      * Gets the parent.
    866      * <p>
    867      *   <strong>Note:</strong> It is a client responsibility to recycle the
    868      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
    869      *     to avoid creating of multiple instances.
    870      * </p>
    871      *
    872      * @return The parent.
    873      */
    874     public AccessibilityNodeInfo getParent() {
    875         enforceSealed();
    876         if (!canPerformRequestOverConnection(mParentNodeId)) {
    877             return null;
    878         }
    879         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
    880         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
    881                 mWindowId, mParentNodeId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
    882     }
    883 
    884     /**
    885      * @return The parent node id.
    886      *
    887      * @hide
    888      */
    889     public long getParentNodeId() {
    890         return mParentNodeId;
    891     }
    892 
    893     /**
    894      * Sets the parent.
    895      * <p>
    896      *   <strong>Note:</strong> Cannot be called from an
    897      *   {@link android.accessibilityservice.AccessibilityService}.
    898      *   This class is made immutable before being delivered to an AccessibilityService.
    899      * </p>
    900      *
    901      * @param parent The parent.
    902      *
    903      * @throws IllegalStateException If called from an AccessibilityService.
    904      */
    905     public void setParent(View parent) {
    906         setParent(parent, UNDEFINED);
    907     }
    908 
    909     /**
    910      * Sets the parent to be a virtual descendant of the given <code>root</code>.
    911      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
    912      * is set as the parent.
    913      * <p>
    914      * A virtual descendant is an imaginary View that is reported as a part of the view
    915      * hierarchy for accessibility purposes. This enables custom views that draw complex
    916      * content to report them selves as a tree of virtual views, thus conveying their
    917      * logical structure.
    918      * </p>
    919      * <p>
    920      *   <strong>Note:</strong> Cannot be called from an
    921      *   {@link android.accessibilityservice.AccessibilityService}.
    922      *   This class is made immutable before being delivered to an AccessibilityService.
    923      * </p>
    924      *
    925      * @param root The root of the virtual subtree.
    926      * @param virtualDescendantId The id of the virtual descendant.
    927      */
    928     public void setParent(View root, int virtualDescendantId) {
    929         enforceNotSealed();
    930         final int rootAccessibilityViewId =
    931             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
    932         mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
    933     }
    934 
    935     /**
    936      * Gets the node bounds in parent coordinates.
    937      *
    938      * @param outBounds The output node bounds.
    939      */
    940     public void getBoundsInParent(Rect outBounds) {
    941         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
    942                 mBoundsInParent.right, mBoundsInParent.bottom);
    943     }
    944 
    945     /**
    946      * Sets the node bounds in parent coordinates.
    947      * <p>
    948      *   <strong>Note:</strong> Cannot be called from an
    949      *   {@link android.accessibilityservice.AccessibilityService}.
    950      *   This class is made immutable before being delivered to an AccessibilityService.
    951      * </p>
    952      *
    953      * @param bounds The node bounds.
    954      *
    955      * @throws IllegalStateException If called from an AccessibilityService.
    956      */
    957     public void setBoundsInParent(Rect bounds) {
    958         enforceNotSealed();
    959         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
    960     }
    961 
    962     /**
    963      * Gets the node bounds in screen coordinates.
    964      *
    965      * @param outBounds The output node bounds.
    966      */
    967     public void getBoundsInScreen(Rect outBounds) {
    968         outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
    969                 mBoundsInScreen.right, mBoundsInScreen.bottom);
    970     }
    971 
    972     /**
    973      * Sets the node bounds in screen coordinates.
    974      * <p>
    975      *   <strong>Note:</strong> Cannot be called from an
    976      *   {@link android.accessibilityservice.AccessibilityService}.
    977      *   This class is made immutable before being delivered to an AccessibilityService.
    978      * </p>
    979      *
    980      * @param bounds The node bounds.
    981      *
    982      * @throws IllegalStateException If called from an AccessibilityService.
    983      */
    984     public void setBoundsInScreen(Rect bounds) {
    985         enforceNotSealed();
    986         mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
    987     }
    988 
    989     /**
    990      * Gets whether this node is checkable.
    991      *
    992      * @return True if the node is checkable.
    993      */
    994     public boolean isCheckable() {
    995         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
    996     }
    997 
    998     /**
    999      * Sets whether this node is checkable.
   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 checkable True if the node is checkable.
   1007      *
   1008      * @throws IllegalStateException If called from an AccessibilityService.
   1009      */
   1010     public void setCheckable(boolean checkable) {
   1011         setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
   1012     }
   1013 
   1014     /**
   1015      * Gets whether this node is checked.
   1016      *
   1017      * @return True if the node is checked.
   1018      */
   1019     public boolean isChecked() {
   1020         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
   1021     }
   1022 
   1023     /**
   1024      * Sets whether this node is checked.
   1025      * <p>
   1026      *   <strong>Note:</strong> Cannot be called from an
   1027      *   {@link android.accessibilityservice.AccessibilityService}.
   1028      *   This class is made immutable before being delivered to an AccessibilityService.
   1029      * </p>
   1030      *
   1031      * @param checked True if the node is checked.
   1032      *
   1033      * @throws IllegalStateException If called from an AccessibilityService.
   1034      */
   1035     public void setChecked(boolean checked) {
   1036         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
   1037     }
   1038 
   1039     /**
   1040      * Gets whether this node is focusable.
   1041      *
   1042      * @return True if the node is focusable.
   1043      */
   1044     public boolean isFocusable() {
   1045         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
   1046     }
   1047 
   1048     /**
   1049      * Sets whether this node is focusable.
   1050      * <p>
   1051      *   <strong>Note:</strong> Cannot be called from an
   1052      *   {@link android.accessibilityservice.AccessibilityService}.
   1053      *   This class is made immutable before being delivered to an AccessibilityService.
   1054      * </p>
   1055      *
   1056      * @param focusable True if the node is focusable.
   1057      *
   1058      * @throws IllegalStateException If called from an AccessibilityService.
   1059      */
   1060     public void setFocusable(boolean focusable) {
   1061         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
   1062     }
   1063 
   1064     /**
   1065      * Gets whether this node is focused.
   1066      *
   1067      * @return True if the node is focused.
   1068      */
   1069     public boolean isFocused() {
   1070         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
   1071     }
   1072 
   1073     /**
   1074      * Sets whether this node is focused.
   1075      * <p>
   1076      *   <strong>Note:</strong> Cannot be called from an
   1077      *   {@link android.accessibilityservice.AccessibilityService}.
   1078      *   This class is made immutable before being delivered to an AccessibilityService.
   1079      * </p>
   1080      *
   1081      * @param focused True if the node is focused.
   1082      *
   1083      * @throws IllegalStateException If called from an AccessibilityService.
   1084      */
   1085     public void setFocused(boolean focused) {
   1086         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
   1087     }
   1088 
   1089     /**
   1090      * Sets whether this node is visible to the user.
   1091      *
   1092      * @return Whether the node is visible to the user.
   1093      */
   1094     public boolean isVisibleToUser() {
   1095         return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
   1096     }
   1097 
   1098     /**
   1099      * Sets whether this node is visible to the user.
   1100      * <p>
   1101      *   <strong>Note:</strong> Cannot be called from an
   1102      *   {@link android.accessibilityservice.AccessibilityService}.
   1103      *   This class is made immutable before being delivered to an AccessibilityService.
   1104      * </p>
   1105      *
   1106      * @param visibleToUser Whether the node is visible to the user.
   1107      *
   1108      * @throws IllegalStateException If called from an AccessibilityService.
   1109      */
   1110     public void setVisibleToUser(boolean visibleToUser) {
   1111         setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
   1112     }
   1113 
   1114     /**
   1115      * Gets whether this node is accessibility focused.
   1116      *
   1117      * @return True if the node is accessibility focused.
   1118      */
   1119     public boolean isAccessibilityFocused() {
   1120         return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
   1121     }
   1122 
   1123     /**
   1124      * Sets whether this node is accessibility focused.
   1125      * <p>
   1126      *   <strong>Note:</strong> Cannot be called from an
   1127      *   {@link android.accessibilityservice.AccessibilityService}.
   1128      *   This class is made immutable before being delivered to an AccessibilityService.
   1129      * </p>
   1130      *
   1131      * @param focused True if the node is accessibility focused.
   1132      *
   1133      * @throws IllegalStateException If called from an AccessibilityService.
   1134      */
   1135     public void setAccessibilityFocused(boolean focused) {
   1136         setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
   1137     }
   1138 
   1139     /**
   1140      * Gets whether this node is selected.
   1141      *
   1142      * @return True if the node is selected.
   1143      */
   1144     public boolean isSelected() {
   1145         return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
   1146     }
   1147 
   1148     /**
   1149      * Sets whether this node is selected.
   1150      * <p>
   1151      *   <strong>Note:</strong> Cannot be called from an
   1152      *   {@link android.accessibilityservice.AccessibilityService}.
   1153      *   This class is made immutable before being delivered to an AccessibilityService.
   1154      * </p>
   1155      *
   1156      * @param selected True if the node is selected.
   1157      *
   1158      * @throws IllegalStateException If called from an AccessibilityService.
   1159      */
   1160     public void setSelected(boolean selected) {
   1161         setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
   1162     }
   1163 
   1164     /**
   1165      * Gets whether this node is clickable.
   1166      *
   1167      * @return True if the node is clickable.
   1168      */
   1169     public boolean isClickable() {
   1170         return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
   1171     }
   1172 
   1173     /**
   1174      * Sets whether this node is clickable.
   1175      * <p>
   1176      *   <strong>Note:</strong> Cannot be called from an
   1177      *   {@link android.accessibilityservice.AccessibilityService}.
   1178      *   This class is made immutable before being delivered to an AccessibilityService.
   1179      * </p>
   1180      *
   1181      * @param clickable True if the node is clickable.
   1182      *
   1183      * @throws IllegalStateException If called from an AccessibilityService.
   1184      */
   1185     public void setClickable(boolean clickable) {
   1186         setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
   1187     }
   1188 
   1189     /**
   1190      * Gets whether this node is long clickable.
   1191      *
   1192      * @return True if the node is long clickable.
   1193      */
   1194     public boolean isLongClickable() {
   1195         return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
   1196     }
   1197 
   1198     /**
   1199      * Sets whether this node is long clickable.
   1200      * <p>
   1201      *   <strong>Note:</strong> Cannot be called from an
   1202      *   {@link android.accessibilityservice.AccessibilityService}.
   1203      *   This class is made immutable before being delivered to an AccessibilityService.
   1204      * </p>
   1205      *
   1206      * @param longClickable True if the node is long clickable.
   1207      *
   1208      * @throws IllegalStateException If called from an AccessibilityService.
   1209      */
   1210     public void setLongClickable(boolean longClickable) {
   1211         setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
   1212     }
   1213 
   1214     /**
   1215      * Gets whether this node is enabled.
   1216      *
   1217      * @return True if the node is enabled.
   1218      */
   1219     public boolean isEnabled() {
   1220         return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
   1221     }
   1222 
   1223     /**
   1224      * Sets whether this node is enabled.
   1225      * <p>
   1226      *   <strong>Note:</strong> Cannot be called from an
   1227      *   {@link android.accessibilityservice.AccessibilityService}.
   1228      *   This class is made immutable before being delivered to an AccessibilityService.
   1229      * </p>
   1230      *
   1231      * @param enabled True if the node is enabled.
   1232      *
   1233      * @throws IllegalStateException If called from an AccessibilityService.
   1234      */
   1235     public void setEnabled(boolean enabled) {
   1236         setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
   1237     }
   1238 
   1239     /**
   1240      * Gets whether this node is a password.
   1241      *
   1242      * @return True if the node is a password.
   1243      */
   1244     public boolean isPassword() {
   1245         return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
   1246     }
   1247 
   1248     /**
   1249      * Sets whether this node is a password.
   1250      * <p>
   1251      *   <strong>Note:</strong> Cannot be called from an
   1252      *   {@link android.accessibilityservice.AccessibilityService}.
   1253      *   This class is made immutable before being delivered to an AccessibilityService.
   1254      * </p>
   1255      *
   1256      * @param password True if the node is a password.
   1257      *
   1258      * @throws IllegalStateException If called from an AccessibilityService.
   1259      */
   1260     public void setPassword(boolean password) {
   1261         setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
   1262     }
   1263 
   1264     /**
   1265      * Gets if the node is scrollable.
   1266      *
   1267      * @return True if the node is scrollable, false otherwise.
   1268      */
   1269     public boolean isScrollable() {
   1270         return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
   1271     }
   1272 
   1273     /**
   1274      * Sets if the node is scrollable.
   1275      * <p>
   1276      *   <strong>Note:</strong> Cannot be called from an
   1277      *   {@link android.accessibilityservice.AccessibilityService}.
   1278      *   This class is made immutable before being delivered to an AccessibilityService.
   1279      * </p>
   1280      *
   1281      * @param scrollable True if the node is scrollable, false otherwise.
   1282      *
   1283      * @throws IllegalStateException If called from an AccessibilityService.
   1284      */
   1285     public void setScrollable(boolean scrollable) {
   1286         enforceNotSealed();
   1287         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
   1288     }
   1289 
   1290     /**
   1291      * Gets if the node is editable.
   1292      *
   1293      * @return True if the node is editable, false otherwise.
   1294      */
   1295     public boolean isEditable() {
   1296         return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
   1297     }
   1298 
   1299     /**
   1300      * Sets whether this node is editable.
   1301      * <p>
   1302      *   <strong>Note:</strong> Cannot be called from an
   1303      *   {@link android.accessibilityservice.AccessibilityService}.
   1304      *   This class is made immutable before being delivered to an AccessibilityService.
   1305      * </p>
   1306      *
   1307      * @param editable True if the node is editable.
   1308      *
   1309      * @throws IllegalStateException If called from an AccessibilityService.
   1310      */
   1311     public void setEditable(boolean editable) {
   1312         setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
   1313     }
   1314 
   1315     /**
   1316      * Gets the package this node comes from.
   1317      *
   1318      * @return The package name.
   1319      */
   1320     public CharSequence getPackageName() {
   1321         return mPackageName;
   1322     }
   1323 
   1324     /**
   1325      * Sets the package this node comes from.
   1326      * <p>
   1327      *   <strong>Note:</strong> Cannot be called from an
   1328      *   {@link android.accessibilityservice.AccessibilityService}.
   1329      *   This class is made immutable before being delivered to an AccessibilityService.
   1330      * </p>
   1331      *
   1332      * @param packageName The package name.
   1333      *
   1334      * @throws IllegalStateException If called from an AccessibilityService.
   1335      */
   1336     public void setPackageName(CharSequence packageName) {
   1337         enforceNotSealed();
   1338         mPackageName = packageName;
   1339     }
   1340 
   1341     /**
   1342      * Gets the class this node comes from.
   1343      *
   1344      * @return The class name.
   1345      */
   1346     public CharSequence getClassName() {
   1347         return mClassName;
   1348     }
   1349 
   1350     /**
   1351      * Sets the class this node comes from.
   1352      * <p>
   1353      *   <strong>Note:</strong> Cannot be called from an
   1354      *   {@link android.accessibilityservice.AccessibilityService}.
   1355      *   This class is made immutable before being delivered to an AccessibilityService.
   1356      * </p>
   1357      *
   1358      * @param className The class name.
   1359      *
   1360      * @throws IllegalStateException If called from an AccessibilityService.
   1361      */
   1362     public void setClassName(CharSequence className) {
   1363         enforceNotSealed();
   1364         mClassName = className;
   1365     }
   1366 
   1367     /**
   1368      * Gets the text of this node.
   1369      *
   1370      * @return The text.
   1371      */
   1372     public CharSequence getText() {
   1373         return mText;
   1374     }
   1375 
   1376     /**
   1377      * Sets the text of this node.
   1378      * <p>
   1379      *   <strong>Note:</strong> Cannot be called from an
   1380      *   {@link android.accessibilityservice.AccessibilityService}.
   1381      *   This class is made immutable before being delivered to an AccessibilityService.
   1382      * </p>
   1383      *
   1384      * @param text The text.
   1385      *
   1386      * @throws IllegalStateException If called from an AccessibilityService.
   1387      */
   1388     public void setText(CharSequence text) {
   1389         enforceNotSealed();
   1390         mText = text;
   1391     }
   1392 
   1393     /**
   1394      * Gets the content description of this node.
   1395      *
   1396      * @return The content description.
   1397      */
   1398     public CharSequence getContentDescription() {
   1399         return mContentDescription;
   1400     }
   1401 
   1402     /**
   1403      * Sets the content description of this node.
   1404      * <p>
   1405      *   <strong>Note:</strong> Cannot be called from an
   1406      *   {@link android.accessibilityservice.AccessibilityService}.
   1407      *   This class is made immutable before being delivered to an AccessibilityService.
   1408      * </p>
   1409      *
   1410      * @param contentDescription The content description.
   1411      *
   1412      * @throws IllegalStateException If called from an AccessibilityService.
   1413      */
   1414     public void setContentDescription(CharSequence contentDescription) {
   1415         enforceNotSealed();
   1416         mContentDescription = contentDescription;
   1417     }
   1418 
   1419     /**
   1420      * Sets the view for which the view represented by this info serves as a
   1421      * label for accessibility purposes.
   1422      *
   1423      * @param labeled The view for which this info serves as a label.
   1424      */
   1425     public void setLabelFor(View labeled) {
   1426         setLabelFor(labeled, UNDEFINED);
   1427     }
   1428 
   1429     /**
   1430      * Sets the view for which the view represented by this info serves as a
   1431      * label for accessibility purposes. If <code>virtualDescendantId</code>
   1432      * is {@link View#NO_ID} the root is set as the labeled.
   1433      * <p>
   1434      * A virtual descendant is an imaginary View that is reported as a part of the view
   1435      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1436      * content to report themselves as a tree of virtual views, thus conveying their
   1437      * logical structure.
   1438      * </p>
   1439      * <p>
   1440      *   <strong>Note:</strong> Cannot be called from an
   1441      *   {@link android.accessibilityservice.AccessibilityService}.
   1442      *   This class is made immutable before being delivered to an AccessibilityService.
   1443      * </p>
   1444      *
   1445      * @param root The root whose virtual descendant serves as a label.
   1446      * @param virtualDescendantId The id of the virtual descendant.
   1447      */
   1448     public void setLabelFor(View root, int virtualDescendantId) {
   1449         enforceNotSealed();
   1450         final int rootAccessibilityViewId = (root != null)
   1451                 ? root.getAccessibilityViewId() : UNDEFINED;
   1452         mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1453     }
   1454 
   1455     /**
   1456      * Gets the node info for which the view represented by this info serves as
   1457      * a label for accessibility purposes.
   1458      * <p>
   1459      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1460      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1461      *     to avoid creating of multiple instances.
   1462      * </p>
   1463      *
   1464      * @return The labeled info.
   1465      */
   1466     public AccessibilityNodeInfo getLabelFor() {
   1467         enforceSealed();
   1468         if (!canPerformRequestOverConnection(mLabelForId)) {
   1469             return null;
   1470         }
   1471         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1472         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
   1473                 mWindowId, mLabelForId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
   1474     }
   1475 
   1476     /**
   1477      * Sets the view which serves as the label of the view represented by
   1478      * this info for accessibility purposes.
   1479      *
   1480      * @param label The view that labels this node's source.
   1481      */
   1482     public void setLabeledBy(View label) {
   1483         setLabeledBy(label, UNDEFINED);
   1484     }
   1485 
   1486     /**
   1487      * Sets the view which serves as the label of the view represented by
   1488      * this info for accessibility purposes. If <code>virtualDescendantId</code>
   1489      * is {@link View#NO_ID} the root is set as the label.
   1490      * <p>
   1491      * A virtual descendant is an imaginary View that is reported as a part of the view
   1492      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1493      * content to report themselves as a tree of virtual views, thus conveying their
   1494      * logical structure.
   1495      * </p>
   1496      * <p>
   1497      *   <strong>Note:</strong> Cannot be called from an
   1498      *   {@link android.accessibilityservice.AccessibilityService}.
   1499      *   This class is made immutable before being delivered to an AccessibilityService.
   1500      * </p>
   1501      *
   1502      * @param root The root whose virtual descendant labels this node's source.
   1503      * @param virtualDescendantId The id of the virtual descendant.
   1504      */
   1505     public void setLabeledBy(View root, int virtualDescendantId) {
   1506         enforceNotSealed();
   1507         final int rootAccessibilityViewId = (root != null)
   1508                 ? root.getAccessibilityViewId() : UNDEFINED;
   1509         mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
   1510     }
   1511 
   1512     /**
   1513      * Gets the node info which serves as the label of the view represented by
   1514      * this info for accessibility purposes.
   1515      * <p>
   1516      *   <strong>Note:</strong> It is a client responsibility to recycle the
   1517      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
   1518      *     to avoid creating of multiple instances.
   1519      * </p>
   1520      *
   1521      * @return The label.
   1522      */
   1523     public AccessibilityNodeInfo getLabeledBy() {
   1524         enforceSealed();
   1525         if (!canPerformRequestOverConnection(mLabeledById)) {
   1526             return null;
   1527         }
   1528         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
   1529         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
   1530                 mWindowId, mLabeledById, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
   1531     }
   1532 
   1533     /**
   1534      * Sets the fully qualified resource name of the source view's id.
   1535      *
   1536      * <p>
   1537      *   <strong>Note:</strong> Cannot be called from an
   1538      *   {@link android.accessibilityservice.AccessibilityService}.
   1539      *   This class is made immutable before being delivered to an AccessibilityService.
   1540      * </p>
   1541      *
   1542      * @param viewIdResName The id resource name.
   1543      */
   1544     public void setViewIdResourceName(String viewIdResName) {
   1545         enforceNotSealed();
   1546         mViewIdResourceName = viewIdResName;
   1547     }
   1548 
   1549     /**
   1550      * Gets the fully qualified resource name of the source view's id.
   1551      *
   1552      * <p>
   1553      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   1554      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
   1555      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
   1556      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   1557      * </p>
   1558 
   1559      * @return The id resource name.
   1560      */
   1561     public String getViewIdResourceName() {
   1562         return mViewIdResourceName;
   1563     }
   1564 
   1565     /**
   1566      * Gets the text selection start.
   1567      *
   1568      * @return The text selection start if there is selection or -1.
   1569      */
   1570     public int getTextSelectionStart() {
   1571         return mTextSelectionStart;
   1572     }
   1573 
   1574     /**
   1575      * Gets the text selection end.
   1576      *
   1577      * @return The text selection end if there is selection or -1.
   1578      */
   1579     public int getTextSelectionEnd() {
   1580         return mTextSelectionEnd;
   1581     }
   1582 
   1583     /**
   1584      * Sets the text selection start and end.
   1585      * <p>
   1586      *   <strong>Note:</strong> Cannot be called from an
   1587      *   {@link android.accessibilityservice.AccessibilityService}.
   1588      *   This class is made immutable before being delivered to an AccessibilityService.
   1589      * </p>
   1590      *
   1591      * @param start The text selection start.
   1592      * @param end The text selection end.
   1593      *
   1594      * @throws IllegalStateException If called from an AccessibilityService.
   1595      */
   1596     public void setTextSelection(int start, int end) {
   1597         enforceNotSealed();
   1598         mTextSelectionStart = start;
   1599         mTextSelectionEnd = end;
   1600     }
   1601 
   1602     /**
   1603      * Gets the value of a boolean property.
   1604      *
   1605      * @param property The property.
   1606      * @return The value.
   1607      */
   1608     private boolean getBooleanProperty(int property) {
   1609         return (mBooleanProperties & property) != 0;
   1610     }
   1611 
   1612     /**
   1613      * Sets a boolean property.
   1614      *
   1615      * @param property The property.
   1616      * @param value The value.
   1617      *
   1618      * @throws IllegalStateException If called from an AccessibilityService.
   1619      */
   1620     private void setBooleanProperty(int property, boolean value) {
   1621         enforceNotSealed();
   1622         if (value) {
   1623             mBooleanProperties |= property;
   1624         } else {
   1625             mBooleanProperties &= ~property;
   1626         }
   1627     }
   1628 
   1629     /**
   1630      * Sets the unique id of the IAccessibilityServiceConnection over which
   1631      * this instance can send requests to the system.
   1632      *
   1633      * @param connectionId The connection id.
   1634      *
   1635      * @hide
   1636      */
   1637     public void setConnectionId(int connectionId) {
   1638         enforceNotSealed();
   1639         mConnectionId = connectionId;
   1640     }
   1641 
   1642     /**
   1643      * {@inheritDoc}
   1644      */
   1645     public int describeContents() {
   1646         return 0;
   1647     }
   1648 
   1649     /**
   1650      * Gets the id of the source node.
   1651      *
   1652      * @return The id.
   1653      *
   1654      * @hide
   1655      */
   1656     public long getSourceNodeId() {
   1657         return mSourceNodeId;
   1658     }
   1659 
   1660     /**
   1661      * Sets if this instance is sealed.
   1662      *
   1663      * @param sealed Whether is sealed.
   1664      *
   1665      * @hide
   1666      */
   1667     public void setSealed(boolean sealed) {
   1668         mSealed = sealed;
   1669     }
   1670 
   1671     /**
   1672      * Gets if this instance is sealed.
   1673      *
   1674      * @return Whether is sealed.
   1675      *
   1676      * @hide
   1677      */
   1678     public boolean isSealed() {
   1679         return mSealed;
   1680     }
   1681 
   1682     /**
   1683      * Enforces that this instance is sealed.
   1684      *
   1685      * @throws IllegalStateException If this instance is not sealed.
   1686      *
   1687      * @hide
   1688      */
   1689     protected void enforceSealed() {
   1690         if (!isSealed()) {
   1691             throw new IllegalStateException("Cannot perform this "
   1692                     + "action on a not sealed instance.");
   1693         }
   1694     }
   1695 
   1696     private void enforceValidFocusDirection(int direction) {
   1697         switch (direction) {
   1698             case View.FOCUS_DOWN:
   1699             case View.FOCUS_UP:
   1700             case View.FOCUS_LEFT:
   1701             case View.FOCUS_RIGHT:
   1702             case View.FOCUS_FORWARD:
   1703             case View.FOCUS_BACKWARD:
   1704                 return;
   1705             default:
   1706                 throw new IllegalArgumentException("Unknown direction: " + direction);
   1707         }
   1708     }
   1709 
   1710     private void enforceValidFocusType(int focusType) {
   1711         switch (focusType) {
   1712             case FOCUS_INPUT:
   1713             case FOCUS_ACCESSIBILITY:
   1714                 return;
   1715             default:
   1716                 throw new IllegalArgumentException("Unknown focus type: " + focusType);
   1717         }
   1718     }
   1719 
   1720     /**
   1721      * Enforces that this instance is not sealed.
   1722      *
   1723      * @throws IllegalStateException If this instance is sealed.
   1724      *
   1725      * @hide
   1726      */
   1727     protected void enforceNotSealed() {
   1728         if (isSealed()) {
   1729             throw new IllegalStateException("Cannot perform this "
   1730                     + "action on a sealed instance.");
   1731         }
   1732     }
   1733 
   1734     /**
   1735      * Returns a cached instance if such is available otherwise a new one
   1736      * and sets the source.
   1737      *
   1738      * @param source The source view.
   1739      * @return An instance.
   1740      *
   1741      * @see #setSource(View)
   1742      */
   1743     public static AccessibilityNodeInfo obtain(View source) {
   1744         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   1745         info.setSource(source);
   1746         return info;
   1747     }
   1748 
   1749     /**
   1750      * Returns a cached instance if such is available otherwise a new one
   1751      * and sets the source.
   1752      *
   1753      * @param root The root of the virtual subtree.
   1754      * @param virtualDescendantId The id of the virtual descendant.
   1755      * @return An instance.
   1756      *
   1757      * @see #setSource(View, int)
   1758      */
   1759     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
   1760         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   1761         info.setSource(root, virtualDescendantId);
   1762         return info;
   1763     }
   1764 
   1765     /**
   1766      * Returns a cached instance if such is available otherwise a new one.
   1767      *
   1768      * @return An instance.
   1769      */
   1770     public static AccessibilityNodeInfo obtain() {
   1771         AccessibilityNodeInfo info = sPool.acquire();
   1772         return (info != null) ? info : new AccessibilityNodeInfo();
   1773     }
   1774 
   1775     /**
   1776      * Returns a cached instance if such is available or a new one is
   1777      * create. The returned instance is initialized from the given
   1778      * <code>info</code>.
   1779      *
   1780      * @param info The other info.
   1781      * @return An instance.
   1782      */
   1783     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
   1784         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
   1785         infoClone.init(info);
   1786         return infoClone;
   1787     }
   1788 
   1789     /**
   1790      * Return an instance back to be reused.
   1791      * <p>
   1792      * <strong>Note:</strong> You must not touch the object after calling this function.
   1793      *
   1794      * @throws IllegalStateException If the info is already recycled.
   1795      */
   1796     public void recycle() {
   1797         clear();
   1798         sPool.release(this);
   1799     }
   1800 
   1801     /**
   1802      * {@inheritDoc}
   1803      * <p>
   1804      *   <strong>Note:</strong> After the instance is written to a parcel it
   1805      *      is recycled. You must not touch the object after calling this function.
   1806      * </p>
   1807      */
   1808     public void writeToParcel(Parcel parcel, int flags) {
   1809         parcel.writeInt(isSealed() ? 1 : 0);
   1810         parcel.writeLong(mSourceNodeId);
   1811         parcel.writeInt(mWindowId);
   1812         parcel.writeLong(mParentNodeId);
   1813         parcel.writeLong(mLabelForId);
   1814         parcel.writeLong(mLabeledById);
   1815         parcel.writeInt(mConnectionId);
   1816 
   1817         SparseLongArray childIds = mChildNodeIds;
   1818         final int childIdsSize = childIds.size();
   1819         parcel.writeInt(childIdsSize);
   1820         for (int i = 0; i < childIdsSize; i++) {
   1821             parcel.writeLong(childIds.valueAt(i));
   1822         }
   1823 
   1824         parcel.writeInt(mBoundsInParent.top);
   1825         parcel.writeInt(mBoundsInParent.bottom);
   1826         parcel.writeInt(mBoundsInParent.left);
   1827         parcel.writeInt(mBoundsInParent.right);
   1828 
   1829         parcel.writeInt(mBoundsInScreen.top);
   1830         parcel.writeInt(mBoundsInScreen.bottom);
   1831         parcel.writeInt(mBoundsInScreen.left);
   1832         parcel.writeInt(mBoundsInScreen.right);
   1833 
   1834         parcel.writeInt(mActions);
   1835 
   1836         parcel.writeInt(mMovementGranularities);
   1837 
   1838         parcel.writeInt(mBooleanProperties);
   1839 
   1840         parcel.writeCharSequence(mPackageName);
   1841         parcel.writeCharSequence(mClassName);
   1842         parcel.writeCharSequence(mText);
   1843         parcel.writeCharSequence(mContentDescription);
   1844         parcel.writeString(mViewIdResourceName);
   1845 
   1846         parcel.writeInt(mTextSelectionStart);
   1847         parcel.writeInt(mTextSelectionEnd);
   1848 
   1849         // Since instances of this class are fetched via synchronous i.e. blocking
   1850         // calls in IPCs we always recycle as soon as the instance is marshaled.
   1851         recycle();
   1852     }
   1853 
   1854     /**
   1855      * Initializes this instance from another one.
   1856      *
   1857      * @param other The other instance.
   1858      */
   1859     private void init(AccessibilityNodeInfo other) {
   1860         mSealed = other.mSealed;
   1861         mSourceNodeId = other.mSourceNodeId;
   1862         mParentNodeId = other.mParentNodeId;
   1863         mLabelForId = other.mLabelForId;
   1864         mLabeledById = other.mLabeledById;
   1865         mWindowId = other.mWindowId;
   1866         mConnectionId = other.mConnectionId;
   1867         mBoundsInParent.set(other.mBoundsInParent);
   1868         mBoundsInScreen.set(other.mBoundsInScreen);
   1869         mPackageName = other.mPackageName;
   1870         mClassName = other.mClassName;
   1871         mText = other.mText;
   1872         mContentDescription = other.mContentDescription;
   1873         mViewIdResourceName = other.mViewIdResourceName;
   1874         mActions= other.mActions;
   1875         mBooleanProperties = other.mBooleanProperties;
   1876         mMovementGranularities = other.mMovementGranularities;
   1877         final int otherChildIdCount = other.mChildNodeIds.size();
   1878         for (int i = 0; i < otherChildIdCount; i++) {
   1879             mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
   1880         }
   1881         mTextSelectionStart = other.mTextSelectionStart;
   1882         mTextSelectionEnd = other.mTextSelectionEnd;
   1883     }
   1884 
   1885     /**
   1886      * Creates a new instance from a {@link Parcel}.
   1887      *
   1888      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
   1889      */
   1890     private void initFromParcel(Parcel parcel) {
   1891         mSealed = (parcel.readInt()  == 1);
   1892         mSourceNodeId = parcel.readLong();
   1893         mWindowId = parcel.readInt();
   1894         mParentNodeId = parcel.readLong();
   1895         mLabelForId = parcel.readLong();
   1896         mLabeledById = parcel.readLong();
   1897         mConnectionId = parcel.readInt();
   1898 
   1899         SparseLongArray childIds = mChildNodeIds;
   1900         final int childrenSize = parcel.readInt();
   1901         for (int i = 0; i < childrenSize; i++) {
   1902             final long childId = parcel.readLong();
   1903             childIds.put(i, childId);
   1904         }
   1905 
   1906         mBoundsInParent.top = parcel.readInt();
   1907         mBoundsInParent.bottom = parcel.readInt();
   1908         mBoundsInParent.left = parcel.readInt();
   1909         mBoundsInParent.right = parcel.readInt();
   1910 
   1911         mBoundsInScreen.top = parcel.readInt();
   1912         mBoundsInScreen.bottom = parcel.readInt();
   1913         mBoundsInScreen.left = parcel.readInt();
   1914         mBoundsInScreen.right = parcel.readInt();
   1915 
   1916         mActions = parcel.readInt();
   1917 
   1918         mMovementGranularities = parcel.readInt();
   1919 
   1920         mBooleanProperties = parcel.readInt();
   1921 
   1922         mPackageName = parcel.readCharSequence();
   1923         mClassName = parcel.readCharSequence();
   1924         mText = parcel.readCharSequence();
   1925         mContentDescription = parcel.readCharSequence();
   1926         mViewIdResourceName = parcel.readString();
   1927 
   1928         mTextSelectionStart = parcel.readInt();
   1929         mTextSelectionEnd = parcel.readInt();
   1930     }
   1931 
   1932     /**
   1933      * Clears the state of this instance.
   1934      */
   1935     private void clear() {
   1936         mSealed = false;
   1937         mSourceNodeId = ROOT_NODE_ID;
   1938         mParentNodeId = ROOT_NODE_ID;
   1939         mLabelForId = ROOT_NODE_ID;
   1940         mLabeledById = ROOT_NODE_ID;
   1941         mWindowId = UNDEFINED;
   1942         mConnectionId = UNDEFINED;
   1943         mMovementGranularities = 0;
   1944         mChildNodeIds.clear();
   1945         mBoundsInParent.set(0, 0, 0, 0);
   1946         mBoundsInScreen.set(0, 0, 0, 0);
   1947         mBooleanProperties = 0;
   1948         mPackageName = null;
   1949         mClassName = null;
   1950         mText = null;
   1951         mContentDescription = null;
   1952         mViewIdResourceName = null;
   1953         mActions = 0;
   1954         mTextSelectionStart = UNDEFINED;
   1955         mTextSelectionEnd = UNDEFINED;
   1956     }
   1957 
   1958     /**
   1959      * Gets the human readable action symbolic name.
   1960      *
   1961      * @param action The action.
   1962      * @return The symbolic name.
   1963      */
   1964     private static String getActionSymbolicName(int action) {
   1965         switch (action) {
   1966             case ACTION_FOCUS:
   1967                 return "ACTION_FOCUS";
   1968             case ACTION_CLEAR_FOCUS:
   1969                 return "ACTION_CLEAR_FOCUS";
   1970             case ACTION_SELECT:
   1971                 return "ACTION_SELECT";
   1972             case ACTION_CLEAR_SELECTION:
   1973                 return "ACTION_CLEAR_SELECTION";
   1974             case ACTION_CLICK:
   1975                 return "ACTION_CLICK";
   1976             case ACTION_LONG_CLICK:
   1977                 return "ACTION_LONG_CLICK";
   1978             case ACTION_ACCESSIBILITY_FOCUS:
   1979                 return "ACTION_ACCESSIBILITY_FOCUS";
   1980             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
   1981                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
   1982             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
   1983                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
   1984             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
   1985                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
   1986             case ACTION_NEXT_HTML_ELEMENT:
   1987                 return "ACTION_NEXT_HTML_ELEMENT";
   1988             case ACTION_PREVIOUS_HTML_ELEMENT:
   1989                 return "ACTION_PREVIOUS_HTML_ELEMENT";
   1990             case ACTION_SCROLL_FORWARD:
   1991                 return "ACTION_SCROLL_FORWARD";
   1992             case ACTION_SCROLL_BACKWARD:
   1993                 return "ACTION_SCROLL_BACKWARD";
   1994             case ACTION_CUT:
   1995                 return "ACTION_CUT";
   1996             case ACTION_COPY:
   1997                 return "ACTION_COPY";
   1998             case ACTION_PASTE:
   1999                 return "ACTION_PASTE";
   2000             case ACTION_SET_SELECTION:
   2001                 return "ACTION_SET_SELECTION";
   2002             default:
   2003                 return"ACTION_UNKNOWN";
   2004         }
   2005     }
   2006 
   2007     /**
   2008      * Gets the human readable movement granularity symbolic name.
   2009      *
   2010      * @param granularity The granularity.
   2011      * @return The symbolic name.
   2012      */
   2013     private static String getMovementGranularitySymbolicName(int granularity) {
   2014         switch (granularity) {
   2015             case MOVEMENT_GRANULARITY_CHARACTER:
   2016                 return "MOVEMENT_GRANULARITY_CHARACTER";
   2017             case MOVEMENT_GRANULARITY_WORD:
   2018                 return "MOVEMENT_GRANULARITY_WORD";
   2019             case MOVEMENT_GRANULARITY_LINE:
   2020                 return "MOVEMENT_GRANULARITY_LINE";
   2021             case MOVEMENT_GRANULARITY_PARAGRAPH:
   2022                 return "MOVEMENT_GRANULARITY_PARAGRAPH";
   2023             case MOVEMENT_GRANULARITY_PAGE:
   2024                 return "MOVEMENT_GRANULARITY_PAGE";
   2025             default:
   2026                 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
   2027         }
   2028     }
   2029 
   2030     private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
   2031         return (mWindowId != UNDEFINED
   2032                 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED
   2033                 && mConnectionId != UNDEFINED);
   2034     }
   2035 
   2036     @Override
   2037     public boolean equals(Object object) {
   2038         if (this == object) {
   2039             return true;
   2040         }
   2041         if (object == null) {
   2042             return false;
   2043         }
   2044         if (getClass() != object.getClass()) {
   2045             return false;
   2046         }
   2047         AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
   2048         if (mSourceNodeId != other.mSourceNodeId) {
   2049             return false;
   2050         }
   2051         if (mWindowId != other.mWindowId) {
   2052             return false;
   2053         }
   2054         return true;
   2055     }
   2056 
   2057     @Override
   2058     public int hashCode() {
   2059         final int prime = 31;
   2060         int result = 1;
   2061         result = prime * result + getAccessibilityViewId(mSourceNodeId);
   2062         result = prime * result + getVirtualDescendantId(mSourceNodeId);
   2063         result = prime * result + mWindowId;
   2064         return result;
   2065     }
   2066 
   2067     @Override
   2068     public String toString() {
   2069         StringBuilder builder = new StringBuilder();
   2070         builder.append(super.toString());
   2071 
   2072         if (DEBUG) {
   2073             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
   2074             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
   2075             builder.append("; mParentNodeId: " + mParentNodeId);
   2076 
   2077             int granularities = mMovementGranularities;
   2078             builder.append("; MovementGranularities: [");
   2079             while (granularities != 0) {
   2080                 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
   2081                 granularities &= ~granularity;
   2082                 builder.append(getMovementGranularitySymbolicName(granularity));
   2083                 if (granularities != 0) {
   2084                     builder.append(", ");
   2085                 }
   2086             }
   2087             builder.append("]");
   2088 
   2089             SparseLongArray childIds = mChildNodeIds;
   2090             builder.append("; childAccessibilityIds: [");
   2091             for (int i = 0, count = childIds.size(); i < count; i++) {
   2092                 builder.append(childIds.valueAt(i));
   2093                 if (i < count - 1) {
   2094                     builder.append(", ");
   2095                 }
   2096             }
   2097             builder.append("]");
   2098         }
   2099 
   2100         builder.append("; boundsInParent: " + mBoundsInParent);
   2101         builder.append("; boundsInScreen: " + mBoundsInScreen);
   2102 
   2103         builder.append("; packageName: ").append(mPackageName);
   2104         builder.append("; className: ").append(mClassName);
   2105         builder.append("; text: ").append(mText);
   2106         builder.append("; contentDescription: ").append(mContentDescription);
   2107         builder.append("; viewIdResName: ").append(mViewIdResourceName);
   2108 
   2109         builder.append("; checkable: ").append(isCheckable());
   2110         builder.append("; checked: ").append(isChecked());
   2111         builder.append("; focusable: ").append(isFocusable());
   2112         builder.append("; focused: ").append(isFocused());
   2113         builder.append("; selected: ").append(isSelected());
   2114         builder.append("; clickable: ").append(isClickable());
   2115         builder.append("; longClickable: ").append(isLongClickable());
   2116         builder.append("; enabled: ").append(isEnabled());
   2117         builder.append("; password: ").append(isPassword());
   2118         builder.append("; scrollable: " + isScrollable());
   2119 
   2120         builder.append("; [");
   2121         for (int actionBits = mActions; actionBits != 0;) {
   2122             final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
   2123             actionBits &= ~action;
   2124             builder.append(getActionSymbolicName(action));
   2125             if (actionBits != 0) {
   2126                 builder.append(", ");
   2127             }
   2128         }
   2129         builder.append("]");
   2130 
   2131         return builder.toString();
   2132     }
   2133 
   2134     /**
   2135      * @see Parcelable.Creator
   2136      */
   2137     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
   2138             new Parcelable.Creator<AccessibilityNodeInfo>() {
   2139         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
   2140             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
   2141             info.initFromParcel(parcel);
   2142             return info;
   2143         }
   2144 
   2145         public AccessibilityNodeInfo[] newArray(int size) {
   2146             return new AccessibilityNodeInfo[size];
   2147         }
   2148     };
   2149 }
   2150