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