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