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