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