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