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