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