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