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