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