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