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