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