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