AccessibilityNodeInfo.java revision 487d8697333b1e7784394b9cd96cb590b047c513
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
2764            int nonLegacyActionCount = 0;
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                } else {
2771                    nonLegacyActionCount++;
2772                }
2773            }
2774            parcel.writeInt(defaultLegacyStandardActions);
2775            parcel.writeInt(nonLegacyActionCount);
2776
2777            for (int i = 0; i < actionCount; i++) {
2778                AccessibilityAction action = mActions.get(i);
2779                if (!isDefaultLegacyStandardAction(action)) {
2780                    parcel.writeInt(action.getId());
2781                    parcel.writeCharSequence(action.getLabel());
2782                }
2783            }
2784        } else {
2785            parcel.writeInt(0);
2786            parcel.writeInt(0);
2787        }
2788
2789        parcel.writeInt(mMaxTextLength);
2790        parcel.writeInt(mMovementGranularities);
2791        parcel.writeInt(mBooleanProperties);
2792
2793        parcel.writeCharSequence(mPackageName);
2794        parcel.writeCharSequence(mClassName);
2795        parcel.writeCharSequence(mText);
2796        parcel.writeCharSequence(mError);
2797        parcel.writeCharSequence(mContentDescription);
2798        parcel.writeString(mViewIdResourceName);
2799
2800        parcel.writeInt(mTextSelectionStart);
2801        parcel.writeInt(mTextSelectionEnd);
2802        parcel.writeInt(mInputType);
2803        parcel.writeInt(mLiveRegion);
2804        parcel.writeInt(mDrawingOrderInParent);
2805
2806        if (mExtras != null) {
2807            parcel.writeInt(1);
2808            parcel.writeBundle(mExtras);
2809        } else {
2810            parcel.writeInt(0);
2811        }
2812
2813        if (mRangeInfo != null) {
2814            parcel.writeInt(1);
2815            parcel.writeInt(mRangeInfo.getType());
2816            parcel.writeFloat(mRangeInfo.getMin());
2817            parcel.writeFloat(mRangeInfo.getMax());
2818            parcel.writeFloat(mRangeInfo.getCurrent());
2819        } else {
2820            parcel.writeInt(0);
2821        }
2822
2823        if (mCollectionInfo != null) {
2824            parcel.writeInt(1);
2825            parcel.writeInt(mCollectionInfo.getRowCount());
2826            parcel.writeInt(mCollectionInfo.getColumnCount());
2827            parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
2828            parcel.writeInt(mCollectionInfo.getSelectionMode());
2829        } else {
2830            parcel.writeInt(0);
2831        }
2832
2833        if (mCollectionItemInfo != null) {
2834            parcel.writeInt(1);
2835            parcel.writeInt(mCollectionItemInfo.getRowIndex());
2836            parcel.writeInt(mCollectionItemInfo.getRowSpan());
2837            parcel.writeInt(mCollectionItemInfo.getColumnIndex());
2838            parcel.writeInt(mCollectionItemInfo.getColumnSpan());
2839            parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
2840            parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
2841        } else {
2842            parcel.writeInt(0);
2843        }
2844
2845        // Since instances of this class are fetched via synchronous i.e. blocking
2846        // calls in IPCs we always recycle as soon as the instance is marshaled.
2847        recycle();
2848    }
2849
2850    /**
2851     * Initializes this instance from another one.
2852     *
2853     * @param other The other instance.
2854     */
2855    private void init(AccessibilityNodeInfo other) {
2856        mSealed = other.mSealed;
2857        mSourceNodeId = other.mSourceNodeId;
2858        mParentNodeId = other.mParentNodeId;
2859        mLabelForId = other.mLabelForId;
2860        mLabeledById = other.mLabeledById;
2861        mTraversalBefore = other.mTraversalBefore;
2862        mTraversalAfter = other.mTraversalAfter;
2863        mWindowId = other.mWindowId;
2864        mConnectionId = other.mConnectionId;
2865        mBoundsInParent.set(other.mBoundsInParent);
2866        mBoundsInScreen.set(other.mBoundsInScreen);
2867        mPackageName = other.mPackageName;
2868        mClassName = other.mClassName;
2869        mText = other.mText;
2870        mError = other.mError;
2871        mContentDescription = other.mContentDescription;
2872        mViewIdResourceName = other.mViewIdResourceName;
2873
2874        final ArrayList<AccessibilityAction> otherActions = other.mActions;
2875        if (otherActions != null && otherActions.size() > 0) {
2876            if (mActions == null) {
2877                mActions = new ArrayList(otherActions);
2878            } else {
2879                mActions.clear();
2880                mActions.addAll(other.mActions);
2881            }
2882        }
2883
2884        mBooleanProperties = other.mBooleanProperties;
2885        mMaxTextLength = other.mMaxTextLength;
2886        mMovementGranularities = other.mMovementGranularities;
2887
2888        final LongArray otherChildNodeIds = other.mChildNodeIds;
2889        if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
2890            if (mChildNodeIds == null) {
2891                mChildNodeIds = otherChildNodeIds.clone();
2892            } else {
2893                mChildNodeIds.clear();
2894                mChildNodeIds.addAll(otherChildNodeIds);
2895            }
2896        }
2897
2898        mTextSelectionStart = other.mTextSelectionStart;
2899        mTextSelectionEnd = other.mTextSelectionEnd;
2900        mInputType = other.mInputType;
2901        mLiveRegion = other.mLiveRegion;
2902        mDrawingOrderInParent = other.mDrawingOrderInParent;
2903        if (other.mExtras != null) {
2904            mExtras = new Bundle(other.mExtras);
2905        } else {
2906            mExtras = null;
2907        }
2908        mRangeInfo = (other.mRangeInfo != null)
2909                ? RangeInfo.obtain(other.mRangeInfo) : null;
2910        mCollectionInfo = (other.mCollectionInfo != null)
2911                ? CollectionInfo.obtain(other.mCollectionInfo) : null;
2912        mCollectionItemInfo =  (other.mCollectionItemInfo != null)
2913                ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
2914    }
2915
2916    /**
2917     * Creates a new instance from a {@link Parcel}.
2918     *
2919     * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
2920     */
2921    private void initFromParcel(Parcel parcel) {
2922        final boolean sealed = (parcel.readInt()  == 1);
2923        mSourceNodeId = parcel.readLong();
2924        mWindowId = parcel.readInt();
2925        mParentNodeId = parcel.readLong();
2926        mLabelForId = parcel.readLong();
2927        mLabeledById = parcel.readLong();
2928        mTraversalBefore = parcel.readLong();
2929        mTraversalAfter = parcel.readLong();
2930
2931        mConnectionId = parcel.readInt();
2932
2933        final int childrenSize = parcel.readInt();
2934        if (childrenSize <= 0) {
2935            mChildNodeIds = null;
2936        } else {
2937            mChildNodeIds = new LongArray(childrenSize);
2938            for (int i = 0; i < childrenSize; i++) {
2939                final long childId = parcel.readLong();
2940                mChildNodeIds.add(childId);
2941            }
2942        }
2943
2944        mBoundsInParent.top = parcel.readInt();
2945        mBoundsInParent.bottom = parcel.readInt();
2946        mBoundsInParent.left = parcel.readInt();
2947        mBoundsInParent.right = parcel.readInt();
2948
2949        mBoundsInScreen.top = parcel.readInt();
2950        mBoundsInScreen.bottom = parcel.readInt();
2951        mBoundsInScreen.left = parcel.readInt();
2952        mBoundsInScreen.right = parcel.readInt();
2953
2954        final int legacyStandardActions = parcel.readInt();
2955        addLegacyStandardActions(legacyStandardActions);
2956        final int nonLegacyActionCount = parcel.readInt();
2957        for (int i = 0; i < nonLegacyActionCount; i++) {
2958            final AccessibilityAction action = new AccessibilityAction(
2959                    parcel.readInt(), parcel.readCharSequence());
2960            addActionUnchecked(action);
2961        }
2962
2963        mMaxTextLength = parcel.readInt();
2964        mMovementGranularities = parcel.readInt();
2965        mBooleanProperties = parcel.readInt();
2966
2967        mPackageName = parcel.readCharSequence();
2968        mClassName = parcel.readCharSequence();
2969        mText = parcel.readCharSequence();
2970        mError = parcel.readCharSequence();
2971        mContentDescription = parcel.readCharSequence();
2972        mViewIdResourceName = parcel.readString();
2973
2974        mTextSelectionStart = parcel.readInt();
2975        mTextSelectionEnd = parcel.readInt();
2976
2977        mInputType = parcel.readInt();
2978        mLiveRegion = parcel.readInt();
2979        mDrawingOrderInParent = parcel.readInt();
2980
2981        if (parcel.readInt() == 1) {
2982            mExtras = parcel.readBundle();
2983        } else {
2984            mExtras = null;
2985        }
2986
2987        if (parcel.readInt() == 1) {
2988            mRangeInfo = RangeInfo.obtain(
2989                    parcel.readInt(),
2990                    parcel.readFloat(),
2991                    parcel.readFloat(),
2992                    parcel.readFloat());
2993        }
2994
2995        if (parcel.readInt() == 1) {
2996            mCollectionInfo = CollectionInfo.obtain(
2997                    parcel.readInt(),
2998                    parcel.readInt(),
2999                    parcel.readInt() == 1,
3000                    parcel.readInt());
3001        }
3002
3003        if (parcel.readInt() == 1) {
3004            mCollectionItemInfo = CollectionItemInfo.obtain(
3005                    parcel.readInt(),
3006                    parcel.readInt(),
3007                    parcel.readInt(),
3008                    parcel.readInt(),
3009                    parcel.readInt() == 1,
3010                    parcel.readInt() == 1);
3011        }
3012
3013        mSealed = sealed;
3014    }
3015
3016    /**
3017     * Clears the state of this instance.
3018     */
3019    private void clear() {
3020        mSealed = false;
3021        mSourceNodeId = ROOT_NODE_ID;
3022        mParentNodeId = ROOT_NODE_ID;
3023        mLabelForId = ROOT_NODE_ID;
3024        mLabeledById = ROOT_NODE_ID;
3025        mTraversalBefore = ROOT_NODE_ID;
3026        mTraversalAfter = ROOT_NODE_ID;
3027        mWindowId = UNDEFINED_ITEM_ID;
3028        mConnectionId = UNDEFINED_CONNECTION_ID;
3029        mMaxTextLength = -1;
3030        mMovementGranularities = 0;
3031        if (mChildNodeIds != null) {
3032            mChildNodeIds.clear();
3033        }
3034        mBoundsInParent.set(0, 0, 0, 0);
3035        mBoundsInScreen.set(0, 0, 0, 0);
3036        mBooleanProperties = 0;
3037        mDrawingOrderInParent = 0;
3038        mPackageName = null;
3039        mClassName = null;
3040        mText = null;
3041        mError = null;
3042        mContentDescription = null;
3043        mViewIdResourceName = null;
3044        if (mActions != null) {
3045            mActions.clear();
3046        }
3047        mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
3048        mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
3049        mInputType = InputType.TYPE_NULL;
3050        mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
3051        mExtras = null;
3052        if (mRangeInfo != null) {
3053            mRangeInfo.recycle();
3054            mRangeInfo = null;
3055        }
3056        if (mCollectionInfo != null) {
3057            mCollectionInfo.recycle();
3058            mCollectionInfo = null;
3059        }
3060        if (mCollectionItemInfo != null) {
3061            mCollectionItemInfo.recycle();
3062            mCollectionItemInfo = null;
3063        }
3064    }
3065
3066    private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
3067        return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
3068                && TextUtils.isEmpty(action.getLabel()));
3069    }
3070
3071    private static AccessibilityAction getActionSingleton(int actionId) {
3072        final int actions = AccessibilityAction.sStandardActions.size();
3073        for (int i = 0; i < actions; i++) {
3074            AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
3075            if (actionId == currentAction.getId()) {
3076                return currentAction;
3077            }
3078        }
3079
3080        return null;
3081    }
3082
3083    private void addLegacyStandardActions(int actionMask) {
3084        int remainingIds = actionMask;
3085        while (remainingIds > 0) {
3086            final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
3087            remainingIds &= ~id;
3088            AccessibilityAction action = getActionSingleton(id);
3089            addAction(action);
3090        }
3091    }
3092
3093    /**
3094     * Gets the human readable action symbolic name.
3095     *
3096     * @param action The action.
3097     * @return The symbolic name.
3098     */
3099    private static String getActionSymbolicName(int action) {
3100        switch (action) {
3101            case ACTION_FOCUS:
3102                return "ACTION_FOCUS";
3103            case ACTION_CLEAR_FOCUS:
3104                return "ACTION_CLEAR_FOCUS";
3105            case ACTION_SELECT:
3106                return "ACTION_SELECT";
3107            case ACTION_CLEAR_SELECTION:
3108                return "ACTION_CLEAR_SELECTION";
3109            case ACTION_CLICK:
3110                return "ACTION_CLICK";
3111            case ACTION_LONG_CLICK:
3112                return "ACTION_LONG_CLICK";
3113            case ACTION_ACCESSIBILITY_FOCUS:
3114                return "ACTION_ACCESSIBILITY_FOCUS";
3115            case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
3116                return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
3117            case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
3118                return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
3119            case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
3120                return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
3121            case ACTION_NEXT_HTML_ELEMENT:
3122                return "ACTION_NEXT_HTML_ELEMENT";
3123            case ACTION_PREVIOUS_HTML_ELEMENT:
3124                return "ACTION_PREVIOUS_HTML_ELEMENT";
3125            case ACTION_SCROLL_FORWARD:
3126                return "ACTION_SCROLL_FORWARD";
3127            case ACTION_SCROLL_BACKWARD:
3128                return "ACTION_SCROLL_BACKWARD";
3129            case ACTION_CUT:
3130                return "ACTION_CUT";
3131            case ACTION_COPY:
3132                return "ACTION_COPY";
3133            case ACTION_PASTE:
3134                return "ACTION_PASTE";
3135            case ACTION_SET_SELECTION:
3136                return "ACTION_SET_SELECTION";
3137            case ACTION_EXPAND:
3138                return "ACTION_EXPAND";
3139            case ACTION_COLLAPSE:
3140                return "ACTION_COLLAPSE";
3141            case ACTION_DISMISS:
3142                return "ACTION_DISMISS";
3143            case ACTION_SET_TEXT:
3144                return "ACTION_SET_TEXT";
3145            case R.id.accessibilityActionShowOnScreen:
3146                return "ACTION_SHOW_ON_SCREEN";
3147            case R.id.accessibilityActionScrollToPosition:
3148                return "ACTION_SCROLL_TO_POSITION";
3149            case R.id.accessibilityActionScrollUp:
3150                return "ACTION_SCROLL_UP";
3151            case R.id.accessibilityActionScrollLeft:
3152                return "ACTION_SCROLL_LEFT";
3153            case R.id.accessibilityActionScrollDown:
3154                return "ACTION_SCROLL_DOWN";
3155            case R.id.accessibilityActionScrollRight:
3156                return "ACTION_SCROLL_RIGHT";
3157            case R.id.accessibilityActionSetProgress:
3158                return "ACTION_SET_PROGRESS";
3159            case R.id.accessibilityActionContextClick:
3160                return "ACTION_CONTEXT_CLICK";
3161            default:
3162                return "ACTION_UNKNOWN";
3163        }
3164    }
3165
3166    /**
3167     * Gets the human readable movement granularity symbolic name.
3168     *
3169     * @param granularity The granularity.
3170     * @return The symbolic name.
3171     */
3172    private static String getMovementGranularitySymbolicName(int granularity) {
3173        switch (granularity) {
3174            case MOVEMENT_GRANULARITY_CHARACTER:
3175                return "MOVEMENT_GRANULARITY_CHARACTER";
3176            case MOVEMENT_GRANULARITY_WORD:
3177                return "MOVEMENT_GRANULARITY_WORD";
3178            case MOVEMENT_GRANULARITY_LINE:
3179                return "MOVEMENT_GRANULARITY_LINE";
3180            case MOVEMENT_GRANULARITY_PARAGRAPH:
3181                return "MOVEMENT_GRANULARITY_PARAGRAPH";
3182            case MOVEMENT_GRANULARITY_PAGE:
3183                return "MOVEMENT_GRANULARITY_PAGE";
3184            default:
3185                throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
3186        }
3187    }
3188
3189    private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
3190        return (mWindowId != UNDEFINED_ITEM_ID
3191                && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID
3192                && mConnectionId != UNDEFINED_CONNECTION_ID);
3193    }
3194
3195    @Override
3196    public boolean equals(Object object) {
3197        if (this == object) {
3198            return true;
3199        }
3200        if (object == null) {
3201            return false;
3202        }
3203        if (getClass() != object.getClass()) {
3204            return false;
3205        }
3206        AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
3207        if (mSourceNodeId != other.mSourceNodeId) {
3208            return false;
3209        }
3210        if (mWindowId != other.mWindowId) {
3211            return false;
3212        }
3213        return true;
3214    }
3215
3216    @Override
3217    public int hashCode() {
3218        final int prime = 31;
3219        int result = 1;
3220        result = prime * result + getAccessibilityViewId(mSourceNodeId);
3221        result = prime * result + getVirtualDescendantId(mSourceNodeId);
3222        result = prime * result + mWindowId;
3223        return result;
3224    }
3225
3226    @Override
3227    public String toString() {
3228        StringBuilder builder = new StringBuilder();
3229        builder.append(super.toString());
3230
3231        if (DEBUG) {
3232            builder.append("; sourceNodeId: " + mSourceNodeId);
3233            builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
3234            builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
3235            builder.append("; mParentNodeId: " + mParentNodeId);
3236            builder.append("; traversalBefore: ").append(mTraversalBefore);
3237            builder.append("; traversalAfter: ").append(mTraversalAfter);
3238
3239            int granularities = mMovementGranularities;
3240            builder.append("; MovementGranularities: [");
3241            while (granularities != 0) {
3242                final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
3243                granularities &= ~granularity;
3244                builder.append(getMovementGranularitySymbolicName(granularity));
3245                if (granularities != 0) {
3246                    builder.append(", ");
3247                }
3248            }
3249            builder.append("]");
3250
3251            builder.append("; childAccessibilityIds: [");
3252            final LongArray childIds = mChildNodeIds;
3253            if (childIds != null) {
3254                for (int i = 0, count = childIds.size(); i < count; i++) {
3255                    builder.append(childIds.get(i));
3256                    if (i < count - 1) {
3257                        builder.append(", ");
3258                    }
3259                }
3260            }
3261            builder.append("]");
3262        }
3263
3264        builder.append("; boundsInParent: " + mBoundsInParent);
3265        builder.append("; boundsInScreen: " + mBoundsInScreen);
3266
3267        builder.append("; packageName: ").append(mPackageName);
3268        builder.append("; className: ").append(mClassName);
3269        builder.append("; text: ").append(mText);
3270        builder.append("; error: ").append(mError);
3271        builder.append("; maxTextLength: ").append(mMaxTextLength);
3272        builder.append("; contentDescription: ").append(mContentDescription);
3273        builder.append("; viewIdResName: ").append(mViewIdResourceName);
3274
3275        builder.append("; checkable: ").append(isCheckable());
3276        builder.append("; checked: ").append(isChecked());
3277        builder.append("; focusable: ").append(isFocusable());
3278        builder.append("; focused: ").append(isFocused());
3279        builder.append("; selected: ").append(isSelected());
3280        builder.append("; clickable: ").append(isClickable());
3281        builder.append("; longClickable: ").append(isLongClickable());
3282        builder.append("; contextClickable: ").append(isContextClickable());
3283        builder.append("; enabled: ").append(isEnabled());
3284        builder.append("; password: ").append(isPassword());
3285        builder.append("; scrollable: ").append(isScrollable());
3286        builder.append("; actions: ").append(mActions);
3287
3288        return builder.toString();
3289    }
3290
3291    private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
3292        if (!canPerformRequestOverConnection(accessibilityId)) {
3293            return null;
3294        }
3295        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
3296        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
3297                mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
3298                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
3299    }
3300
3301    /**
3302     * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
3303     * Each action has a unique id that is mandatory and optional data.
3304     * <p>
3305     * There are three categories of actions:
3306     * <ul>
3307     * <li><strong>Standard actions</strong> - These are actions that are reported and
3308     * handled by the standard UI widgets in the platform. For each standard action
3309     * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
3310     * </li>
3311     * <li><strong>Custom actions action</strong> - These are actions that are reported
3312     * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
3313     * example, an application may define a custom action for clearing the user history.
3314     * </li>
3315     * <li><strong>Overriden standard actions</strong> - These are actions that override
3316     * standard actions to customize them. For example, an app may add a label to the
3317     * standard {@link #ACTION_CLICK} action to announce that this action clears browsing history.
3318     * </ul>
3319     * </p>
3320     * <p>
3321     * Actions are typically added to an {@link AccessibilityNodeInfo} by using
3322     * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within
3323     * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed
3324     * within {@link View#performAccessibilityAction(int, Bundle)}.
3325     * </p>
3326     * <p class="note">
3327     * <strong>Note:</strong> Views which support these actions should invoke
3328     * {@link View#setImportantForAccessibility(int)} with
3329     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService}
3330     * can discover the set of supported actions.
3331     * </p>
3332     */
3333    public static final class AccessibilityAction {
3334
3335        /**
3336         * Action that gives input focus to the node.
3337         */
3338        public static final AccessibilityAction ACTION_FOCUS =
3339                new AccessibilityAction(
3340                        AccessibilityNodeInfo.ACTION_FOCUS, null);
3341
3342        /**
3343         * Action that clears input focus of the node.
3344         */
3345        public static final AccessibilityAction ACTION_CLEAR_FOCUS =
3346                new AccessibilityAction(
3347                        AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
3348
3349        /**
3350         *  Action that selects the node.
3351         */
3352        public static final AccessibilityAction ACTION_SELECT =
3353                new AccessibilityAction(
3354                        AccessibilityNodeInfo.ACTION_SELECT, null);
3355
3356        /**
3357         * Action that deselects the node.
3358         */
3359        public static final AccessibilityAction ACTION_CLEAR_SELECTION =
3360                new AccessibilityAction(
3361                        AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
3362
3363        /**
3364         * Action that clicks on the node info.
3365         */
3366        public static final AccessibilityAction ACTION_CLICK =
3367                new AccessibilityAction(
3368                        AccessibilityNodeInfo.ACTION_CLICK, null);
3369
3370        /**
3371         * Action that long clicks on the node.
3372         */
3373        public static final AccessibilityAction ACTION_LONG_CLICK =
3374                new AccessibilityAction(
3375                        AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
3376
3377        /**
3378         * Action that gives accessibility focus to the node.
3379         */
3380        public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
3381                new AccessibilityAction(
3382                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
3383
3384        /**
3385         * Action that clears accessibility focus of the node.
3386         */
3387        public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
3388                new AccessibilityAction(
3389                        AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3390
3391        /**
3392         * Action that requests to go to the next entity in this node's text
3393         * at a given movement granularity. For example, move to the next character,
3394         * word, etc.
3395         * <p>
3396         * <strong>Arguments:</strong>
3397         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3398         *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3399         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3400         *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3401         * <strong>Example:</strong> Move to the previous character and do not extend selection.
3402         * <code><pre><p>
3403         *   Bundle arguments = new Bundle();
3404         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3405         *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3406         *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3407         *           false);
3408         *   info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
3409         *           arguments);
3410         * </code></pre></p>
3411         * </p>
3412         *
3413         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3414         *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3415         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3416         *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3417         *
3418         * @see AccessibilityNodeInfo#setMovementGranularities(int)
3419         *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3420         * @see AccessibilityNodeInfo#getMovementGranularities()
3421         *  AccessibilityNodeInfo.getMovementGranularities()
3422         *
3423         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3424         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3425         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3426         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3427         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3428         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3429         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3430         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3431         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3432         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3433         */
3434        public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
3435                new AccessibilityAction(
3436                        AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
3437
3438        /**
3439         * Action that requests to go to the previous entity in this node's text
3440         * at a given movement granularity. For example, move to the next character,
3441         * word, etc.
3442         * <p>
3443         * <strong>Arguments:</strong>
3444         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3445         *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3446         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3447         *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3448         * <strong>Example:</strong> Move to the next character and do not extend selection.
3449         * <code><pre><p>
3450         *   Bundle arguments = new Bundle();
3451         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3452         *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3453         *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3454         *           false);
3455         *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
3456         *           arguments);
3457         * </code></pre></p>
3458         * </p>
3459         *
3460         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3461         *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3462         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3463         *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3464         *
3465         * @see AccessibilityNodeInfo#setMovementGranularities(int)
3466         *   AccessibilityNodeInfo.setMovementGranularities(int)
3467         * @see AccessibilityNodeInfo#getMovementGranularities()
3468         *  AccessibilityNodeInfo.getMovementGranularities()
3469         *
3470         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3471         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3472         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3473         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3474         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3475         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3476         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3477         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3478         * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3479         *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3480         */
3481        public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
3482                new AccessibilityAction(
3483                        AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
3484
3485        /**
3486         * Action to move to the next HTML element of a given type. For example, move
3487         * to the BUTTON, INPUT, TABLE, etc.
3488         * <p>
3489         * <strong>Arguments:</strong>
3490         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3491         *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3492         * <strong>Example:</strong>
3493         * <code><pre><p>
3494         *   Bundle arguments = new Bundle();
3495         *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3496         *   info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
3497         * </code></pre></p>
3498         * </p>
3499         */
3500        public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
3501                new AccessibilityAction(
3502                        AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
3503
3504        /**
3505         * Action to move to the previous HTML element of a given type. For example, move
3506         * to the BUTTON, INPUT, TABLE, etc.
3507         * <p>
3508         * <strong>Arguments:</strong>
3509         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3510         *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3511         * <strong>Example:</strong>
3512         * <code><pre><p>
3513         *   Bundle arguments = new Bundle();
3514         *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3515         *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
3516         * </code></pre></p>
3517         * </p>
3518         */
3519        public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
3520                new AccessibilityAction(
3521                        AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
3522
3523        /**
3524         * Action to scroll the node content forward.
3525         */
3526        public static final AccessibilityAction ACTION_SCROLL_FORWARD =
3527                new AccessibilityAction(
3528                        AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
3529
3530        /**
3531         * Action to scroll the node content backward.
3532         */
3533        public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
3534                new AccessibilityAction(
3535                        AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
3536
3537        /**
3538         * Action to copy the current selection to the clipboard.
3539         */
3540        public static final AccessibilityAction ACTION_COPY =
3541                new AccessibilityAction(
3542                        AccessibilityNodeInfo.ACTION_COPY, null);
3543
3544        /**
3545         * Action to paste the current clipboard content.
3546         */
3547        public static final AccessibilityAction ACTION_PASTE =
3548                new AccessibilityAction(
3549                        AccessibilityNodeInfo.ACTION_PASTE, null);
3550
3551        /**
3552         * Action to cut the current selection and place it to the clipboard.
3553         */
3554        public static final AccessibilityAction ACTION_CUT =
3555                new AccessibilityAction(
3556                        AccessibilityNodeInfo.ACTION_CUT, null);
3557
3558        /**
3559         * Action to set the selection. Performing this action with no arguments
3560         * clears the selection.
3561         * <p>
3562         * <strong>Arguments:</strong>
3563         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3564         *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
3565         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3566         *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
3567         * <strong>Example:</strong>
3568         * <code><pre><p>
3569         *   Bundle arguments = new Bundle();
3570         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
3571         *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
3572         *   info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
3573         * </code></pre></p>
3574         * </p>
3575         *
3576         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3577         *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
3578         * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3579         *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
3580         */
3581        public static final AccessibilityAction ACTION_SET_SELECTION =
3582                new AccessibilityAction(
3583                        AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
3584
3585        /**
3586         * Action to expand an expandable node.
3587         */
3588        public static final AccessibilityAction ACTION_EXPAND =
3589                new AccessibilityAction(
3590                        AccessibilityNodeInfo.ACTION_EXPAND, null);
3591
3592        /**
3593         * Action to collapse an expandable node.
3594         */
3595        public static final AccessibilityAction ACTION_COLLAPSE =
3596                new AccessibilityAction(
3597                        AccessibilityNodeInfo.ACTION_COLLAPSE, null);
3598
3599        /**
3600         * Action to dismiss a dismissable node.
3601         */
3602        public static final AccessibilityAction ACTION_DISMISS =
3603                new AccessibilityAction(
3604                        AccessibilityNodeInfo.ACTION_DISMISS, null);
3605
3606        /**
3607         * Action that sets the text of the node. Performing the action without argument,
3608         * using <code> null</code> or empty {@link CharSequence} will clear the text. This
3609         * action will also put the cursor at the end of text.
3610         * <p>
3611         * <strong>Arguments:</strong>
3612         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
3613         *  AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
3614         * <strong>Example:</strong>
3615         * <code><pre><p>
3616         *   Bundle arguments = new Bundle();
3617         *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
3618         *       "android");
3619         *   info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
3620         * </code></pre></p>
3621         */
3622        public static final AccessibilityAction ACTION_SET_TEXT =
3623                new AccessibilityAction(
3624                        AccessibilityNodeInfo.ACTION_SET_TEXT, null);
3625
3626        /**
3627         * Action that requests the node make its bounding rectangle visible
3628         * on the screen, scrolling if necessary just enough.
3629         *
3630         * @see View#requestRectangleOnScreen(Rect)
3631         */
3632        public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
3633                new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
3634
3635        /**
3636         * Action that scrolls the node to make the specified collection
3637         * position visible on screen.
3638         * <p>
3639         * <strong>Arguments:</strong>
3640         * <ul>
3641         *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
3642         *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
3643         * <ul>
3644         *
3645         * @see AccessibilityNodeInfo#getCollectionInfo()
3646         */
3647        public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
3648                new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
3649
3650        /**
3651         * Action to scroll the node content up.
3652         */
3653        public static final AccessibilityAction ACTION_SCROLL_UP =
3654                new AccessibilityAction(R.id.accessibilityActionScrollUp, null);
3655
3656        /**
3657         * Action to scroll the node content left.
3658         */
3659        public static final AccessibilityAction ACTION_SCROLL_LEFT =
3660                new AccessibilityAction(R.id.accessibilityActionScrollLeft, null);
3661
3662        /**
3663         * Action to scroll the node content down.
3664         */
3665        public static final AccessibilityAction ACTION_SCROLL_DOWN =
3666                new AccessibilityAction(R.id.accessibilityActionScrollDown, null);
3667
3668        /**
3669         * Action to scroll the node content right.
3670         */
3671        public static final AccessibilityAction ACTION_SCROLL_RIGHT =
3672                new AccessibilityAction(R.id.accessibilityActionScrollRight, null);
3673
3674        /**
3675         * Action that context clicks the node.
3676         */
3677        public static final AccessibilityAction ACTION_CONTEXT_CLICK =
3678                new AccessibilityAction(R.id.accessibilityActionContextClick, null);
3679
3680        /**
3681         * Action that sets progress between {@link  RangeInfo#getMin() RangeInfo.getMin()} and
3682         * {@link  RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as
3683         * {@link RangeInfo#getType() RangeInfo.getType()}
3684         * <p>
3685         * <strong>Arguments:</strong>
3686         * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE}
3687         *
3688         * @see RangeInfo
3689         */
3690        public static final AccessibilityAction ACTION_SET_PROGRESS =
3691                new AccessibilityAction(R.id.accessibilityActionSetProgress, null);
3692
3693        private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
3694        static {
3695            sStandardActions.add(ACTION_FOCUS);
3696            sStandardActions.add(ACTION_CLEAR_FOCUS);
3697            sStandardActions.add(ACTION_SELECT);
3698            sStandardActions.add(ACTION_CLEAR_SELECTION);
3699            sStandardActions.add(ACTION_CLICK);
3700            sStandardActions.add(ACTION_LONG_CLICK);
3701            sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
3702            sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
3703            sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
3704            sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
3705            sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
3706            sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
3707            sStandardActions.add(ACTION_SCROLL_FORWARD);
3708            sStandardActions.add(ACTION_SCROLL_BACKWARD);
3709            sStandardActions.add(ACTION_COPY);
3710            sStandardActions.add(ACTION_PASTE);
3711            sStandardActions.add(ACTION_CUT);
3712            sStandardActions.add(ACTION_SET_SELECTION);
3713            sStandardActions.add(ACTION_EXPAND);
3714            sStandardActions.add(ACTION_COLLAPSE);
3715            sStandardActions.add(ACTION_DISMISS);
3716            sStandardActions.add(ACTION_SET_TEXT);
3717            sStandardActions.add(ACTION_SHOW_ON_SCREEN);
3718            sStandardActions.add(ACTION_SCROLL_TO_POSITION);
3719            sStandardActions.add(ACTION_SCROLL_UP);
3720            sStandardActions.add(ACTION_SCROLL_LEFT);
3721            sStandardActions.add(ACTION_SCROLL_DOWN);
3722            sStandardActions.add(ACTION_SCROLL_RIGHT);
3723            sStandardActions.add(ACTION_SET_PROGRESS);
3724            sStandardActions.add(ACTION_CONTEXT_CLICK);
3725        }
3726
3727        private final int mActionId;
3728        private final CharSequence mLabel;
3729
3730        /**
3731         * Creates a new AccessibilityAction. For adding a standard action without a specific label,
3732         * use the static constants.
3733         *
3734         * You can also override the description for one the standard actions. Below is an example
3735         * how to override the standard click action by adding a custom label:
3736         * <pre>
3737         *   AccessibilityAction action = new AccessibilityAction(
3738         *           AccessibilityAction.ACTION_ACTION_CLICK, getLocalizedLabel());
3739         *   node.addAction(action);
3740         * </pre>
3741         *
3742         * @param actionId The id for this action. This should either be one of the
3743         *                 standard actions or a specific action for your app. In that case it is
3744         *                 required to use a resource identifier.
3745         * @param label The label for the new AccessibilityAction.
3746         */
3747        public AccessibilityAction(int actionId, @Nullable CharSequence label) {
3748            if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
3749                throw new IllegalArgumentException("Invalid standard action id");
3750            }
3751
3752            mActionId = actionId;
3753            mLabel = label;
3754        }
3755
3756        /**
3757         * Gets the id for this action.
3758         *
3759         * @return The action id.
3760         */
3761        public int getId() {
3762            return mActionId;
3763        }
3764
3765        /**
3766         * Gets the label for this action. Its purpose is to describe the
3767         * action to user.
3768         *
3769         * @return The label.
3770         */
3771        public CharSequence getLabel() {
3772            return mLabel;
3773        }
3774
3775        @Override
3776        public int hashCode() {
3777            return mActionId;
3778        }
3779
3780        @Override
3781        public boolean equals(Object other) {
3782            if (other == null) {
3783                return false;
3784            }
3785
3786            if (other == this) {
3787                return true;
3788            }
3789
3790            if (getClass() != other.getClass()) {
3791                return false;
3792            }
3793
3794            return mActionId == ((AccessibilityAction)other).mActionId;
3795        }
3796
3797        @Override
3798        public String toString() {
3799            return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
3800        }
3801    }
3802
3803    /**
3804     * Class with information if a node is a range. Use
3805     * {@link RangeInfo#obtain(int, float, float, float)} to get an instance.
3806     */
3807    public static final class RangeInfo {
3808        private static final int MAX_POOL_SIZE = 10;
3809
3810        /** Range type: integer. */
3811        public static final int RANGE_TYPE_INT = 0;
3812        /** Range type: float. */
3813        public static final int RANGE_TYPE_FLOAT = 1;
3814        /** Range type: percent with values from zero to one.*/
3815        public static final int RANGE_TYPE_PERCENT = 2;
3816
3817        private static final SynchronizedPool<RangeInfo> sPool =
3818                new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
3819
3820        private int mType;
3821        private float mMin;
3822        private float mMax;
3823        private float mCurrent;
3824
3825        /**
3826         * Obtains a pooled instance that is a clone of another one.
3827         *
3828         * @param other The instance to clone.
3829         *
3830         * @hide
3831         */
3832        public static RangeInfo obtain(RangeInfo other) {
3833            return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
3834        }
3835
3836        /**
3837         * Obtains a pooled instance.
3838         *
3839         * @param type The type of the range.
3840         * @param min The min value.
3841         * @param max The max value.
3842         * @param current The current value.
3843         */
3844        public static RangeInfo obtain(int type, float min, float max, float current) {
3845            RangeInfo info = sPool.acquire();
3846            if (info == null) {
3847                return new RangeInfo(type, min, max, current);
3848            }
3849
3850            info.mType = type;
3851            info.mMin = min;
3852            info.mMax = max;
3853            info.mCurrent = current;
3854            return info;
3855        }
3856
3857        /**
3858         * Creates a new range.
3859         *
3860         * @param type The type of the range.
3861         * @param min The min value.
3862         * @param max The max value.
3863         * @param current The current value.
3864         */
3865        private RangeInfo(int type, float min, float max, float current) {
3866            mType = type;
3867            mMin = min;
3868            mMax = max;
3869            mCurrent = current;
3870        }
3871
3872        /**
3873         * Gets the range type.
3874         *
3875         * @return The range type.
3876         *
3877         * @see #RANGE_TYPE_INT
3878         * @see #RANGE_TYPE_FLOAT
3879         * @see #RANGE_TYPE_PERCENT
3880         */
3881        public int getType() {
3882            return mType;
3883        }
3884
3885        /**
3886         * Gets the min value.
3887         *
3888         * @return The min value.
3889         */
3890        public float getMin() {
3891            return mMin;
3892        }
3893
3894        /**
3895         * Gets the max value.
3896         *
3897         * @return The max value.
3898         */
3899        public float getMax() {
3900            return mMax;
3901        }
3902
3903        /**
3904         * Gets the current value.
3905         *
3906         * @return The current value.
3907         */
3908        public float getCurrent() {
3909            return mCurrent;
3910        }
3911
3912        /**
3913         * Recycles this instance.
3914         */
3915        void recycle() {
3916            clear();
3917            sPool.release(this);
3918        }
3919
3920        private void clear() {
3921            mType = 0;
3922            mMin = 0;
3923            mMax = 0;
3924            mCurrent = 0;
3925        }
3926    }
3927
3928    /**
3929     * Class with information if a node is a collection. Use
3930     * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance.
3931     * <p>
3932     * A collection of items has rows and columns and may be hierarchical.
3933     * For example, a horizontal list is a collection with one column, as
3934     * many rows as the list items, and is not hierarchical; A table is a
3935     * collection with several rows, several columns, and is not hierarchical;
3936     * A vertical tree is a hierarchical collection with one column and
3937     * as many rows as the first level children.
3938     * </p>
3939     */
3940    public static final class CollectionInfo {
3941        /** Selection mode where items are not selectable. */
3942        public static final int SELECTION_MODE_NONE = 0;
3943
3944        /** Selection mode where a single item may be selected. */
3945        public static final int SELECTION_MODE_SINGLE = 1;
3946
3947        /** Selection mode where multiple items may be selected. */
3948        public static final int SELECTION_MODE_MULTIPLE = 2;
3949
3950        private static final int MAX_POOL_SIZE = 20;
3951
3952        private static final SynchronizedPool<CollectionInfo> sPool =
3953                new SynchronizedPool<>(MAX_POOL_SIZE);
3954
3955        private int mRowCount;
3956        private int mColumnCount;
3957        private boolean mHierarchical;
3958        private int mSelectionMode;
3959
3960        /**
3961         * Obtains a pooled instance that is a clone of another one.
3962         *
3963         * @param other The instance to clone.
3964         * @hide
3965         */
3966        public static CollectionInfo obtain(CollectionInfo other) {
3967            return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
3968                    other.mSelectionMode);
3969        }
3970
3971        /**
3972         * Obtains a pooled instance.
3973         *
3974         * @param rowCount The number of rows.
3975         * @param columnCount The number of columns.
3976         * @param hierarchical Whether the collection is hierarchical.
3977         */
3978        public static CollectionInfo obtain(int rowCount, int columnCount,
3979                boolean hierarchical) {
3980            return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
3981        }
3982
3983        /**
3984         * Obtains a pooled instance.
3985         *
3986         * @param rowCount The number of rows.
3987         * @param columnCount The number of columns.
3988         * @param hierarchical Whether the collection is hierarchical.
3989         * @param selectionMode The collection's selection mode, one of:
3990         *            <ul>
3991         *            <li>{@link #SELECTION_MODE_NONE}
3992         *            <li>{@link #SELECTION_MODE_SINGLE}
3993         *            <li>{@link #SELECTION_MODE_MULTIPLE}
3994         *            </ul>
3995         */
3996        public static CollectionInfo obtain(int rowCount, int columnCount,
3997                boolean hierarchical, int selectionMode) {
3998           final CollectionInfo info = sPool.acquire();
3999            if (info == null) {
4000                return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
4001            }
4002
4003            info.mRowCount = rowCount;
4004            info.mColumnCount = columnCount;
4005            info.mHierarchical = hierarchical;
4006            info.mSelectionMode = selectionMode;
4007            return info;
4008        }
4009
4010        /**
4011         * Creates a new instance.
4012         *
4013         * @param rowCount The number of rows.
4014         * @param columnCount The number of columns.
4015         * @param hierarchical Whether the collection is hierarchical.
4016         * @param selectionMode The collection's selection mode.
4017         */
4018        private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
4019                int selectionMode) {
4020            mRowCount = rowCount;
4021            mColumnCount = columnCount;
4022            mHierarchical = hierarchical;
4023            mSelectionMode = selectionMode;
4024        }
4025
4026        /**
4027         * Gets the number of rows.
4028         *
4029         * @return The row count.
4030         */
4031        public int getRowCount() {
4032            return mRowCount;
4033        }
4034
4035        /**
4036         * Gets the number of columns.
4037         *
4038         * @return The column count.
4039         */
4040        public int getColumnCount() {
4041            return mColumnCount;
4042        }
4043
4044        /**
4045         * Gets if the collection is a hierarchically ordered.
4046         *
4047         * @return Whether the collection is hierarchical.
4048         */
4049        public boolean isHierarchical() {
4050            return mHierarchical;
4051        }
4052
4053        /**
4054         * Gets the collection's selection mode.
4055         *
4056         * @return The collection's selection mode, one of:
4057         *         <ul>
4058         *         <li>{@link #SELECTION_MODE_NONE}
4059         *         <li>{@link #SELECTION_MODE_SINGLE}
4060         *         <li>{@link #SELECTION_MODE_MULTIPLE}
4061         *         </ul>
4062         */
4063        public int getSelectionMode() {
4064            return mSelectionMode;
4065        }
4066
4067        /**
4068         * Recycles this instance.
4069         */
4070        void recycle() {
4071            clear();
4072            sPool.release(this);
4073        }
4074
4075        private void clear() {
4076            mRowCount = 0;
4077            mColumnCount = 0;
4078            mHierarchical = false;
4079            mSelectionMode = SELECTION_MODE_NONE;
4080        }
4081    }
4082
4083    /**
4084     * Class with information if a node is a collection item. Use
4085     * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
4086     * to get an instance.
4087     * <p>
4088     * A collection item is contained in a collection, it starts at
4089     * a given row and column in the collection, and spans one or
4090     * more rows and columns. For example, a header of two related
4091     * table columns starts at the first row and the first column,
4092     * spans one row and two columns.
4093     * </p>
4094     */
4095    public static final class CollectionItemInfo {
4096        private static final int MAX_POOL_SIZE = 20;
4097
4098        private static final SynchronizedPool<CollectionItemInfo> sPool =
4099                new SynchronizedPool<>(MAX_POOL_SIZE);
4100
4101        /**
4102         * Obtains a pooled instance that is a clone of another one.
4103         *
4104         * @param other The instance to clone.
4105         * @hide
4106         */
4107        public static CollectionItemInfo obtain(CollectionItemInfo other) {
4108            return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
4109                    other.mColumnSpan, other.mHeading, other.mSelected);
4110        }
4111
4112        /**
4113         * Obtains a pooled instance.
4114         *
4115         * @param rowIndex The row index at which the item is located.
4116         * @param rowSpan The number of rows the item spans.
4117         * @param columnIndex The column index at which the item is located.
4118         * @param columnSpan The number of columns the item spans.
4119         * @param heading Whether the item is a heading.
4120         */
4121        public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4122                int columnIndex, int columnSpan, boolean heading) {
4123            return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
4124        }
4125
4126        /**
4127         * Obtains a pooled instance.
4128         *
4129         * @param rowIndex The row index at which the item is located.
4130         * @param rowSpan The number of rows the item spans.
4131         * @param columnIndex The column index at which the item is located.
4132         * @param columnSpan The number of columns the item spans.
4133         * @param heading Whether the item is a heading.
4134         * @param selected Whether the item is selected.
4135         */
4136        public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4137                int columnIndex, int columnSpan, boolean heading, boolean selected) {
4138            final CollectionItemInfo info = sPool.acquire();
4139            if (info == null) {
4140                return new CollectionItemInfo(
4141                        rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
4142            }
4143
4144            info.mRowIndex = rowIndex;
4145            info.mRowSpan = rowSpan;
4146            info.mColumnIndex = columnIndex;
4147            info.mColumnSpan = columnSpan;
4148            info.mHeading = heading;
4149            info.mSelected = selected;
4150            return info;
4151        }
4152
4153        private boolean mHeading;
4154        private int mColumnIndex;
4155        private int mRowIndex;
4156        private int mColumnSpan;
4157        private int mRowSpan;
4158        private boolean mSelected;
4159
4160        /**
4161         * Creates a new instance.
4162         *
4163         * @param rowIndex The row index at which the item is located.
4164         * @param rowSpan The number of rows the item spans.
4165         * @param columnIndex The column index at which the item is located.
4166         * @param columnSpan The number of columns the item spans.
4167         * @param heading Whether the item is a heading.
4168         */
4169        private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
4170                boolean heading, boolean selected) {
4171            mRowIndex = rowIndex;
4172            mRowSpan = rowSpan;
4173            mColumnIndex = columnIndex;
4174            mColumnSpan = columnSpan;
4175            mHeading = heading;
4176            mSelected = selected;
4177        }
4178
4179        /**
4180         * Gets the column index at which the item is located.
4181         *
4182         * @return The column index.
4183         */
4184        public int getColumnIndex() {
4185            return mColumnIndex;
4186        }
4187
4188        /**
4189         * Gets the row index at which the item is located.
4190         *
4191         * @return The row index.
4192         */
4193        public int getRowIndex() {
4194            return mRowIndex;
4195        }
4196
4197        /**
4198         * Gets the number of columns the item spans.
4199         *
4200         * @return The column span.
4201         */
4202        public int getColumnSpan() {
4203            return mColumnSpan;
4204        }
4205
4206        /**
4207         * Gets the number of rows the item spans.
4208         *
4209         * @return The row span.
4210         */
4211        public int getRowSpan() {
4212            return mRowSpan;
4213        }
4214
4215        /**
4216         * Gets if the collection item is a heading. For example, section
4217         * heading, table header, etc.
4218         *
4219         * @return If the item is a heading.
4220         */
4221        public boolean isHeading() {
4222            return mHeading;
4223        }
4224
4225        /**
4226         * Gets if the collection item is selected.
4227         *
4228         * @return If the item is selected.
4229         */
4230        public boolean isSelected() {
4231            return mSelected;
4232        }
4233
4234        /**
4235         * Recycles this instance.
4236         */
4237        void recycle() {
4238            clear();
4239            sPool.release(this);
4240        }
4241
4242        private void clear() {
4243            mColumnIndex = 0;
4244            mColumnSpan = 0;
4245            mRowIndex = 0;
4246            mRowSpan = 0;
4247            mHeading = false;
4248            mSelected = false;
4249        }
4250    }
4251
4252    /**
4253     * @see android.os.Parcelable.Creator
4254     */
4255    public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
4256            new Parcelable.Creator<AccessibilityNodeInfo>() {
4257        @Override
4258        public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
4259            AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
4260            info.initFromParcel(parcel);
4261            return info;
4262        }
4263
4264        @Override
4265        public AccessibilityNodeInfo[] newArray(int size) {
4266            return new AccessibilityNodeInfo[size];
4267        }
4268    };
4269}
4270