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