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