• 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 android.accessibilityservice.AccessibilityService;
20 import android.accessibilityservice.AccessibilityServiceInfo;
21 import android.annotation.Nullable;
22 import android.graphics.Rect;
23 import android.os.Bundle;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.text.InputType;
27 import android.text.TextUtils;
28 import android.util.ArraySet;
29 import android.util.LongArray;
30 import android.util.Pools.SynchronizedPool;
31 import android.view.View;
32 
33 import com.android.internal.R;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 
39 /**
40  * This class represents a node of the window content as well as actions that
41  * can be requested from its source. From the point of view of an
42  * {@link android.accessibilityservice.AccessibilityService} a window's content is
43  * presented as a tree of accessibility node infos, which may or may not map one-to-one
44  * to the view hierarchy. In other words, a custom view is free to report itself as
45  * a tree of accessibility node info.
46  * </p>
47  * <p>
48  * Once an accessibility node info is delivered to an accessibility service it is
49  * made immutable and calling a state mutation method generates an error.
50  * </p>
51  * <p>
52  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
53  * details about how to obtain a handle to window content as a tree of accessibility
54  * node info as well as details about the security model.
55  * </p>
56  * <div class="special reference">
57  * <h3>Developer Guides</h3>
58  * <p>For more information about making applications accessible, read the
59  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
60  * developer guide.</p>
61  * </div>
62  *
63  * @see android.accessibilityservice.AccessibilityService
64  * @see AccessibilityEvent
65  * @see AccessibilityManager
66  */
67 public class AccessibilityNodeInfo implements Parcelable {
68 
69     private static final boolean DEBUG = false;
70 
71     /** @hide */
72     public static final int UNDEFINED_CONNECTION_ID = -1;
73 
74     /** @hide */
75     public static final int UNDEFINED_SELECTION_INDEX = -1;
76 
77     /** @hide */
78     public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE;
79 
80     /** @hide */
81     public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID);
82 
83     /** @hide */
84     public static final int ACTIVE_WINDOW_ID = UNDEFINED_ITEM_ID;
85 
86     /** @hide */
87     public static final int ANY_WINDOW_ID = -2;
88 
89     /** @hide */
90     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
91 
92     /** @hide */
93     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
94 
95     /** @hide */
96     public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
97 
98     /** @hide */
99     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
100 
101     /** @hide */
102     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
103 
104     // Actions.
105 
106     /**
107      * Action that gives input focus to the node.
108      */
109     public static final int ACTION_FOCUS =  0x00000001;
110 
111     /**
112      * Action that clears input focus of the node.
113      */
114     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
115 
116     /**
117      * Action that selects the node.
118      */
119     public static final int ACTION_SELECT = 0x00000004;
120 
121     /**
122      * Action that deselects the node.
123      */
124     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
125 
126     /**
127      * Action that clicks on the node info.
128      *
129      * See {@link AccessibilityAction#ACTION_CLICK}
130      */
131     public static final int ACTION_CLICK = 0x00000010;
132 
133     /**
134      * Action that long clicks on the node.
135      */
136     public static final int ACTION_LONG_CLICK = 0x00000020;
137 
138     /**
139      * Action that gives accessibility focus to the node.
140      */
141     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
142 
143     /**
144      * Action that clears accessibility focus of the node.
145      */
146     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
147 
148     /**
149      * Action that requests to go to the next entity in this node's text
150      * at a given movement granularity. For example, move to the next character,
151      * word, etc.
152      * <p>
153      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
154      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
155      * <strong>Example:</strong> Move to the previous character and do not extend selection.
156      * <code><pre><p>
157      *   Bundle arguments = new Bundle();
158      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
159      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
160      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
161      *           false);
162      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
163      * </code></pre></p>
164      * </p>
165      *
166      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
167      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
168      *
169      * @see #setMovementGranularities(int)
170      * @see #getMovementGranularities()
171      *
172      * @see #MOVEMENT_GRANULARITY_CHARACTER
173      * @see #MOVEMENT_GRANULARITY_WORD
174      * @see #MOVEMENT_GRANULARITY_LINE
175      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
176      * @see #MOVEMENT_GRANULARITY_PAGE
177      */
178     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
179 
180     /**
181      * Action that requests to go to the previous entity in this node's text
182      * at a given movement granularity. For example, move to the next character,
183      * word, etc.
184      * <p>
185      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
186      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
187      * <strong>Example:</strong> Move to the next character and do not extend selection.
188      * <code><pre><p>
189      *   Bundle arguments = new Bundle();
190      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
191      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
192      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
193      *           false);
194      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
195      *           arguments);
196      * </code></pre></p>
197      * </p>
198      *
199      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
200      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
201      *
202      * @see #setMovementGranularities(int)
203      * @see #getMovementGranularities()
204      *
205      * @see #MOVEMENT_GRANULARITY_CHARACTER
206      * @see #MOVEMENT_GRANULARITY_WORD
207      * @see #MOVEMENT_GRANULARITY_LINE
208      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
209      * @see #MOVEMENT_GRANULARITY_PAGE
210      */
211     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
212 
213     /**
214      * Action to move to the next HTML element of a given type. For example, move
215      * to the BUTTON, INPUT, TABLE, etc.
216      * <p>
217      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
218      * <strong>Example:</strong>
219      * <code><pre><p>
220      *   Bundle arguments = new Bundle();
221      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
222      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
223      * </code></pre></p>
224      * </p>
225      */
226     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
227 
228     /**
229      * Action to move to the previous HTML element of a given type. For example, move
230      * to the BUTTON, INPUT, TABLE, etc.
231      * <p>
232      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
233      * <strong>Example:</strong>
234      * <code><pre><p>
235      *   Bundle arguments = new Bundle();
236      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
237      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
238      * </code></pre></p>
239      * </p>
240      */
241     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
242 
243     /**
244      * Action to scroll the node content forward.
245      */
246     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
247 
248     /**
249      * Action to scroll the node content backward.
250      */
251     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
252 
253     /**
254      * Action to copy the current selection to the clipboard.
255      */
256     public static final int ACTION_COPY = 0x00004000;
257 
258     /**
259      * Action to paste the current clipboard content.
260      */
261     public static final int ACTION_PASTE = 0x00008000;
262 
263     /**
264      * Action to cut the current selection and place it to the clipboard.
265      */
266     public static final int ACTION_CUT = 0x00010000;
267 
268     /**
269      * Action to set the selection. Performing this action with no arguments
270      * clears the selection.
271      * <p>
272      * <strong>Arguments:</strong>
273      * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
274      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
275      * <strong>Example:</strong>
276      * <code><pre><p>
277      *   Bundle arguments = new Bundle();
278      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
279      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
280      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
281      * </code></pre></p>
282      * </p>
283      *
284      * @see #ACTION_ARGUMENT_SELECTION_START_INT
285      * @see #ACTION_ARGUMENT_SELECTION_END_INT
286      */
287     public static final int ACTION_SET_SELECTION = 0x00020000;
288 
289     /**
290      * Action to expand an expandable node.
291      */
292     public static final int ACTION_EXPAND = 0x00040000;
293 
294     /**
295      * Action to collapse an expandable node.
296      */
297     public static final int ACTION_COLLAPSE = 0x00080000;
298 
299     /**
300      * Action to dismiss a dismissable node.
301      */
302     public static final int ACTION_DISMISS = 0x00100000;
303 
304     /**
305      * Action that sets the text of the node. Performing the action without argument, using <code>
306      * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
307      * cursor at the end of text.
308      * <p>
309      * <strong>Arguments:</strong>
310      * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
311      * <strong>Example:</strong>
312      * <code><pre><p>
313      *   Bundle arguments = new Bundle();
314      *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
315      *       "android");
316      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
317      * </code></pre></p>
318      */
319     public static final int ACTION_SET_TEXT = 0x00200000;
320 
321     private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
322 
323     /**
324      * Mask to see if the value is larger than the largest ACTION_ constant
325      */
326     private static final int ACTION_TYPE_MASK = 0xFF000000;
327 
328     // Action arguments
329 
330     /**
331      * Argument for which movement granularity to be used when traversing the node text.
332      * <p>
333      * <strong>Type:</strong> int<br>
334      * <strong>Actions:</strong>
335      * <ul>
336      *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
337      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
338      * </ul>
339      * </p>
340      *
341      * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
342      * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
343      */
344     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
345             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
346 
347     /**
348      * Argument for which HTML element to get moving to the next/previous HTML element.
349      * <p>
350      * <strong>Type:</strong> String<br>
351      * <strong>Actions:</strong>
352      * <ul>
353      *     <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li>
354      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li>
355      * </ul>
356      * </p>
357      *
358      * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT
359      * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT
360      */
361     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
362             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
363 
364     /**
365      * Argument for whether when moving at granularity to extend the selection
366      * or to move it otherwise.
367      * <p>
368      * <strong>Type:</strong> boolean<br>
369      * <strong>Actions:</strong>
370      * <ul>
371      *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
372      *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
373      * </ul>
374      *
375      * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
376      * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
377      */
378     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
379             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
380 
381     /**
382      * Argument for specifying the selection start.
383      * <p>
384      * <strong>Type:</strong> int<br>
385      * <strong>Actions:</strong>
386      * <ul>
387      *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
388      * </ul>
389      *
390      * @see AccessibilityAction#ACTION_SET_SELECTION
391      */
392     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
393             "ACTION_ARGUMENT_SELECTION_START_INT";
394 
395     /**
396      * Argument for specifying the selection end.
397      * <p>
398      * <strong>Type:</strong> int<br>
399      * <strong>Actions:</strong>
400      * <ul>
401      *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
402      * </ul>
403      *
404      * @see AccessibilityAction#ACTION_SET_SELECTION
405      */
406     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
407             "ACTION_ARGUMENT_SELECTION_END_INT";
408 
409     /**
410      * Argument for specifying the text content to set.
411      * <p>
412      * <strong>Type:</strong> CharSequence<br>
413      * <strong>Actions:</strong>
414      * <ul>
415      *     <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li>
416      * </ul>
417      *
418      * @see AccessibilityAction#ACTION_SET_TEXT
419      */
420     public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
421             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
422 
423     /**
424      * Argument for specifying the collection row to make visible on screen.
425      * <p>
426      * <strong>Type:</strong> int<br>
427      * <strong>Actions:</strong>
428      * <ul>
429      *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
430      * </ul>
431      *
432      * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
433      */
434     public static final String ACTION_ARGUMENT_ROW_INT =
435             "android.view.accessibility.action.ARGUMENT_ROW_INT";
436 
437     /**
438      * Argument for specifying the collection column to make visible on screen.
439      * <p>
440      * <strong>Type:</strong> int<br>
441      * <strong>Actions:</strong>
442      * <ul>
443      *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
444      * </ul>
445      *
446      * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
447      */
448     public static final String ACTION_ARGUMENT_COLUMN_INT =
449             "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
450 
451     /**
452      * Argument for specifying the progress value to set.
453      * <p>
454      * <strong>Type:</strong> float<br>
455      * <strong>Actions:</strong>
456      * <ul>
457      *     <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li>
458      * </ul>
459      *
460      * @see AccessibilityAction#ACTION_SET_PROGRESS
461      */
462     public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
463             "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
464 
465     // Focus types
466 
467     /**
468      * The input focus.
469      */
470     public static final int FOCUS_INPUT = 1;
471 
472     /**
473      * The accessibility focus.
474      */
475     public static final int FOCUS_ACCESSIBILITY = 2;
476 
477     // Movement granularities
478 
479     /**
480      * Movement granularity bit for traversing the text of a node by character.
481      */
482     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
483 
484     /**
485      * Movement granularity bit for traversing the text of a node by word.
486      */
487     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
488 
489     /**
490      * Movement granularity bit for traversing the text of a node by line.
491      */
492     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
493 
494     /**
495      * Movement granularity bit for traversing the text of a node by paragraph.
496      */
497     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
498 
499     /**
500      * Movement granularity bit for traversing the text of a node by page.
501      */
502     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
503 
504     // Boolean attributes.
505 
506     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
507 
508     private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
509 
510     private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
511 
512     private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
513 
514     private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
515 
516     private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
517 
518     private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
519 
520     private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
521 
522     private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
523 
524     private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
525 
526     private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
527 
528     private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
529 
530     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
531 
532     private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
533 
534     private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
535 
536     private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
537 
538     private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
539 
540     private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 0x00020000;
541 
542     private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
543 
544     /**
545      * Bits that provide the id of a virtual descendant of a view.
546      */
547     private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
548 
549     /**
550      * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
551      * virtual descendant of a view. Such a descendant does not exist in the view
552      * hierarchy and is only reported via the accessibility APIs.
553      */
554     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
555 
556     /**
557      * Gets the accessibility view id which identifies a View in the view three.
558      *
559      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
560      * @return The accessibility view id part of the node id.
561      *
562      * @hide
563      */
getAccessibilityViewId(long accessibilityNodeId)564     public static int getAccessibilityViewId(long accessibilityNodeId) {
565         return (int) accessibilityNodeId;
566     }
567 
568     /**
569      * Gets the virtual descendant id which identifies an imaginary view in a
570      * containing View.
571      *
572      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
573      * @return The virtual view id part of the node id.
574      *
575      * @hide
576      */
getVirtualDescendantId(long accessibilityNodeId)577     public static int getVirtualDescendantId(long accessibilityNodeId) {
578         return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
579                 >> VIRTUAL_DESCENDANT_ID_SHIFT);
580     }
581 
582     /**
583      * Makes a node id by shifting the <code>virtualDescendantId</code>
584      * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
585      * the bitwise or with the <code>accessibilityViewId</code>.
586      *
587      * @param accessibilityViewId A View accessibility id.
588      * @param virtualDescendantId A virtual descendant id.
589      * @return The node id.
590      *
591      * @hide
592      */
makeNodeId(int accessibilityViewId, int virtualDescendantId)593     public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
594         // We changed the value for undefined node to positive due to wrong
595         // global id composition (two 32-bin ints into one 64-bit long) but
596         // the value used for the host node provider view has id -1 so we
597         // remap it here.
598         if (virtualDescendantId == AccessibilityNodeProvider.HOST_VIEW_ID) {
599             virtualDescendantId = UNDEFINED_ITEM_ID;
600         }
601         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
602     }
603 
604     // Housekeeping.
605     private static final int MAX_POOL_SIZE = 50;
606     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
607             new SynchronizedPool<>(MAX_POOL_SIZE);
608 
609     private boolean mSealed;
610 
611     // Data.
612     private int mWindowId = UNDEFINED_ITEM_ID;
613     private long mSourceNodeId = ROOT_NODE_ID;
614     private long mParentNodeId = ROOT_NODE_ID;
615     private long mLabelForId = ROOT_NODE_ID;
616     private long mLabeledById = ROOT_NODE_ID;
617     private long mTraversalBefore = ROOT_NODE_ID;
618     private long mTraversalAfter = ROOT_NODE_ID;
619 
620     private int mBooleanProperties;
621     private final Rect mBoundsInParent = new Rect();
622     private final Rect mBoundsInScreen = new Rect();
623     private int mDrawingOrderInParent;
624 
625     private CharSequence mPackageName;
626     private CharSequence mClassName;
627     private CharSequence mText;
628     private CharSequence mError;
629     private CharSequence mContentDescription;
630     private String mViewIdResourceName;
631 
632     private LongArray mChildNodeIds;
633     private ArrayList<AccessibilityAction> mActions;
634 
635     private int mMaxTextLength = -1;
636     private int mMovementGranularities;
637 
638     private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
639     private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
640     private int mInputType = InputType.TYPE_NULL;
641     private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
642 
643     private Bundle mExtras;
644 
645     private int mConnectionId = UNDEFINED_CONNECTION_ID;
646 
647     private RangeInfo mRangeInfo;
648     private CollectionInfo mCollectionInfo;
649     private CollectionItemInfo mCollectionItemInfo;
650 
651     /**
652      * Hide constructor from clients.
653      */
AccessibilityNodeInfo()654     private AccessibilityNodeInfo() {
655         /* do nothing */
656     }
657 
658     /**
659      * Sets the source.
660      * <p>
661      *   <strong>Note:</strong> Cannot be called from an
662      *   {@link android.accessibilityservice.AccessibilityService}.
663      *   This class is made immutable before being delivered to an AccessibilityService.
664      * </p>
665      *
666      * @param source The info source.
667      */
setSource(View source)668     public void setSource(View source) {
669         setSource(source, UNDEFINED_ITEM_ID);
670     }
671 
672     /**
673      * Sets the source to be a virtual descendant of the given <code>root</code>.
674      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
675      * is set as the source.
676      * <p>
677      * A virtual descendant is an imaginary View that is reported as a part of the view
678      * hierarchy for accessibility purposes. This enables custom views that draw complex
679      * content to report themselves as a tree of virtual views, thus conveying their
680      * logical structure.
681      * </p>
682      * <p>
683      *   <strong>Note:</strong> Cannot be called from an
684      *   {@link android.accessibilityservice.AccessibilityService}.
685      *   This class is made immutable before being delivered to an AccessibilityService.
686      * </p>
687      *
688      * @param root The root of the virtual subtree.
689      * @param virtualDescendantId The id of the virtual descendant.
690      */
setSource(View root, int virtualDescendantId)691     public void setSource(View root, int virtualDescendantId) {
692         enforceNotSealed();
693         mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID;
694         final int rootAccessibilityViewId =
695             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
696         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
697     }
698 
699     /**
700      * Find the view that has the specified focus type. The search starts from
701      * the view represented by this node info.
702      *
703      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
704      *         {@link #FOCUS_ACCESSIBILITY}.
705      * @return The node info of the focused view or null.
706      *
707      * @see #FOCUS_INPUT
708      * @see #FOCUS_ACCESSIBILITY
709      */
findFocus(int focus)710     public AccessibilityNodeInfo findFocus(int focus) {
711         enforceSealed();
712         enforceValidFocusType(focus);
713         if (!canPerformRequestOverConnection(mSourceNodeId)) {
714             return null;
715         }
716         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
717                 mSourceNodeId, focus);
718     }
719 
720     /**
721      * Searches for the nearest view in the specified direction that can take
722      * the input focus.
723      *
724      * @param direction The direction. Can be one of:
725      *     {@link View#FOCUS_DOWN},
726      *     {@link View#FOCUS_UP},
727      *     {@link View#FOCUS_LEFT},
728      *     {@link View#FOCUS_RIGHT},
729      *     {@link View#FOCUS_FORWARD},
730      *     {@link View#FOCUS_BACKWARD}.
731      *
732      * @return The node info for the view that can take accessibility focus.
733      */
focusSearch(int direction)734     public AccessibilityNodeInfo focusSearch(int direction) {
735         enforceSealed();
736         enforceValidFocusDirection(direction);
737         if (!canPerformRequestOverConnection(mSourceNodeId)) {
738             return null;
739         }
740         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
741                 mSourceNodeId, direction);
742     }
743 
744     /**
745      * Gets the id of the window from which the info comes from.
746      *
747      * @return The window id.
748      */
getWindowId()749     public int getWindowId() {
750         return mWindowId;
751     }
752 
753     /**
754      * Refreshes this info with the latest state of the view it represents.
755      * <p>
756      * <strong>Note:</strong> If this method returns false this info is obsolete
757      * since it represents a view that is no longer in the view tree and should
758      * be recycled.
759      * </p>
760      *
761      * @param bypassCache Whether to bypass the cache.
762      * @return Whether the refresh succeeded.
763      *
764      * @hide
765      */
refresh(boolean bypassCache)766     public boolean refresh(boolean bypassCache) {
767         enforceSealed();
768         if (!canPerformRequestOverConnection(mSourceNodeId)) {
769             return false;
770         }
771         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
772         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
773                 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
774         if (refreshedInfo == null) {
775             return false;
776         }
777         init(refreshedInfo);
778         refreshedInfo.recycle();
779         return true;
780     }
781 
782     /**
783      * Refreshes this info with the latest state of the view it represents.
784      * <p>
785      * <strong>Note:</strong> If this method returns false this info is obsolete
786      * since it represents a view that is no longer in the view tree and should
787      * be recycled.
788      * </p>
789      * @return Whether the refresh succeeded.
790      */
refresh()791     public boolean refresh() {
792         return refresh(true);
793     }
794 
795     /**
796      * Returns the array containing the IDs of this node's children.
797      *
798      * @hide
799      */
getChildNodeIds()800     public LongArray getChildNodeIds() {
801         return mChildNodeIds;
802     }
803 
804     /**
805      * Returns the id of the child at the specified index.
806      *
807      * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
808      *             getChildCount()
809      * @hide
810      */
getChildId(int index)811     public long getChildId(int index) {
812         if (mChildNodeIds == null) {
813             throw new IndexOutOfBoundsException();
814         }
815         return mChildNodeIds.get(index);
816     }
817 
818     /**
819      * Gets the number of children.
820      *
821      * @return The child count.
822      */
getChildCount()823     public int getChildCount() {
824         return mChildNodeIds == null ? 0 : mChildNodeIds.size();
825     }
826 
827     /**
828      * Get the child at given index.
829      * <p>
830      *   <strong>Note:</strong> It is a client responsibility to recycle the
831      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
832      *     to avoid creating of multiple instances.
833      * </p>
834      *
835      * @param index The child index.
836      * @return The child node.
837      *
838      * @throws IllegalStateException If called outside of an AccessibilityService.
839      *
840      */
getChild(int index)841     public AccessibilityNodeInfo getChild(int index) {
842         enforceSealed();
843         if (mChildNodeIds == null) {
844             return null;
845         }
846         if (!canPerformRequestOverConnection(mSourceNodeId)) {
847             return null;
848         }
849         final long childId = mChildNodeIds.get(index);
850         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
851         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
852                 childId, false, FLAG_PREFETCH_DESCENDANTS);
853     }
854 
855     /**
856      * Adds a child.
857      * <p>
858      * <strong>Note:</strong> Cannot be called from an
859      * {@link android.accessibilityservice.AccessibilityService}.
860      * This class is made immutable before being delivered to an AccessibilityService.
861      * </p>
862      *
863      * @param child The child.
864      *
865      * @throws IllegalStateException If called from an AccessibilityService.
866      */
addChild(View child)867     public void addChild(View child) {
868         addChildInternal(child, UNDEFINED_ITEM_ID, true);
869     }
870 
871     /**
872      * Unchecked version of {@link #addChild(View)} that does not verify
873      * uniqueness. For framework use only.
874      *
875      * @hide
876      */
addChildUnchecked(View child)877     public void addChildUnchecked(View child) {
878         addChildInternal(child, UNDEFINED_ITEM_ID, false);
879     }
880 
881     /**
882      * Removes a child. If the child was not previously added to the node,
883      * calling this method has no effect.
884      * <p>
885      * <strong>Note:</strong> Cannot be called from an
886      * {@link android.accessibilityservice.AccessibilityService}.
887      * This class is made immutable before being delivered to an AccessibilityService.
888      * </p>
889      *
890      * @param child The child.
891      * @return true if the child was present
892      *
893      * @throws IllegalStateException If called from an AccessibilityService.
894      */
removeChild(View child)895     public boolean removeChild(View child) {
896         return removeChild(child, UNDEFINED_ITEM_ID);
897     }
898 
899     /**
900      * Adds a virtual child which is a descendant of the given <code>root</code>.
901      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
902      * is added as a child.
903      * <p>
904      * A virtual descendant is an imaginary View that is reported as a part of the view
905      * hierarchy for accessibility purposes. This enables custom views that draw complex
906      * content to report them selves as a tree of virtual views, thus conveying their
907      * logical structure.
908      * </p>
909      *
910      * @param root The root of the virtual subtree.
911      * @param virtualDescendantId The id of the virtual child.
912      */
addChild(View root, int virtualDescendantId)913     public void addChild(View root, int virtualDescendantId) {
914         addChildInternal(root, virtualDescendantId, true);
915     }
916 
addChildInternal(View root, int virtualDescendantId, boolean checked)917     private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
918         enforceNotSealed();
919         if (mChildNodeIds == null) {
920             mChildNodeIds = new LongArray();
921         }
922         final int rootAccessibilityViewId =
923             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
924         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
925         // If we're checking uniqueness and the ID already exists, abort.
926         if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
927             return;
928         }
929         mChildNodeIds.add(childNodeId);
930     }
931 
932     /**
933      * Removes a virtual child which is a descendant of the given
934      * <code>root</code>. If the child was not previously added to the node,
935      * calling this method has no effect.
936      *
937      * @param root The root of the virtual subtree.
938      * @param virtualDescendantId The id of the virtual child.
939      * @return true if the child was present
940      * @see #addChild(View, int)
941      */
removeChild(View root, int virtualDescendantId)942     public boolean removeChild(View root, int virtualDescendantId) {
943         enforceNotSealed();
944         final LongArray childIds = mChildNodeIds;
945         if (childIds == null) {
946             return false;
947         }
948         final int rootAccessibilityViewId =
949                 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
950         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
951         final int index = childIds.indexOf(childNodeId);
952         if (index < 0) {
953             return false;
954         }
955         childIds.remove(index);
956         return true;
957     }
958 
959     /**
960      * Gets the actions that can be performed on the node.
961      */
getActionList()962     public List<AccessibilityAction> getActionList() {
963         if (mActions == null) {
964             return Collections.emptyList();
965         }
966 
967         return mActions;
968     }
969 
970     /**
971      * Gets the actions that can be performed on the node.
972      *
973      * @return The bit mask of with actions.
974      *
975      * @see AccessibilityNodeInfo#ACTION_FOCUS
976      * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
977      * @see AccessibilityNodeInfo#ACTION_SELECT
978      * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
979      * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
980      * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
981      * @see AccessibilityNodeInfo#ACTION_CLICK
982      * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
983      * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
984      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
985      * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
986      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
987      * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
988      * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
989      *
990      * @deprecated Use {@link #getActionList()}.
991      */
992     @Deprecated
getActions()993     public int getActions() {
994         int returnValue = 0;
995 
996         if (mActions == null) {
997             return returnValue;
998         }
999 
1000         final int actionSize = mActions.size();
1001         for (int i = 0; i < actionSize; i++) {
1002             int actionId = mActions.get(i).getId();
1003             if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
1004                 returnValue |= actionId;
1005             }
1006         }
1007 
1008         return returnValue;
1009     }
1010 
1011     /**
1012      * Adds an action that can be performed on the node.
1013      * <p>
1014      * To add a standard action use the static constants on {@link AccessibilityAction}.
1015      * To add a custom action create a new {@link AccessibilityAction} by passing in a
1016      * resource id from your application as the action id and an optional label that
1017      * describes the action. To override one of the standard actions use as the action
1018      * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
1019      * describes the action.
1020      * </p>
1021      * <p>
1022      *   <strong>Note:</strong> Cannot be called from an
1023      *   {@link android.accessibilityservice.AccessibilityService}.
1024      *   This class is made immutable before being delivered to an AccessibilityService.
1025      * </p>
1026      *
1027      * @param action The action.
1028      *
1029      * @throws IllegalStateException If called from an AccessibilityService.
1030      */
addAction(AccessibilityAction action)1031     public void addAction(AccessibilityAction action) {
1032         enforceNotSealed();
1033 
1034         addActionUnchecked(action);
1035     }
1036 
addActionUnchecked(AccessibilityAction action)1037     private void addActionUnchecked(AccessibilityAction action) {
1038         if (action == null) {
1039             return;
1040         }
1041 
1042         if (mActions == null) {
1043             mActions = new ArrayList<>();
1044         }
1045 
1046         mActions.remove(action);
1047         mActions.add(action);
1048     }
1049 
1050     /**
1051      * Adds an action that can be performed on the node.
1052      * <p>
1053      *   <strong>Note:</strong> Cannot be called from an
1054      *   {@link android.accessibilityservice.AccessibilityService}.
1055      *   This class is made immutable before being delivered to an AccessibilityService.
1056      * </p>
1057      *
1058      * @param action The action.
1059      *
1060      * @throws IllegalStateException If called from an AccessibilityService.
1061      * @throws IllegalArgumentException If the argument is not one of the standard actions.
1062      *
1063      * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
1064      */
1065     @Deprecated
addAction(int action)1066     public void addAction(int action) {
1067         enforceNotSealed();
1068 
1069         if ((action & ACTION_TYPE_MASK) != 0) {
1070             throw new IllegalArgumentException("Action is not a combination of the standard " +
1071                     "actions: " + action);
1072         }
1073 
1074         addLegacyStandardActions(action);
1075     }
1076 
1077     /**
1078      * Removes an action that can be performed on the node. If the action was
1079      * not already added to the node, calling this method has no effect.
1080      * <p>
1081      *   <strong>Note:</strong> Cannot be called from an
1082      *   {@link android.accessibilityservice.AccessibilityService}.
1083      *   This class is made immutable before being delivered to an AccessibilityService.
1084      * </p>
1085      *
1086      * @param action The action to be removed.
1087      *
1088      * @throws IllegalStateException If called from an AccessibilityService.
1089      * @deprecated Use {@link #removeAction(AccessibilityAction)}
1090      */
1091     @Deprecated
removeAction(int action)1092     public void removeAction(int action) {
1093         enforceNotSealed();
1094 
1095         removeAction(getActionSingleton(action));
1096     }
1097 
1098     /**
1099      * Removes an action that can be performed on the node. If the action was
1100      * not already added to the node, calling this method has no effect.
1101      * <p>
1102      *   <strong>Note:</strong> Cannot be called from an
1103      *   {@link android.accessibilityservice.AccessibilityService}.
1104      *   This class is made immutable before being delivered to an AccessibilityService.
1105      * </p>
1106      *
1107      * @param action The action to be removed.
1108      * @return The action removed from the list of actions.
1109      *
1110      * @throws IllegalStateException If called from an AccessibilityService.
1111      */
removeAction(AccessibilityAction action)1112     public boolean removeAction(AccessibilityAction action) {
1113         enforceNotSealed();
1114 
1115         if (mActions == null || action == null) {
1116             return false;
1117         }
1118 
1119         return mActions.remove(action);
1120     }
1121 
1122     /**
1123      * Gets the node before which this one is visited during traversal. A screen-reader
1124      * must visit the content of this node before the content of the one it precedes.
1125      *
1126      * @return The succeeding node if such or <code>null</code>.
1127      *
1128      * @see #setTraversalBefore(android.view.View)
1129      * @see #setTraversalBefore(android.view.View, int)
1130      */
getTraversalBefore()1131     public AccessibilityNodeInfo getTraversalBefore() {
1132         enforceSealed();
1133         return getNodeForAccessibilityId(mTraversalBefore);
1134     }
1135 
1136     /**
1137      * Sets the view before whose node this one should be visited during traversal. A
1138      * screen-reader must visit the content of this node before the content of the one
1139      * it precedes.
1140      * <p>
1141      *   <strong>Note:</strong> Cannot be called from an
1142      *   {@link android.accessibilityservice.AccessibilityService}.
1143      *   This class is made immutable before being delivered to an AccessibilityService.
1144      * </p>
1145      *
1146      * @param view The view providing the preceding node.
1147      *
1148      * @see #getTraversalBefore()
1149      */
setTraversalBefore(View view)1150     public void setTraversalBefore(View view) {
1151         setTraversalBefore(view, UNDEFINED_ITEM_ID);
1152     }
1153 
1154     /**
1155      * Sets the node before which this one is visited during traversal. A screen-reader
1156      * must visit the content of this node before the content of the one it precedes.
1157      * The successor is a virtual descendant of the given <code>root</code>. If
1158      * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
1159      * as the successor.
1160      * <p>
1161      * A virtual descendant is an imaginary View that is reported as a part of the view
1162      * hierarchy for accessibility purposes. This enables custom views that draw complex
1163      * content to report them selves as a tree of virtual views, thus conveying their
1164      * logical structure.
1165      * </p>
1166      * <p>
1167      *   <strong>Note:</strong> Cannot be called from an
1168      *   {@link android.accessibilityservice.AccessibilityService}.
1169      *   This class is made immutable before being delivered to an AccessibilityService.
1170      * </p>
1171      *
1172      * @param root The root of the virtual subtree.
1173      * @param virtualDescendantId The id of the virtual descendant.
1174      */
setTraversalBefore(View root, int virtualDescendantId)1175     public void setTraversalBefore(View root, int virtualDescendantId) {
1176         enforceNotSealed();
1177         final int rootAccessibilityViewId = (root != null)
1178                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1179         mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1180     }
1181 
1182     /**
1183      * Gets the node after which this one is visited in accessibility traversal.
1184      * A screen-reader must visit the content of the other node before the content
1185      * of this one.
1186      *
1187      * @return The succeeding node if such or <code>null</code>.
1188      *
1189      * @see #setTraversalAfter(android.view.View)
1190      * @see #setTraversalAfter(android.view.View, int)
1191      */
getTraversalAfter()1192     public AccessibilityNodeInfo getTraversalAfter() {
1193         enforceSealed();
1194         return getNodeForAccessibilityId(mTraversalAfter);
1195     }
1196 
1197     /**
1198      * Sets the view whose node is visited after this one in accessibility traversal.
1199      * A screen-reader must visit the content of the other node before the content
1200      * of this one.
1201      * <p>
1202      *   <strong>Note:</strong> Cannot be called from an
1203      *   {@link android.accessibilityservice.AccessibilityService}.
1204      *   This class is made immutable before being delivered to an AccessibilityService.
1205      * </p>
1206      *
1207      * @param view The previous view.
1208      *
1209      * @see #getTraversalAfter()
1210      */
setTraversalAfter(View view)1211     public void setTraversalAfter(View view) {
1212         setTraversalAfter(view, UNDEFINED_ITEM_ID);
1213     }
1214 
1215     /**
1216      * Sets the node after which this one is visited in accessibility traversal.
1217      * A screen-reader must visit the content of the other node before the content
1218      * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
1219      * the root is set as the predecessor.
1220      * <p>
1221      * A virtual descendant is an imaginary View that is reported as a part of the view
1222      * hierarchy for accessibility purposes. This enables custom views that draw complex
1223      * content to report them selves as a tree of virtual views, thus conveying their
1224      * logical structure.
1225      * </p>
1226      * <p>
1227      *   <strong>Note:</strong> Cannot be called from an
1228      *   {@link android.accessibilityservice.AccessibilityService}.
1229      *   This class is made immutable before being delivered to an AccessibilityService.
1230      * </p>
1231      *
1232      * @param root The root of the virtual subtree.
1233      * @param virtualDescendantId The id of the virtual descendant.
1234      */
setTraversalAfter(View root, int virtualDescendantId)1235     public void setTraversalAfter(View root, int virtualDescendantId) {
1236         enforceNotSealed();
1237         final int rootAccessibilityViewId = (root != null)
1238                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1239         mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1240     }
1241 
1242     /**
1243      * Sets the maximum text length, or -1 for no limit.
1244      * <p>
1245      * Typically used to indicate that an editable text field has a limit on
1246      * the number of characters entered.
1247      * <p>
1248      * <strong>Note:</strong> Cannot be called from an
1249      * {@link android.accessibilityservice.AccessibilityService}.
1250      * This class is made immutable before being delivered to an AccessibilityService.
1251      *
1252      * @param max The maximum text length.
1253      * @see #getMaxTextLength()
1254      *
1255      * @throws IllegalStateException If called from an AccessibilityService.
1256      */
setMaxTextLength(int max)1257     public void setMaxTextLength(int max) {
1258         enforceNotSealed();
1259         mMaxTextLength = max;
1260     }
1261 
1262     /**
1263      * Returns the maximum text length for this node.
1264      *
1265      * @return The maximum text length, or -1 for no limit.
1266      * @see #setMaxTextLength(int)
1267      */
getMaxTextLength()1268     public int getMaxTextLength() {
1269         return mMaxTextLength;
1270     }
1271 
1272     /**
1273      * Sets the movement granularities for traversing the text of this node.
1274      * <p>
1275      *   <strong>Note:</strong> Cannot be called from an
1276      *   {@link android.accessibilityservice.AccessibilityService}.
1277      *   This class is made immutable before being delivered to an AccessibilityService.
1278      * </p>
1279      *
1280      * @param granularities The bit mask with granularities.
1281      *
1282      * @throws IllegalStateException If called from an AccessibilityService.
1283      */
setMovementGranularities(int granularities)1284     public void setMovementGranularities(int granularities) {
1285         enforceNotSealed();
1286         mMovementGranularities = granularities;
1287     }
1288 
1289     /**
1290      * Gets the movement granularities for traversing the text of this node.
1291      *
1292      * @return The bit mask with granularities.
1293      */
getMovementGranularities()1294     public int getMovementGranularities() {
1295         return mMovementGranularities;
1296     }
1297 
1298     /**
1299      * Performs an action on the node.
1300      * <p>
1301      *   <strong>Note:</strong> An action can be performed only if the request is made
1302      *   from an {@link android.accessibilityservice.AccessibilityService}.
1303      * </p>
1304      *
1305      * @param action The action to perform.
1306      * @return True if the action was performed.
1307      *
1308      * @throws IllegalStateException If called outside of an AccessibilityService.
1309      */
performAction(int action)1310     public boolean performAction(int action) {
1311         enforceSealed();
1312         if (!canPerformRequestOverConnection(mSourceNodeId)) {
1313             return false;
1314         }
1315         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1316         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1317                 action, null);
1318     }
1319 
1320     /**
1321      * Performs an action on the node.
1322      * <p>
1323      *   <strong>Note:</strong> An action can be performed only if the request is made
1324      *   from an {@link android.accessibilityservice.AccessibilityService}.
1325      * </p>
1326      *
1327      * @param action The action to perform.
1328      * @param arguments A bundle with additional arguments.
1329      * @return True if the action was performed.
1330      *
1331      * @throws IllegalStateException If called outside of an AccessibilityService.
1332      */
performAction(int action, Bundle arguments)1333     public boolean performAction(int action, Bundle arguments) {
1334         enforceSealed();
1335         if (!canPerformRequestOverConnection(mSourceNodeId)) {
1336             return false;
1337         }
1338         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1339         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1340                 action, arguments);
1341     }
1342 
1343     /**
1344      * Finds {@link AccessibilityNodeInfo}s by text. The match is case
1345      * insensitive containment. The search is relative to this info i.e.
1346      * this info is the root of the traversed tree.
1347      *
1348      * <p>
1349      *   <strong>Note:</strong> It is a client responsibility to recycle the
1350      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
1351      *     to avoid creating of multiple instances.
1352      * </p>
1353      *
1354      * @param text The searched text.
1355      * @return A list of node info.
1356      */
findAccessibilityNodeInfosByText(String text)1357     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
1358         enforceSealed();
1359         if (!canPerformRequestOverConnection(mSourceNodeId)) {
1360             return Collections.emptyList();
1361         }
1362         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1363         return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
1364                 text);
1365     }
1366 
1367     /**
1368      * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
1369      * name where a fully qualified id is of the from "package:id/id_resource_name".
1370      * For example, if the target application's package is "foo.bar" and the id
1371      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
1372      *
1373      * <p>
1374      *   <strong>Note:</strong> It is a client responsibility to recycle the
1375      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
1376      *     to avoid creating of multiple instances.
1377      * </p>
1378      * <p>
1379      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
1380      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
1381      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
1382      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
1383      * </p>
1384      *
1385      * @param viewId The fully qualified resource name of the view id to find.
1386      * @return A list of node info.
1387      */
findAccessibilityNodeInfosByViewId(String viewId)1388     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
1389         enforceSealed();
1390         if (!canPerformRequestOverConnection(mSourceNodeId)) {
1391             return Collections.emptyList();
1392         }
1393         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1394         return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
1395                 viewId);
1396     }
1397 
1398     /**
1399      * Gets the window to which this node belongs.
1400      *
1401      * @return The window.
1402      *
1403      * @see android.accessibilityservice.AccessibilityService#getWindows()
1404      */
getWindow()1405     public AccessibilityWindowInfo getWindow() {
1406         enforceSealed();
1407         if (!canPerformRequestOverConnection(mSourceNodeId)) {
1408             return null;
1409         }
1410         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1411         return client.getWindow(mConnectionId, mWindowId);
1412     }
1413 
1414     /**
1415      * Gets the parent.
1416      * <p>
1417      *   <strong>Note:</strong> It is a client responsibility to recycle the
1418      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
1419      *     to avoid creating of multiple instances.
1420      * </p>
1421      *
1422      * @return The parent.
1423      */
getParent()1424     public AccessibilityNodeInfo getParent() {
1425         enforceSealed();
1426         return getNodeForAccessibilityId(mParentNodeId);
1427     }
1428 
1429     /**
1430      * @return The parent node id.
1431      *
1432      * @hide
1433      */
getParentNodeId()1434     public long getParentNodeId() {
1435         return mParentNodeId;
1436     }
1437 
1438     /**
1439      * Sets the parent.
1440      * <p>
1441      *   <strong>Note:</strong> Cannot be called from an
1442      *   {@link android.accessibilityservice.AccessibilityService}.
1443      *   This class is made immutable before being delivered to an AccessibilityService.
1444      * </p>
1445      *
1446      * @param parent The parent.
1447      *
1448      * @throws IllegalStateException If called from an AccessibilityService.
1449      */
setParent(View parent)1450     public void setParent(View parent) {
1451         setParent(parent, UNDEFINED_ITEM_ID);
1452     }
1453 
1454     /**
1455      * Sets the parent to be a virtual descendant of the given <code>root</code>.
1456      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
1457      * is set as the parent.
1458      * <p>
1459      * A virtual descendant is an imaginary View that is reported as a part of the view
1460      * hierarchy for accessibility purposes. This enables custom views that draw complex
1461      * content to report them selves as a tree of virtual views, thus conveying their
1462      * logical structure.
1463      * </p>
1464      * <p>
1465      *   <strong>Note:</strong> Cannot be called from an
1466      *   {@link android.accessibilityservice.AccessibilityService}.
1467      *   This class is made immutable before being delivered to an AccessibilityService.
1468      * </p>
1469      *
1470      * @param root The root of the virtual subtree.
1471      * @param virtualDescendantId The id of the virtual descendant.
1472      */
setParent(View root, int virtualDescendantId)1473     public void setParent(View root, int virtualDescendantId) {
1474         enforceNotSealed();
1475         final int rootAccessibilityViewId =
1476             (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1477         mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1478     }
1479 
1480     /**
1481      * Gets the node bounds in parent coordinates.
1482      *
1483      * @param outBounds The output node bounds.
1484      */
getBoundsInParent(Rect outBounds)1485     public void getBoundsInParent(Rect outBounds) {
1486         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
1487                 mBoundsInParent.right, mBoundsInParent.bottom);
1488     }
1489 
1490     /**
1491      * Sets the node bounds in parent coordinates.
1492      * <p>
1493      *   <strong>Note:</strong> Cannot be called from an
1494      *   {@link android.accessibilityservice.AccessibilityService}.
1495      *   This class is made immutable before being delivered to an AccessibilityService.
1496      * </p>
1497      *
1498      * @param bounds The node bounds.
1499      *
1500      * @throws IllegalStateException If called from an AccessibilityService.
1501      */
setBoundsInParent(Rect bounds)1502     public void setBoundsInParent(Rect bounds) {
1503         enforceNotSealed();
1504         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
1505     }
1506 
1507     /**
1508      * Gets the node bounds in screen coordinates.
1509      *
1510      * @param outBounds The output node bounds.
1511      */
getBoundsInScreen(Rect outBounds)1512     public void getBoundsInScreen(Rect outBounds) {
1513         outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
1514                 mBoundsInScreen.right, mBoundsInScreen.bottom);
1515     }
1516 
1517     /**
1518      * Returns the actual rect containing the node bounds in screen coordinates.
1519      *
1520      * @hide Not safe to expose outside the framework.
1521      */
getBoundsInScreen()1522     public Rect getBoundsInScreen() {
1523         return mBoundsInScreen;
1524     }
1525 
1526     /**
1527      * Sets the node bounds in screen coordinates.
1528      * <p>
1529      *   <strong>Note:</strong> Cannot be called from an
1530      *   {@link android.accessibilityservice.AccessibilityService}.
1531      *   This class is made immutable before being delivered to an AccessibilityService.
1532      * </p>
1533      *
1534      * @param bounds The node bounds.
1535      *
1536      * @throws IllegalStateException If called from an AccessibilityService.
1537      */
setBoundsInScreen(Rect bounds)1538     public void setBoundsInScreen(Rect bounds) {
1539         enforceNotSealed();
1540         mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
1541     }
1542 
1543     /**
1544      * Gets whether this node is checkable.
1545      *
1546      * @return True if the node is checkable.
1547      */
isCheckable()1548     public boolean isCheckable() {
1549         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
1550     }
1551 
1552     /**
1553      * Sets whether this node is checkable.
1554      * <p>
1555      *   <strong>Note:</strong> Cannot be called from an
1556      *   {@link android.accessibilityservice.AccessibilityService}.
1557      *   This class is made immutable before being delivered to an AccessibilityService.
1558      * </p>
1559      *
1560      * @param checkable True if the node is checkable.
1561      *
1562      * @throws IllegalStateException If called from an AccessibilityService.
1563      */
setCheckable(boolean checkable)1564     public void setCheckable(boolean checkable) {
1565         setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
1566     }
1567 
1568     /**
1569      * Gets whether this node is checked.
1570      *
1571      * @return True if the node is checked.
1572      */
isChecked()1573     public boolean isChecked() {
1574         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
1575     }
1576 
1577     /**
1578      * Sets whether this node is checked.
1579      * <p>
1580      *   <strong>Note:</strong> Cannot be called from an
1581      *   {@link android.accessibilityservice.AccessibilityService}.
1582      *   This class is made immutable before being delivered to an AccessibilityService.
1583      * </p>
1584      *
1585      * @param checked True if the node is checked.
1586      *
1587      * @throws IllegalStateException If called from an AccessibilityService.
1588      */
setChecked(boolean checked)1589     public void setChecked(boolean checked) {
1590         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
1591     }
1592 
1593     /**
1594      * Gets whether this node is focusable.
1595      *
1596      * @return True if the node is focusable.
1597      */
isFocusable()1598     public boolean isFocusable() {
1599         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
1600     }
1601 
1602     /**
1603      * Sets whether this node is focusable.
1604      * <p>
1605      *   <strong>Note:</strong> Cannot be called from an
1606      *   {@link android.accessibilityservice.AccessibilityService}.
1607      *   This class is made immutable before being delivered to an AccessibilityService.
1608      * </p>
1609      *
1610      * @param focusable True if the node is focusable.
1611      *
1612      * @throws IllegalStateException If called from an AccessibilityService.
1613      */
setFocusable(boolean focusable)1614     public void setFocusable(boolean focusable) {
1615         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
1616     }
1617 
1618     /**
1619      * Gets whether this node is focused.
1620      *
1621      * @return True if the node is focused.
1622      */
isFocused()1623     public boolean isFocused() {
1624         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
1625     }
1626 
1627     /**
1628      * Sets whether this node is focused.
1629      * <p>
1630      *   <strong>Note:</strong> Cannot be called from an
1631      *   {@link android.accessibilityservice.AccessibilityService}.
1632      *   This class is made immutable before being delivered to an AccessibilityService.
1633      * </p>
1634      *
1635      * @param focused True if the node is focused.
1636      *
1637      * @throws IllegalStateException If called from an AccessibilityService.
1638      */
setFocused(boolean focused)1639     public void setFocused(boolean focused) {
1640         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
1641     }
1642 
1643     /**
1644      * Gets whether this node is visible to the user.
1645      *
1646      * @return Whether the node is visible to the user.
1647      */
isVisibleToUser()1648     public boolean isVisibleToUser() {
1649         return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
1650     }
1651 
1652     /**
1653      * Sets whether this node is visible to the user.
1654      * <p>
1655      *   <strong>Note:</strong> Cannot be called from an
1656      *   {@link android.accessibilityservice.AccessibilityService}.
1657      *   This class is made immutable before being delivered to an AccessibilityService.
1658      * </p>
1659      *
1660      * @param visibleToUser Whether the node is visible to the user.
1661      *
1662      * @throws IllegalStateException If called from an AccessibilityService.
1663      */
setVisibleToUser(boolean visibleToUser)1664     public void setVisibleToUser(boolean visibleToUser) {
1665         setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
1666     }
1667 
1668     /**
1669      * Gets whether this node is accessibility focused.
1670      *
1671      * @return True if the node is accessibility focused.
1672      */
isAccessibilityFocused()1673     public boolean isAccessibilityFocused() {
1674         return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
1675     }
1676 
1677     /**
1678      * Sets whether this node is accessibility focused.
1679      * <p>
1680      *   <strong>Note:</strong> Cannot be called from an
1681      *   {@link android.accessibilityservice.AccessibilityService}.
1682      *   This class is made immutable before being delivered to an AccessibilityService.
1683      * </p>
1684      *
1685      * @param focused True if the node is accessibility focused.
1686      *
1687      * @throws IllegalStateException If called from an AccessibilityService.
1688      */
setAccessibilityFocused(boolean focused)1689     public void setAccessibilityFocused(boolean focused) {
1690         setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
1691     }
1692 
1693     /**
1694      * Gets whether this node is selected.
1695      *
1696      * @return True if the node is selected.
1697      */
isSelected()1698     public boolean isSelected() {
1699         return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
1700     }
1701 
1702     /**
1703      * Sets whether this node is selected.
1704      * <p>
1705      *   <strong>Note:</strong> Cannot be called from an
1706      *   {@link android.accessibilityservice.AccessibilityService}.
1707      *   This class is made immutable before being delivered to an AccessibilityService.
1708      * </p>
1709      *
1710      * @param selected True if the node is selected.
1711      *
1712      * @throws IllegalStateException If called from an AccessibilityService.
1713      */
setSelected(boolean selected)1714     public void setSelected(boolean selected) {
1715         setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
1716     }
1717 
1718     /**
1719      * Gets whether this node is clickable.
1720      *
1721      * @return True if the node is clickable.
1722      */
isClickable()1723     public boolean isClickable() {
1724         return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
1725     }
1726 
1727     /**
1728      * Sets whether this node is clickable.
1729      * <p>
1730      *   <strong>Note:</strong> Cannot be called from an
1731      *   {@link android.accessibilityservice.AccessibilityService}.
1732      *   This class is made immutable before being delivered to an AccessibilityService.
1733      * </p>
1734      *
1735      * @param clickable True if the node is clickable.
1736      *
1737      * @throws IllegalStateException If called from an AccessibilityService.
1738      */
setClickable(boolean clickable)1739     public void setClickable(boolean clickable) {
1740         setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
1741     }
1742 
1743     /**
1744      * Gets whether this node is long clickable.
1745      *
1746      * @return True if the node is long clickable.
1747      */
isLongClickable()1748     public boolean isLongClickable() {
1749         return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
1750     }
1751 
1752     /**
1753      * Sets whether this node is long clickable.
1754      * <p>
1755      *   <strong>Note:</strong> Cannot be called from an
1756      *   {@link android.accessibilityservice.AccessibilityService}.
1757      *   This class is made immutable before being delivered to an AccessibilityService.
1758      * </p>
1759      *
1760      * @param longClickable True if the node is long clickable.
1761      *
1762      * @throws IllegalStateException If called from an AccessibilityService.
1763      */
setLongClickable(boolean longClickable)1764     public void setLongClickable(boolean longClickable) {
1765         setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
1766     }
1767 
1768     /**
1769      * Gets whether this node is enabled.
1770      *
1771      * @return True if the node is enabled.
1772      */
isEnabled()1773     public boolean isEnabled() {
1774         return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
1775     }
1776 
1777     /**
1778      * Sets whether this node is enabled.
1779      * <p>
1780      *   <strong>Note:</strong> Cannot be called from an
1781      *   {@link android.accessibilityservice.AccessibilityService}.
1782      *   This class is made immutable before being delivered to an AccessibilityService.
1783      * </p>
1784      *
1785      * @param enabled True if the node is enabled.
1786      *
1787      * @throws IllegalStateException If called from an AccessibilityService.
1788      */
setEnabled(boolean enabled)1789     public void setEnabled(boolean enabled) {
1790         setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
1791     }
1792 
1793     /**
1794      * Gets whether this node is a password.
1795      *
1796      * @return True if the node is a password.
1797      */
isPassword()1798     public boolean isPassword() {
1799         return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
1800     }
1801 
1802     /**
1803      * Sets whether this node is a password.
1804      * <p>
1805      *   <strong>Note:</strong> Cannot be called from an
1806      *   {@link android.accessibilityservice.AccessibilityService}.
1807      *   This class is made immutable before being delivered to an AccessibilityService.
1808      * </p>
1809      *
1810      * @param password True if the node is a password.
1811      *
1812      * @throws IllegalStateException If called from an AccessibilityService.
1813      */
setPassword(boolean password)1814     public void setPassword(boolean password) {
1815         setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
1816     }
1817 
1818     /**
1819      * Gets if the node is scrollable.
1820      *
1821      * @return True if the node is scrollable, false otherwise.
1822      */
isScrollable()1823     public boolean isScrollable() {
1824         return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
1825     }
1826 
1827     /**
1828      * Sets if the node is scrollable.
1829      * <p>
1830      *   <strong>Note:</strong> Cannot be called from an
1831      *   {@link android.accessibilityservice.AccessibilityService}.
1832      *   This class is made immutable before being delivered to an AccessibilityService.
1833      * </p>
1834      *
1835      * @param scrollable True if the node is scrollable, false otherwise.
1836      *
1837      * @throws IllegalStateException If called from an AccessibilityService.
1838      */
setScrollable(boolean scrollable)1839     public void setScrollable(boolean scrollable) {
1840         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
1841     }
1842 
1843     /**
1844      * Gets if the node is editable.
1845      *
1846      * @return True if the node is editable, false otherwise.
1847      */
isEditable()1848     public boolean isEditable() {
1849         return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
1850     }
1851 
1852     /**
1853      * Sets whether this node is editable.
1854      * <p>
1855      *   <strong>Note:</strong> Cannot be called from an
1856      *   {@link android.accessibilityservice.AccessibilityService}.
1857      *   This class is made immutable before being delivered to an AccessibilityService.
1858      * </p>
1859      *
1860      * @param editable True if the node is editable.
1861      *
1862      * @throws IllegalStateException If called from an AccessibilityService.
1863      */
setEditable(boolean editable)1864     public void setEditable(boolean editable) {
1865         setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
1866     }
1867 
1868     /**
1869      * Get the drawing order of the view corresponding it this node.
1870      * <p>
1871      * Drawing order is determined only within the node's parent, so this index is only relative
1872      * to its siblings.
1873      * <p>
1874      * In some cases, the drawing order is essentially simultaneous, so it is possible for two
1875      * siblings to return the same value. It is also possible that values will be skipped.
1876      *
1877      * @return The drawing position of the view corresponding to this node relative to its siblings.
1878      */
getDrawingOrder()1879     public int getDrawingOrder() {
1880         return mDrawingOrderInParent;
1881     }
1882 
1883     /**
1884      * Set the drawing order of the view corresponding it this node.
1885      *
1886      * <p>
1887      *   <strong>Note:</strong> Cannot be called from an
1888      *   {@link android.accessibilityservice.AccessibilityService}.
1889      *   This class is made immutable before being delivered to an AccessibilityService.
1890      * </p>
1891      * @param drawingOrderInParent
1892      * @throws IllegalStateException If called from an AccessibilityService.
1893      */
setDrawingOrder(int drawingOrderInParent)1894     public void setDrawingOrder(int drawingOrderInParent) {
1895         enforceNotSealed();
1896         mDrawingOrderInParent = drawingOrderInParent;
1897     }
1898 
1899     /**
1900      * Gets the collection info if the node is a collection. A collection
1901      * child is always a collection item.
1902      *
1903      * @return The collection info.
1904      */
getCollectionInfo()1905     public CollectionInfo getCollectionInfo() {
1906         return mCollectionInfo;
1907     }
1908 
1909     /**
1910      * Sets the collection info if the node is a collection. A collection
1911      * child is always a collection item.
1912      * <p>
1913      *   <strong>Note:</strong> Cannot be called from an
1914      *   {@link android.accessibilityservice.AccessibilityService}.
1915      *   This class is made immutable before being delivered to an AccessibilityService.
1916      * </p>
1917      *
1918      * @param collectionInfo The collection info.
1919      */
setCollectionInfo(CollectionInfo collectionInfo)1920     public void setCollectionInfo(CollectionInfo collectionInfo) {
1921         enforceNotSealed();
1922         mCollectionInfo = collectionInfo;
1923     }
1924 
1925     /**
1926      * Gets the collection item info if the node is a collection item. A collection
1927      * item is always a child of a collection.
1928      *
1929      * @return The collection item info.
1930      */
getCollectionItemInfo()1931     public CollectionItemInfo getCollectionItemInfo() {
1932         return mCollectionItemInfo;
1933     }
1934 
1935     /**
1936      * Sets the collection item info if the node is a collection item. A collection
1937      * item is always a child of a collection.
1938      * <p>
1939      *   <strong>Note:</strong> Cannot be called from an
1940      *   {@link android.accessibilityservice.AccessibilityService}.
1941      *   This class is made immutable before being delivered to an AccessibilityService.
1942      * </p>
1943      */
setCollectionItemInfo(CollectionItemInfo collectionItemInfo)1944     public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
1945         enforceNotSealed();
1946         mCollectionItemInfo = collectionItemInfo;
1947     }
1948 
1949     /**
1950      * Gets the range info if this node is a range.
1951      *
1952      * @return The range.
1953      */
getRangeInfo()1954     public RangeInfo getRangeInfo() {
1955         return mRangeInfo;
1956     }
1957 
1958     /**
1959      * Sets the range info if this node is a range.
1960      * <p>
1961      *   <strong>Note:</strong> Cannot be called from an
1962      *   {@link android.accessibilityservice.AccessibilityService}.
1963      *   This class is made immutable before being delivered to an AccessibilityService.
1964      * </p>
1965      *
1966      * @param rangeInfo The range info.
1967      */
setRangeInfo(RangeInfo rangeInfo)1968     public void setRangeInfo(RangeInfo rangeInfo) {
1969         enforceNotSealed();
1970         mRangeInfo = rangeInfo;
1971     }
1972 
1973     /**
1974      * Gets if the content of this node is invalid. For example,
1975      * a date is not well-formed.
1976      *
1977      * @return If the node content is invalid.
1978      */
isContentInvalid()1979     public boolean isContentInvalid() {
1980         return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
1981     }
1982 
1983     /**
1984      * Sets if the content of this node is invalid. For example,
1985      * a date is not well-formed.
1986      * <p>
1987      *   <strong>Note:</strong> Cannot be called from an
1988      *   {@link android.accessibilityservice.AccessibilityService}.
1989      *   This class is made immutable before being delivered to an AccessibilityService.
1990      * </p>
1991      *
1992      * @param contentInvalid If the node content is invalid.
1993      */
setContentInvalid(boolean contentInvalid)1994     public void setContentInvalid(boolean contentInvalid) {
1995         setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
1996     }
1997 
1998     /**
1999      * Gets whether this node is context clickable.
2000      *
2001      * @return True if the node is context clickable.
2002      */
isContextClickable()2003     public boolean isContextClickable() {
2004         return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE);
2005     }
2006 
2007     /**
2008      * Sets whether this node is context clickable.
2009      * <p>
2010      * <strong>Note:</strong> Cannot be called from an
2011      * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
2012      * before being delivered to an AccessibilityService.
2013      * </p>
2014      *
2015      * @param contextClickable True if the node is context clickable.
2016      * @throws IllegalStateException If called from an AccessibilityService.
2017      */
setContextClickable(boolean contextClickable)2018     public void setContextClickable(boolean contextClickable) {
2019         setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable);
2020     }
2021 
2022     /**
2023      * Gets the node's live region mode.
2024      * <p>
2025      * A live region is a node that contains information that is important for
2026      * the user and when it changes the user should be notified. For example,
2027      * in a login screen with a TextView that displays an "incorrect password"
2028      * notification, that view should be marked as a live region with mode
2029      * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
2030      * <p>
2031      * It is the responsibility of the accessibility service to monitor
2032      * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
2033      * changes to live region nodes and their children.
2034      *
2035      * @return The live region mode, or
2036      *         {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2037      *         live region.
2038      * @see android.view.View#getAccessibilityLiveRegion()
2039      */
getLiveRegion()2040     public int getLiveRegion() {
2041         return mLiveRegion;
2042     }
2043 
2044     /**
2045      * Sets the node's live region mode.
2046      * <p>
2047      * <strong>Note:</strong> Cannot be called from an
2048      * {@link android.accessibilityservice.AccessibilityService}. This class is
2049      * made immutable before being delivered to an AccessibilityService.
2050      *
2051      * @param mode The live region mode, or
2052      *        {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2053      *        live region.
2054      * @see android.view.View#setAccessibilityLiveRegion(int)
2055      */
setLiveRegion(int mode)2056     public void setLiveRegion(int mode) {
2057         enforceNotSealed();
2058         mLiveRegion = mode;
2059     }
2060 
2061     /**
2062      * Gets if the node is a multi line editable text.
2063      *
2064      * @return True if the node is multi line.
2065      */
isMultiLine()2066     public boolean isMultiLine() {
2067         return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
2068     }
2069 
2070     /**
2071      * Sets if the node is a multi line editable text.
2072      * <p>
2073      *   <strong>Note:</strong> Cannot be called from an
2074      *   {@link android.accessibilityservice.AccessibilityService}.
2075      *   This class is made immutable before being delivered to an AccessibilityService.
2076      * </p>
2077      *
2078      * @param multiLine True if the node is multi line.
2079      */
setMultiLine(boolean multiLine)2080     public void setMultiLine(boolean multiLine) {
2081         setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
2082     }
2083 
2084     /**
2085      * Gets if this node opens a popup or a dialog.
2086      *
2087      * @return If the the node opens a popup.
2088      */
canOpenPopup()2089     public boolean canOpenPopup() {
2090         return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
2091     }
2092 
2093     /**
2094      * Sets if this node opens a popup or a dialog.
2095      * <p>
2096      *   <strong>Note:</strong> Cannot be called from an
2097      *   {@link android.accessibilityservice.AccessibilityService}.
2098      *   This class is made immutable before being delivered to an AccessibilityService.
2099      * </p>
2100      *
2101      * @param opensPopup If the the node opens a popup.
2102      */
setCanOpenPopup(boolean opensPopup)2103     public void setCanOpenPopup(boolean opensPopup) {
2104         enforceNotSealed();
2105         setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
2106     }
2107 
2108     /**
2109      * Gets if the node can be dismissed.
2110      *
2111      * @return If the node can be dismissed.
2112      */
isDismissable()2113     public boolean isDismissable() {
2114         return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
2115     }
2116 
2117     /**
2118      * Sets if the node can be dismissed.
2119      * <p>
2120      *   <strong>Note:</strong> Cannot be called from an
2121      *   {@link android.accessibilityservice.AccessibilityService}.
2122      *   This class is made immutable before being delivered to an AccessibilityService.
2123      * </p>
2124      *
2125      * @param dismissable If the node can be dismissed.
2126      */
setDismissable(boolean dismissable)2127     public void setDismissable(boolean dismissable) {
2128         setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
2129     }
2130 
2131     /**
2132      * Returns whether the node originates from a view considered important for accessibility.
2133      *
2134      * @return {@code true} if the node originates from a view considered important for
2135      *         accessibility, {@code false} otherwise
2136      *
2137      * @see View#isImportantForAccessibility()
2138      */
isImportantForAccessibility()2139     public boolean isImportantForAccessibility() {
2140         return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE);
2141     }
2142 
2143     /**
2144      * Sets whether the node is considered important for accessibility.
2145      * <p>
2146      *   <strong>Note:</strong> Cannot be called from an
2147      *   {@link android.accessibilityservice.AccessibilityService}.
2148      *   This class is made immutable before being delivered to an AccessibilityService.
2149      * </p>
2150      *
2151      * @param important {@code true} if the node is considered important for accessibility,
2152      *                  {@code false} otherwise
2153      */
setImportantForAccessibility(boolean important)2154     public void setImportantForAccessibility(boolean important) {
2155         setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important);
2156     }
2157 
2158     /**
2159      * Gets the package this node comes from.
2160      *
2161      * @return The package name.
2162      */
getPackageName()2163     public CharSequence getPackageName() {
2164         return mPackageName;
2165     }
2166 
2167     /**
2168      * Sets the package this node comes from.
2169      * <p>
2170      *   <strong>Note:</strong> Cannot be called from an
2171      *   {@link android.accessibilityservice.AccessibilityService}.
2172      *   This class is made immutable before being delivered to an AccessibilityService.
2173      * </p>
2174      *
2175      * @param packageName The package name.
2176      *
2177      * @throws IllegalStateException If called from an AccessibilityService.
2178      */
setPackageName(CharSequence packageName)2179     public void setPackageName(CharSequence packageName) {
2180         enforceNotSealed();
2181         mPackageName = packageName;
2182     }
2183 
2184     /**
2185      * Gets the class this node comes from.
2186      *
2187      * @return The class name.
2188      */
getClassName()2189     public CharSequence getClassName() {
2190         return mClassName;
2191     }
2192 
2193     /**
2194      * Sets the class this node comes from.
2195      * <p>
2196      *   <strong>Note:</strong> Cannot be called from an
2197      *   {@link android.accessibilityservice.AccessibilityService}.
2198      *   This class is made immutable before being delivered to an AccessibilityService.
2199      * </p>
2200      *
2201      * @param className The class name.
2202      *
2203      * @throws IllegalStateException If called from an AccessibilityService.
2204      */
setClassName(CharSequence className)2205     public void setClassName(CharSequence className) {
2206         enforceNotSealed();
2207         mClassName = className;
2208     }
2209 
2210     /**
2211      * Gets the text of this node.
2212      *
2213      * @return The text.
2214      */
getText()2215     public CharSequence getText() {
2216         return mText;
2217     }
2218 
2219     /**
2220      * Sets the text of this node.
2221      * <p>
2222      *   <strong>Note:</strong> Cannot be called from an
2223      *   {@link android.accessibilityservice.AccessibilityService}.
2224      *   This class is made immutable before being delivered to an AccessibilityService.
2225      * </p>
2226      *
2227      * @param text The text.
2228      *
2229      * @throws IllegalStateException If called from an AccessibilityService.
2230      */
setText(CharSequence text)2231     public void setText(CharSequence text) {
2232         enforceNotSealed();
2233         mText = text;
2234     }
2235 
2236     /**
2237      * Sets the error text of this node.
2238      * <p>
2239      *   <strong>Note:</strong> Cannot be called from an
2240      *   {@link android.accessibilityservice.AccessibilityService}.
2241      *   This class is made immutable before being delivered to an AccessibilityService.
2242      * </p>
2243      *
2244      * @param error The error text.
2245      *
2246      * @throws IllegalStateException If called from an AccessibilityService.
2247      */
setError(CharSequence error)2248     public void setError(CharSequence error) {
2249         enforceNotSealed();
2250         mError = error;
2251     }
2252 
2253     /**
2254      * Gets the error text of this node.
2255      *
2256      * @return The error text.
2257      */
getError()2258     public CharSequence getError() {
2259         return mError;
2260     }
2261 
2262     /**
2263      * Gets the content description of this node.
2264      *
2265      * @return The content description.
2266      */
getContentDescription()2267     public CharSequence getContentDescription() {
2268         return mContentDescription;
2269     }
2270 
2271     /**
2272      * Sets the content description of this node.
2273      * <p>
2274      *   <strong>Note:</strong> Cannot be called from an
2275      *   {@link android.accessibilityservice.AccessibilityService}.
2276      *   This class is made immutable before being delivered to an AccessibilityService.
2277      * </p>
2278      *
2279      * @param contentDescription The content description.
2280      *
2281      * @throws IllegalStateException If called from an AccessibilityService.
2282      */
setContentDescription(CharSequence contentDescription)2283     public void setContentDescription(CharSequence contentDescription) {
2284         enforceNotSealed();
2285         mContentDescription = contentDescription;
2286     }
2287 
2288     /**
2289      * Sets the view for which the view represented by this info serves as a
2290      * label for accessibility purposes.
2291      *
2292      * @param labeled The view for which this info serves as a label.
2293      */
setLabelFor(View labeled)2294     public void setLabelFor(View labeled) {
2295         setLabelFor(labeled, UNDEFINED_ITEM_ID);
2296     }
2297 
2298     /**
2299      * Sets the view for which the view represented by this info serves as a
2300      * label for accessibility purposes. If <code>virtualDescendantId</code>
2301      * is {@link View#NO_ID} the root is set as the labeled.
2302      * <p>
2303      * A virtual descendant is an imaginary View that is reported as a part of the view
2304      * hierarchy for accessibility purposes. This enables custom views that draw complex
2305      * content to report themselves as a tree of virtual views, thus conveying their
2306      * logical structure.
2307      * </p>
2308      * <p>
2309      *   <strong>Note:</strong> Cannot be called from an
2310      *   {@link android.accessibilityservice.AccessibilityService}.
2311      *   This class is made immutable before being delivered to an AccessibilityService.
2312      * </p>
2313      *
2314      * @param root The root whose virtual descendant serves as a label.
2315      * @param virtualDescendantId The id of the virtual descendant.
2316      */
setLabelFor(View root, int virtualDescendantId)2317     public void setLabelFor(View root, int virtualDescendantId) {
2318         enforceNotSealed();
2319         final int rootAccessibilityViewId = (root != null)
2320                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
2321         mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2322     }
2323 
2324     /**
2325      * Gets the node info for which the view represented by this info serves as
2326      * a label for accessibility purposes.
2327      * <p>
2328      *   <strong>Note:</strong> It is a client responsibility to recycle the
2329      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
2330      *     to avoid creating of multiple instances.
2331      * </p>
2332      *
2333      * @return The labeled info.
2334      */
getLabelFor()2335     public AccessibilityNodeInfo getLabelFor() {
2336         enforceSealed();
2337         return getNodeForAccessibilityId(mLabelForId);
2338     }
2339 
2340     /**
2341      * Sets the view which serves as the label of the view represented by
2342      * this info for accessibility purposes.
2343      *
2344      * @param label The view that labels this node's source.
2345      */
setLabeledBy(View label)2346     public void setLabeledBy(View label) {
2347         setLabeledBy(label, UNDEFINED_ITEM_ID);
2348     }
2349 
2350     /**
2351      * Sets the view which serves as the label of the view represented by
2352      * this info for accessibility purposes. If <code>virtualDescendantId</code>
2353      * is {@link View#NO_ID} the root is set as the label.
2354      * <p>
2355      * A virtual descendant is an imaginary View that is reported as a part of the view
2356      * hierarchy for accessibility purposes. This enables custom views that draw complex
2357      * content to report themselves as a tree of virtual views, thus conveying their
2358      * logical structure.
2359      * </p>
2360      * <p>
2361      *   <strong>Note:</strong> Cannot be called from an
2362      *   {@link android.accessibilityservice.AccessibilityService}.
2363      *   This class is made immutable before being delivered to an AccessibilityService.
2364      * </p>
2365      *
2366      * @param root The root whose virtual descendant labels this node's source.
2367      * @param virtualDescendantId The id of the virtual descendant.
2368      */
setLabeledBy(View root, int virtualDescendantId)2369     public void setLabeledBy(View root, int virtualDescendantId) {
2370         enforceNotSealed();
2371         final int rootAccessibilityViewId = (root != null)
2372                 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
2373         mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2374     }
2375 
2376     /**
2377      * Gets the node info which serves as the label of the view represented by
2378      * this info for accessibility purposes.
2379      * <p>
2380      *   <strong>Note:</strong> It is a client responsibility to recycle the
2381      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
2382      *     to avoid creating of multiple instances.
2383      * </p>
2384      *
2385      * @return The label.
2386      */
getLabeledBy()2387     public AccessibilityNodeInfo getLabeledBy() {
2388         enforceSealed();
2389         return getNodeForAccessibilityId(mLabeledById);
2390     }
2391 
2392     /**
2393      * Sets the fully qualified resource name of the source view's id.
2394      *
2395      * <p>
2396      *   <strong>Note:</strong> Cannot be called from an
2397      *   {@link android.accessibilityservice.AccessibilityService}.
2398      *   This class is made immutable before being delivered to an AccessibilityService.
2399      * </p>
2400      *
2401      * @param viewIdResName The id resource name.
2402      */
setViewIdResourceName(String viewIdResName)2403     public void setViewIdResourceName(String viewIdResName) {
2404         enforceNotSealed();
2405         mViewIdResourceName = viewIdResName;
2406     }
2407 
2408     /**
2409      * Gets the fully qualified resource name of the source view's id.
2410      *
2411      * <p>
2412      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
2413      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
2414      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
2415      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
2416      * </p>
2417 
2418      * @return The id resource name.
2419      */
getViewIdResourceName()2420     public String getViewIdResourceName() {
2421         return mViewIdResourceName;
2422     }
2423 
2424     /**
2425      * Gets the text selection start or the cursor position.
2426      * <p>
2427      * If no text is selected, both this method and
2428      * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
2429      * the current location of the cursor.
2430      * </p>
2431      *
2432      * @return The text selection start, the cursor location if there is no selection, or -1 if
2433      *         there is no text selection and no cursor.
2434      */
getTextSelectionStart()2435     public int getTextSelectionStart() {
2436         return mTextSelectionStart;
2437     }
2438 
2439     /**
2440      * Gets the text selection end if text is selected.
2441      * <p>
2442      * If no text is selected, both this method and
2443      * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
2444      * the current location of the cursor.
2445      * </p>
2446      *
2447      * @return The text selection end, the cursor location if there is no selection, or -1 if
2448      *         there is no text selection and no cursor.
2449      */
getTextSelectionEnd()2450     public int getTextSelectionEnd() {
2451         return mTextSelectionEnd;
2452     }
2453 
2454     /**
2455      * Sets the text selection start and end.
2456      * <p>
2457      *   <strong>Note:</strong> Cannot be called from an
2458      *   {@link android.accessibilityservice.AccessibilityService}.
2459      *   This class is made immutable before being delivered to an AccessibilityService.
2460      * </p>
2461      *
2462      * @param start The text selection start.
2463      * @param end The text selection end.
2464      *
2465      * @throws IllegalStateException If called from an AccessibilityService.
2466      */
setTextSelection(int start, int end)2467     public void setTextSelection(int start, int end) {
2468         enforceNotSealed();
2469         mTextSelectionStart = start;
2470         mTextSelectionEnd = end;
2471     }
2472 
2473     /**
2474      * Gets the input type of the source as defined by {@link InputType}.
2475      *
2476      * @return The input type.
2477      */
getInputType()2478     public int getInputType() {
2479         return mInputType;
2480     }
2481 
2482     /**
2483      * Sets the input type of the source as defined by {@link InputType}.
2484      * <p>
2485      *   <strong>Note:</strong> Cannot be called from an
2486      *   {@link android.accessibilityservice.AccessibilityService}.
2487      *   This class is made immutable before being delivered to an
2488      *   AccessibilityService.
2489      * </p>
2490      *
2491      * @param inputType The input type.
2492      *
2493      * @throws IllegalStateException If called from an AccessibilityService.
2494      */
setInputType(int inputType)2495     public void setInputType(int inputType) {
2496         enforceNotSealed();
2497         mInputType = inputType;
2498     }
2499 
2500     /**
2501      * Gets an optional bundle with extra data. The bundle
2502      * is lazily created and never <code>null</code>.
2503      * <p>
2504      * <strong>Note:</strong> It is recommended to use the package
2505      * name of your application as a prefix for the keys to avoid
2506      * collisions which may confuse an accessibility service if the
2507      * same key has different meaning when emitted from different
2508      * applications.
2509      * </p>
2510      *
2511      * @return The bundle.
2512      */
getExtras()2513     public Bundle getExtras() {
2514         if (mExtras == null) {
2515             mExtras = new Bundle();
2516         }
2517         return mExtras;
2518     }
2519 
2520     /**
2521      * Gets the value of a boolean property.
2522      *
2523      * @param property The property.
2524      * @return The value.
2525      */
getBooleanProperty(int property)2526     private boolean getBooleanProperty(int property) {
2527         return (mBooleanProperties & property) != 0;
2528     }
2529 
2530     /**
2531      * Sets a boolean property.
2532      *
2533      * @param property The property.
2534      * @param value The value.
2535      *
2536      * @throws IllegalStateException If called from an AccessibilityService.
2537      */
setBooleanProperty(int property, boolean value)2538     private void setBooleanProperty(int property, boolean value) {
2539         enforceNotSealed();
2540         if (value) {
2541             mBooleanProperties |= property;
2542         } else {
2543             mBooleanProperties &= ~property;
2544         }
2545     }
2546 
2547     /**
2548      * Sets the unique id of the IAccessibilityServiceConnection over which
2549      * this instance can send requests to the system.
2550      *
2551      * @param connectionId The connection id.
2552      *
2553      * @hide
2554      */
setConnectionId(int connectionId)2555     public void setConnectionId(int connectionId) {
2556         enforceNotSealed();
2557         mConnectionId = connectionId;
2558     }
2559 
2560     /**
2561      * {@inheritDoc}
2562      */
2563     @Override
describeContents()2564     public int describeContents() {
2565         return 0;
2566     }
2567 
2568     /**
2569      * Gets the id of the source node.
2570      *
2571      * @return The id.
2572      *
2573      * @hide
2574      */
getSourceNodeId()2575     public long getSourceNodeId() {
2576         return mSourceNodeId;
2577     }
2578 
2579     /**
2580      * Sets if this instance is sealed.
2581      *
2582      * @param sealed Whether is sealed.
2583      *
2584      * @hide
2585      */
setSealed(boolean sealed)2586     public void setSealed(boolean sealed) {
2587         mSealed = sealed;
2588     }
2589 
2590     /**
2591      * Gets if this instance is sealed.
2592      *
2593      * @return Whether is sealed.
2594      *
2595      * @hide
2596      */
isSealed()2597     public boolean isSealed() {
2598         return mSealed;
2599     }
2600 
2601     /**
2602      * Enforces that this instance is sealed.
2603      *
2604      * @throws IllegalStateException If this instance is not sealed.
2605      *
2606      * @hide
2607      */
enforceSealed()2608     protected void enforceSealed() {
2609         if (!isSealed()) {
2610             throw new IllegalStateException("Cannot perform this "
2611                     + "action on a not sealed instance.");
2612         }
2613     }
2614 
enforceValidFocusDirection(int direction)2615     private void enforceValidFocusDirection(int direction) {
2616         switch (direction) {
2617             case View.FOCUS_DOWN:
2618             case View.FOCUS_UP:
2619             case View.FOCUS_LEFT:
2620             case View.FOCUS_RIGHT:
2621             case View.FOCUS_FORWARD:
2622             case View.FOCUS_BACKWARD:
2623                 return;
2624             default:
2625                 throw new IllegalArgumentException("Unknown direction: " + direction);
2626         }
2627     }
2628 
enforceValidFocusType(int focusType)2629     private void enforceValidFocusType(int focusType) {
2630         switch (focusType) {
2631             case FOCUS_INPUT:
2632             case FOCUS_ACCESSIBILITY:
2633                 return;
2634             default:
2635                 throw new IllegalArgumentException("Unknown focus type: " + focusType);
2636         }
2637     }
2638 
2639     /**
2640      * Enforces that this instance is not sealed.
2641      *
2642      * @throws IllegalStateException If this instance is sealed.
2643      *
2644      * @hide
2645      */
enforceNotSealed()2646     protected void enforceNotSealed() {
2647         if (isSealed()) {
2648             throw new IllegalStateException("Cannot perform this "
2649                     + "action on a sealed instance.");
2650         }
2651     }
2652 
2653     /**
2654      * Returns a cached instance if such is available otherwise a new one
2655      * and sets the source.
2656      *
2657      * @param source The source view.
2658      * @return An instance.
2659      *
2660      * @see #setSource(View)
2661      */
obtain(View source)2662     public static AccessibilityNodeInfo obtain(View source) {
2663         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2664         info.setSource(source);
2665         return info;
2666     }
2667 
2668     /**
2669      * Returns a cached instance if such is available otherwise a new one
2670      * and sets the source.
2671      *
2672      * @param root The root of the virtual subtree.
2673      * @param virtualDescendantId The id of the virtual descendant.
2674      * @return An instance.
2675      *
2676      * @see #setSource(View, int)
2677      */
obtain(View root, int virtualDescendantId)2678     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
2679         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2680         info.setSource(root, virtualDescendantId);
2681         return info;
2682     }
2683 
2684     /**
2685      * Returns a cached instance if such is available otherwise a new one.
2686      *
2687      * @return An instance.
2688      */
obtain()2689     public static AccessibilityNodeInfo obtain() {
2690         AccessibilityNodeInfo info = sPool.acquire();
2691         return (info != null) ? info : new AccessibilityNodeInfo();
2692     }
2693 
2694     /**
2695      * Returns a cached instance if such is available or a new one is
2696      * create. The returned instance is initialized from the given
2697      * <code>info</code>.
2698      *
2699      * @param info The other info.
2700      * @return An instance.
2701      */
obtain(AccessibilityNodeInfo info)2702     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
2703         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
2704         infoClone.init(info);
2705         return infoClone;
2706     }
2707 
2708     /**
2709      * Return an instance back to be reused.
2710      * <p>
2711      * <strong>Note:</strong> You must not touch the object after calling this function.
2712      *
2713      * @throws IllegalStateException If the info is already recycled.
2714      */
recycle()2715     public void recycle() {
2716         clear();
2717         sPool.release(this);
2718     }
2719 
2720     /**
2721      * {@inheritDoc}
2722      * <p>
2723      *   <strong>Note:</strong> After the instance is written to a parcel it
2724      *      is recycled. You must not touch the object after calling this function.
2725      * </p>
2726      */
2727     @Override
writeToParcel(Parcel parcel, int flags)2728     public void writeToParcel(Parcel parcel, int flags) {
2729         parcel.writeInt(isSealed() ? 1 : 0);
2730         parcel.writeLong(mSourceNodeId);
2731         parcel.writeInt(mWindowId);
2732         parcel.writeLong(mParentNodeId);
2733         parcel.writeLong(mLabelForId);
2734         parcel.writeLong(mLabeledById);
2735         parcel.writeLong(mTraversalBefore);
2736         parcel.writeLong(mTraversalAfter);
2737 
2738         parcel.writeInt(mConnectionId);
2739 
2740         final LongArray childIds = mChildNodeIds;
2741         if (childIds == null) {
2742             parcel.writeInt(0);
2743         } else {
2744             final int childIdsSize = childIds.size();
2745             parcel.writeInt(childIdsSize);
2746             for (int i = 0; i < childIdsSize; i++) {
2747                 parcel.writeLong(childIds.get(i));
2748             }
2749         }
2750 
2751         parcel.writeInt(mBoundsInParent.top);
2752         parcel.writeInt(mBoundsInParent.bottom);
2753         parcel.writeInt(mBoundsInParent.left);
2754         parcel.writeInt(mBoundsInParent.right);
2755 
2756         parcel.writeInt(mBoundsInScreen.top);
2757         parcel.writeInt(mBoundsInScreen.bottom);
2758         parcel.writeInt(mBoundsInScreen.left);
2759         parcel.writeInt(mBoundsInScreen.right);
2760 
2761         if (mActions != null && !mActions.isEmpty()) {
2762             final int actionCount = mActions.size();
2763 
2764             int nonLegacyActionCount = 0;
2765             int defaultLegacyStandardActions = 0;
2766             for (int i = 0; i < actionCount; i++) {
2767                 AccessibilityAction action = mActions.get(i);
2768                 if (isDefaultLegacyStandardAction(action)) {
2769                     defaultLegacyStandardActions |= action.getId();
2770                 } else {
2771                     nonLegacyActionCount++;
2772                 }
2773             }
2774             parcel.writeInt(defaultLegacyStandardActions);
2775             parcel.writeInt(nonLegacyActionCount);
2776 
2777             for (int i = 0; i < actionCount; i++) {
2778                 AccessibilityAction action = mActions.get(i);
2779                 if (!isDefaultLegacyStandardAction(action)) {
2780                     parcel.writeInt(action.getId());
2781                     parcel.writeCharSequence(action.getLabel());
2782                 }
2783             }
2784         } else {
2785             parcel.writeInt(0);
2786             parcel.writeInt(0);
2787         }
2788 
2789         parcel.writeInt(mMaxTextLength);
2790         parcel.writeInt(mMovementGranularities);
2791         parcel.writeInt(mBooleanProperties);
2792 
2793         parcel.writeCharSequence(mPackageName);
2794         parcel.writeCharSequence(mClassName);
2795         parcel.writeCharSequence(mText);
2796         parcel.writeCharSequence(mError);
2797         parcel.writeCharSequence(mContentDescription);
2798         parcel.writeString(mViewIdResourceName);
2799 
2800         parcel.writeInt(mTextSelectionStart);
2801         parcel.writeInt(mTextSelectionEnd);
2802         parcel.writeInt(mInputType);
2803         parcel.writeInt(mLiveRegion);
2804         parcel.writeInt(mDrawingOrderInParent);
2805 
2806         if (mExtras != null) {
2807             parcel.writeInt(1);
2808             parcel.writeBundle(mExtras);
2809         } else {
2810             parcel.writeInt(0);
2811         }
2812 
2813         if (mRangeInfo != null) {
2814             parcel.writeInt(1);
2815             parcel.writeInt(mRangeInfo.getType());
2816             parcel.writeFloat(mRangeInfo.getMin());
2817             parcel.writeFloat(mRangeInfo.getMax());
2818             parcel.writeFloat(mRangeInfo.getCurrent());
2819         } else {
2820             parcel.writeInt(0);
2821         }
2822 
2823         if (mCollectionInfo != null) {
2824             parcel.writeInt(1);
2825             parcel.writeInt(mCollectionInfo.getRowCount());
2826             parcel.writeInt(mCollectionInfo.getColumnCount());
2827             parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
2828             parcel.writeInt(mCollectionInfo.getSelectionMode());
2829         } else {
2830             parcel.writeInt(0);
2831         }
2832 
2833         if (mCollectionItemInfo != null) {
2834             parcel.writeInt(1);
2835             parcel.writeInt(mCollectionItemInfo.getRowIndex());
2836             parcel.writeInt(mCollectionItemInfo.getRowSpan());
2837             parcel.writeInt(mCollectionItemInfo.getColumnIndex());
2838             parcel.writeInt(mCollectionItemInfo.getColumnSpan());
2839             parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
2840             parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
2841         } else {
2842             parcel.writeInt(0);
2843         }
2844 
2845         // Since instances of this class are fetched via synchronous i.e. blocking
2846         // calls in IPCs we always recycle as soon as the instance is marshaled.
2847         recycle();
2848     }
2849 
2850     /**
2851      * Initializes this instance from another one.
2852      *
2853      * @param other The other instance.
2854      */
init(AccessibilityNodeInfo other)2855     private void init(AccessibilityNodeInfo other) {
2856         mSealed = other.mSealed;
2857         mSourceNodeId = other.mSourceNodeId;
2858         mParentNodeId = other.mParentNodeId;
2859         mLabelForId = other.mLabelForId;
2860         mLabeledById = other.mLabeledById;
2861         mTraversalBefore = other.mTraversalBefore;
2862         mTraversalAfter = other.mTraversalAfter;
2863         mWindowId = other.mWindowId;
2864         mConnectionId = other.mConnectionId;
2865         mBoundsInParent.set(other.mBoundsInParent);
2866         mBoundsInScreen.set(other.mBoundsInScreen);
2867         mPackageName = other.mPackageName;
2868         mClassName = other.mClassName;
2869         mText = other.mText;
2870         mError = other.mError;
2871         mContentDescription = other.mContentDescription;
2872         mViewIdResourceName = other.mViewIdResourceName;
2873 
2874         final ArrayList<AccessibilityAction> otherActions = other.mActions;
2875         if (otherActions != null && otherActions.size() > 0) {
2876             if (mActions == null) {
2877                 mActions = new ArrayList(otherActions);
2878             } else {
2879                 mActions.clear();
2880                 mActions.addAll(other.mActions);
2881             }
2882         }
2883 
2884         mBooleanProperties = other.mBooleanProperties;
2885         mMaxTextLength = other.mMaxTextLength;
2886         mMovementGranularities = other.mMovementGranularities;
2887 
2888         final LongArray otherChildNodeIds = other.mChildNodeIds;
2889         if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
2890             if (mChildNodeIds == null) {
2891                 mChildNodeIds = otherChildNodeIds.clone();
2892             } else {
2893                 mChildNodeIds.clear();
2894                 mChildNodeIds.addAll(otherChildNodeIds);
2895             }
2896         }
2897 
2898         mTextSelectionStart = other.mTextSelectionStart;
2899         mTextSelectionEnd = other.mTextSelectionEnd;
2900         mInputType = other.mInputType;
2901         mLiveRegion = other.mLiveRegion;
2902         mDrawingOrderInParent = other.mDrawingOrderInParent;
2903         if (other.mExtras != null) {
2904             mExtras = new Bundle(other.mExtras);
2905         } else {
2906             mExtras = null;
2907         }
2908         mRangeInfo = (other.mRangeInfo != null)
2909                 ? RangeInfo.obtain(other.mRangeInfo) : null;
2910         mCollectionInfo = (other.mCollectionInfo != null)
2911                 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
2912         mCollectionItemInfo =  (other.mCollectionItemInfo != null)
2913                 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
2914     }
2915 
2916     /**
2917      * Creates a new instance from a {@link Parcel}.
2918      *
2919      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
2920      */
initFromParcel(Parcel parcel)2921     private void initFromParcel(Parcel parcel) {
2922         final boolean sealed = (parcel.readInt()  == 1);
2923         mSourceNodeId = parcel.readLong();
2924         mWindowId = parcel.readInt();
2925         mParentNodeId = parcel.readLong();
2926         mLabelForId = parcel.readLong();
2927         mLabeledById = parcel.readLong();
2928         mTraversalBefore = parcel.readLong();
2929         mTraversalAfter = parcel.readLong();
2930 
2931         mConnectionId = parcel.readInt();
2932 
2933         final int childrenSize = parcel.readInt();
2934         if (childrenSize <= 0) {
2935             mChildNodeIds = null;
2936         } else {
2937             mChildNodeIds = new LongArray(childrenSize);
2938             for (int i = 0; i < childrenSize; i++) {
2939                 final long childId = parcel.readLong();
2940                 mChildNodeIds.add(childId);
2941             }
2942         }
2943 
2944         mBoundsInParent.top = parcel.readInt();
2945         mBoundsInParent.bottom = parcel.readInt();
2946         mBoundsInParent.left = parcel.readInt();
2947         mBoundsInParent.right = parcel.readInt();
2948 
2949         mBoundsInScreen.top = parcel.readInt();
2950         mBoundsInScreen.bottom = parcel.readInt();
2951         mBoundsInScreen.left = parcel.readInt();
2952         mBoundsInScreen.right = parcel.readInt();
2953 
2954         final int legacyStandardActions = parcel.readInt();
2955         addLegacyStandardActions(legacyStandardActions);
2956         final int nonLegacyActionCount = parcel.readInt();
2957         for (int i = 0; i < nonLegacyActionCount; i++) {
2958             final AccessibilityAction action = new AccessibilityAction(
2959                     parcel.readInt(), parcel.readCharSequence());
2960             addActionUnchecked(action);
2961         }
2962 
2963         mMaxTextLength = parcel.readInt();
2964         mMovementGranularities = parcel.readInt();
2965         mBooleanProperties = parcel.readInt();
2966 
2967         mPackageName = parcel.readCharSequence();
2968         mClassName = parcel.readCharSequence();
2969         mText = parcel.readCharSequence();
2970         mError = parcel.readCharSequence();
2971         mContentDescription = parcel.readCharSequence();
2972         mViewIdResourceName = parcel.readString();
2973 
2974         mTextSelectionStart = parcel.readInt();
2975         mTextSelectionEnd = parcel.readInt();
2976 
2977         mInputType = parcel.readInt();
2978         mLiveRegion = parcel.readInt();
2979         mDrawingOrderInParent = parcel.readInt();
2980 
2981         if (parcel.readInt() == 1) {
2982             mExtras = parcel.readBundle();
2983         } else {
2984             mExtras = null;
2985         }
2986 
2987         if (parcel.readInt() == 1) {
2988             mRangeInfo = RangeInfo.obtain(
2989                     parcel.readInt(),
2990                     parcel.readFloat(),
2991                     parcel.readFloat(),
2992                     parcel.readFloat());
2993         }
2994 
2995         if (parcel.readInt() == 1) {
2996             mCollectionInfo = CollectionInfo.obtain(
2997                     parcel.readInt(),
2998                     parcel.readInt(),
2999                     parcel.readInt() == 1,
3000                     parcel.readInt());
3001         }
3002 
3003         if (parcel.readInt() == 1) {
3004             mCollectionItemInfo = CollectionItemInfo.obtain(
3005                     parcel.readInt(),
3006                     parcel.readInt(),
3007                     parcel.readInt(),
3008                     parcel.readInt(),
3009                     parcel.readInt() == 1,
3010                     parcel.readInt() == 1);
3011         }
3012 
3013         mSealed = sealed;
3014     }
3015 
3016     /**
3017      * Clears the state of this instance.
3018      */
clear()3019     private void clear() {
3020         mSealed = false;
3021         mSourceNodeId = ROOT_NODE_ID;
3022         mParentNodeId = ROOT_NODE_ID;
3023         mLabelForId = ROOT_NODE_ID;
3024         mLabeledById = ROOT_NODE_ID;
3025         mTraversalBefore = ROOT_NODE_ID;
3026         mTraversalAfter = ROOT_NODE_ID;
3027         mWindowId = UNDEFINED_ITEM_ID;
3028         mConnectionId = UNDEFINED_CONNECTION_ID;
3029         mMaxTextLength = -1;
3030         mMovementGranularities = 0;
3031         if (mChildNodeIds != null) {
3032             mChildNodeIds.clear();
3033         }
3034         mBoundsInParent.set(0, 0, 0, 0);
3035         mBoundsInScreen.set(0, 0, 0, 0);
3036         mBooleanProperties = 0;
3037         mDrawingOrderInParent = 0;
3038         mPackageName = null;
3039         mClassName = null;
3040         mText = null;
3041         mError = null;
3042         mContentDescription = null;
3043         mViewIdResourceName = null;
3044         if (mActions != null) {
3045             mActions.clear();
3046         }
3047         mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
3048         mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
3049         mInputType = InputType.TYPE_NULL;
3050         mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
3051         mExtras = null;
3052         if (mRangeInfo != null) {
3053             mRangeInfo.recycle();
3054             mRangeInfo = null;
3055         }
3056         if (mCollectionInfo != null) {
3057             mCollectionInfo.recycle();
3058             mCollectionInfo = null;
3059         }
3060         if (mCollectionItemInfo != null) {
3061             mCollectionItemInfo.recycle();
3062             mCollectionItemInfo = null;
3063         }
3064     }
3065 
isDefaultLegacyStandardAction(AccessibilityAction action)3066     private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
3067         return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
3068                 && TextUtils.isEmpty(action.getLabel()));
3069     }
3070 
getActionSingleton(int actionId)3071     private static AccessibilityAction getActionSingleton(int actionId) {
3072         final int actions = AccessibilityAction.sStandardActions.size();
3073         for (int i = 0; i < actions; i++) {
3074             AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
3075             if (actionId == currentAction.getId()) {
3076                 return currentAction;
3077             }
3078         }
3079 
3080         return null;
3081     }
3082 
addLegacyStandardActions(int actionMask)3083     private void addLegacyStandardActions(int actionMask) {
3084         int remainingIds = actionMask;
3085         while (remainingIds > 0) {
3086             final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
3087             remainingIds &= ~id;
3088             AccessibilityAction action = getActionSingleton(id);
3089             addAction(action);
3090         }
3091     }
3092 
3093     /**
3094      * Gets the human readable action symbolic name.
3095      *
3096      * @param action The action.
3097      * @return The symbolic name.
3098      */
getActionSymbolicName(int action)3099     private static String getActionSymbolicName(int action) {
3100         switch (action) {
3101             case ACTION_FOCUS:
3102                 return "ACTION_FOCUS";
3103             case ACTION_CLEAR_FOCUS:
3104                 return "ACTION_CLEAR_FOCUS";
3105             case ACTION_SELECT:
3106                 return "ACTION_SELECT";
3107             case ACTION_CLEAR_SELECTION:
3108                 return "ACTION_CLEAR_SELECTION";
3109             case ACTION_CLICK:
3110                 return "ACTION_CLICK";
3111             case ACTION_LONG_CLICK:
3112                 return "ACTION_LONG_CLICK";
3113             case ACTION_ACCESSIBILITY_FOCUS:
3114                 return "ACTION_ACCESSIBILITY_FOCUS";
3115             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
3116                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
3117             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
3118                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
3119             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
3120                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
3121             case ACTION_NEXT_HTML_ELEMENT:
3122                 return "ACTION_NEXT_HTML_ELEMENT";
3123             case ACTION_PREVIOUS_HTML_ELEMENT:
3124                 return "ACTION_PREVIOUS_HTML_ELEMENT";
3125             case ACTION_SCROLL_FORWARD:
3126                 return "ACTION_SCROLL_FORWARD";
3127             case ACTION_SCROLL_BACKWARD:
3128                 return "ACTION_SCROLL_BACKWARD";
3129             case ACTION_CUT:
3130                 return "ACTION_CUT";
3131             case ACTION_COPY:
3132                 return "ACTION_COPY";
3133             case ACTION_PASTE:
3134                 return "ACTION_PASTE";
3135             case ACTION_SET_SELECTION:
3136                 return "ACTION_SET_SELECTION";
3137             case ACTION_EXPAND:
3138                 return "ACTION_EXPAND";
3139             case ACTION_COLLAPSE:
3140                 return "ACTION_COLLAPSE";
3141             case ACTION_DISMISS:
3142                 return "ACTION_DISMISS";
3143             case ACTION_SET_TEXT:
3144                 return "ACTION_SET_TEXT";
3145             case R.id.accessibilityActionShowOnScreen:
3146                 return "ACTION_SHOW_ON_SCREEN";
3147             case R.id.accessibilityActionScrollToPosition:
3148                 return "ACTION_SCROLL_TO_POSITION";
3149             case R.id.accessibilityActionScrollUp:
3150                 return "ACTION_SCROLL_UP";
3151             case R.id.accessibilityActionScrollLeft:
3152                 return "ACTION_SCROLL_LEFT";
3153             case R.id.accessibilityActionScrollDown:
3154                 return "ACTION_SCROLL_DOWN";
3155             case R.id.accessibilityActionScrollRight:
3156                 return "ACTION_SCROLL_RIGHT";
3157             case R.id.accessibilityActionSetProgress:
3158                 return "ACTION_SET_PROGRESS";
3159             case R.id.accessibilityActionContextClick:
3160                 return "ACTION_CONTEXT_CLICK";
3161             default:
3162                 return "ACTION_UNKNOWN";
3163         }
3164     }
3165 
3166     /**
3167      * Gets the human readable movement granularity symbolic name.
3168      *
3169      * @param granularity The granularity.
3170      * @return The symbolic name.
3171      */
getMovementGranularitySymbolicName(int granularity)3172     private static String getMovementGranularitySymbolicName(int granularity) {
3173         switch (granularity) {
3174             case MOVEMENT_GRANULARITY_CHARACTER:
3175                 return "MOVEMENT_GRANULARITY_CHARACTER";
3176             case MOVEMENT_GRANULARITY_WORD:
3177                 return "MOVEMENT_GRANULARITY_WORD";
3178             case MOVEMENT_GRANULARITY_LINE:
3179                 return "MOVEMENT_GRANULARITY_LINE";
3180             case MOVEMENT_GRANULARITY_PARAGRAPH:
3181                 return "MOVEMENT_GRANULARITY_PARAGRAPH";
3182             case MOVEMENT_GRANULARITY_PAGE:
3183                 return "MOVEMENT_GRANULARITY_PAGE";
3184             default:
3185                 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
3186         }
3187     }
3188 
canPerformRequestOverConnection(long accessibilityNodeId)3189     private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
3190         return (mWindowId != UNDEFINED_ITEM_ID
3191                 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID
3192                 && mConnectionId != UNDEFINED_CONNECTION_ID);
3193     }
3194 
3195     @Override
equals(Object object)3196     public boolean equals(Object object) {
3197         if (this == object) {
3198             return true;
3199         }
3200         if (object == null) {
3201             return false;
3202         }
3203         if (getClass() != object.getClass()) {
3204             return false;
3205         }
3206         AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
3207         if (mSourceNodeId != other.mSourceNodeId) {
3208             return false;
3209         }
3210         if (mWindowId != other.mWindowId) {
3211             return false;
3212         }
3213         return true;
3214     }
3215 
3216     @Override
hashCode()3217     public int hashCode() {
3218         final int prime = 31;
3219         int result = 1;
3220         result = prime * result + getAccessibilityViewId(mSourceNodeId);
3221         result = prime * result + getVirtualDescendantId(mSourceNodeId);
3222         result = prime * result + mWindowId;
3223         return result;
3224     }
3225 
3226     @Override
toString()3227     public String toString() {
3228         StringBuilder builder = new StringBuilder();
3229         builder.append(super.toString());
3230 
3231         if (DEBUG) {
3232             builder.append("; sourceNodeId: " + mSourceNodeId);
3233             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
3234             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
3235             builder.append("; mParentNodeId: " + mParentNodeId);
3236             builder.append("; traversalBefore: ").append(mTraversalBefore);
3237             builder.append("; traversalAfter: ").append(mTraversalAfter);
3238 
3239             int granularities = mMovementGranularities;
3240             builder.append("; MovementGranularities: [");
3241             while (granularities != 0) {
3242                 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
3243                 granularities &= ~granularity;
3244                 builder.append(getMovementGranularitySymbolicName(granularity));
3245                 if (granularities != 0) {
3246                     builder.append(", ");
3247                 }
3248             }
3249             builder.append("]");
3250 
3251             builder.append("; childAccessibilityIds: [");
3252             final LongArray childIds = mChildNodeIds;
3253             if (childIds != null) {
3254                 for (int i = 0, count = childIds.size(); i < count; i++) {
3255                     builder.append(childIds.get(i));
3256                     if (i < count - 1) {
3257                         builder.append(", ");
3258                     }
3259                 }
3260             }
3261             builder.append("]");
3262         }
3263 
3264         builder.append("; boundsInParent: " + mBoundsInParent);
3265         builder.append("; boundsInScreen: " + mBoundsInScreen);
3266 
3267         builder.append("; packageName: ").append(mPackageName);
3268         builder.append("; className: ").append(mClassName);
3269         builder.append("; text: ").append(mText);
3270         builder.append("; error: ").append(mError);
3271         builder.append("; maxTextLength: ").append(mMaxTextLength);
3272         builder.append("; contentDescription: ").append(mContentDescription);
3273         builder.append("; viewIdResName: ").append(mViewIdResourceName);
3274 
3275         builder.append("; checkable: ").append(isCheckable());
3276         builder.append("; checked: ").append(isChecked());
3277         builder.append("; focusable: ").append(isFocusable());
3278         builder.append("; focused: ").append(isFocused());
3279         builder.append("; selected: ").append(isSelected());
3280         builder.append("; clickable: ").append(isClickable());
3281         builder.append("; longClickable: ").append(isLongClickable());
3282         builder.append("; contextClickable: ").append(isContextClickable());
3283         builder.append("; enabled: ").append(isEnabled());
3284         builder.append("; password: ").append(isPassword());
3285         builder.append("; scrollable: ").append(isScrollable());
3286         builder.append("; actions: ").append(mActions);
3287 
3288         return builder.toString();
3289     }
3290 
getNodeForAccessibilityId(long accessibilityId)3291     private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
3292         if (!canPerformRequestOverConnection(accessibilityId)) {
3293             return null;
3294         }
3295         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
3296         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
3297                 mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
3298                         | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
3299     }
3300 
3301     /**
3302      * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
3303      * Each action has a unique id that is mandatory and optional data.
3304      * <p>
3305      * There are three categories of actions:
3306      * <ul>
3307      * <li><strong>Standard actions</strong> - These are actions that are reported and
3308      * handled by the standard UI widgets in the platform. For each standard action
3309      * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
3310      * </li>
3311      * <li><strong>Custom actions action</strong> - These are actions that are reported
3312      * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
3313      * example, an application may define a custom action for clearing the user history.
3314      * </li>
3315      * <li><strong>Overriden standard actions</strong> - These are actions that override
3316      * standard actions to customize them. For example, an app may add a label to the
3317      * standard {@link #ACTION_CLICK} action to announce that this action clears browsing history.
3318      * </ul>
3319      * </p>
3320      * <p>
3321      * Actions are typically added to an {@link AccessibilityNodeInfo} by using
3322      * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within
3323      * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed
3324      * within {@link View#performAccessibilityAction(int, Bundle)}.
3325      * </p>
3326      * <p class="note">
3327      * <strong>Note:</strong> Views which support these actions should invoke
3328      * {@link View#setImportantForAccessibility(int)} with
3329      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService}
3330      * can discover the set of supported actions.
3331      * </p>
3332      */
3333     public static final class AccessibilityAction {
3334 
3335         /**
3336          * Action that gives input focus to the node.
3337          */
3338         public static final AccessibilityAction ACTION_FOCUS =
3339                 new AccessibilityAction(
3340                         AccessibilityNodeInfo.ACTION_FOCUS, null);
3341 
3342         /**
3343          * Action that clears input focus of the node.
3344          */
3345         public static final AccessibilityAction ACTION_CLEAR_FOCUS =
3346                 new AccessibilityAction(
3347                         AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
3348 
3349         /**
3350          *  Action that selects the node.
3351          */
3352         public static final AccessibilityAction ACTION_SELECT =
3353                 new AccessibilityAction(
3354                         AccessibilityNodeInfo.ACTION_SELECT, null);
3355 
3356         /**
3357          * Action that deselects the node.
3358          */
3359         public static final AccessibilityAction ACTION_CLEAR_SELECTION =
3360                 new AccessibilityAction(
3361                         AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
3362 
3363         /**
3364          * Action that clicks on the node info.
3365          */
3366         public static final AccessibilityAction ACTION_CLICK =
3367                 new AccessibilityAction(
3368                         AccessibilityNodeInfo.ACTION_CLICK, null);
3369 
3370         /**
3371          * Action that long clicks on the node.
3372          */
3373         public static final AccessibilityAction ACTION_LONG_CLICK =
3374                 new AccessibilityAction(
3375                         AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
3376 
3377         /**
3378          * Action that gives accessibility focus to the node.
3379          */
3380         public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
3381                 new AccessibilityAction(
3382                         AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
3383 
3384         /**
3385          * Action that clears accessibility focus of the node.
3386          */
3387         public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
3388                 new AccessibilityAction(
3389                         AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3390 
3391         /**
3392          * Action that requests to go to the next entity in this node's text
3393          * at a given movement granularity. For example, move to the next character,
3394          * word, etc.
3395          * <p>
3396          * <strong>Arguments:</strong>
3397          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3398          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3399          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3400          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3401          * <strong>Example:</strong> Move to the previous character and do not extend selection.
3402          * <code><pre><p>
3403          *   Bundle arguments = new Bundle();
3404          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3405          *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3406          *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3407          *           false);
3408          *   info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
3409          *           arguments);
3410          * </code></pre></p>
3411          * </p>
3412          *
3413          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3414          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3415          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3416          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3417          *
3418          * @see AccessibilityNodeInfo#setMovementGranularities(int)
3419          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3420          * @see AccessibilityNodeInfo#getMovementGranularities()
3421          *  AccessibilityNodeInfo.getMovementGranularities()
3422          *
3423          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3424          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3425          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3426          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3427          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3428          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3429          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3430          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3431          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3432          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3433          */
3434         public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
3435                 new AccessibilityAction(
3436                         AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
3437 
3438         /**
3439          * Action that requests to go to the previous entity in this node's text
3440          * at a given movement granularity. For example, move to the next character,
3441          * word, etc.
3442          * <p>
3443          * <strong>Arguments:</strong>
3444          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3445          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3446          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3447          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3448          * <strong>Example:</strong> Move to the next character and do not extend selection.
3449          * <code><pre><p>
3450          *   Bundle arguments = new Bundle();
3451          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3452          *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3453          *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3454          *           false);
3455          *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
3456          *           arguments);
3457          * </code></pre></p>
3458          * </p>
3459          *
3460          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3461          *  AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3462          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3463          *  AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3464          *
3465          * @see AccessibilityNodeInfo#setMovementGranularities(int)
3466          *   AccessibilityNodeInfo.setMovementGranularities(int)
3467          * @see AccessibilityNodeInfo#getMovementGranularities()
3468          *  AccessibilityNodeInfo.getMovementGranularities()
3469          *
3470          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3471          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3472          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3473          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3474          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3475          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3476          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3477          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3478          * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3479          *  AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3480          */
3481         public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
3482                 new AccessibilityAction(
3483                         AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
3484 
3485         /**
3486          * Action to move to the next HTML element of a given type. For example, move
3487          * to the BUTTON, INPUT, TABLE, etc.
3488          * <p>
3489          * <strong>Arguments:</strong>
3490          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3491          *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3492          * <strong>Example:</strong>
3493          * <code><pre><p>
3494          *   Bundle arguments = new Bundle();
3495          *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3496          *   info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
3497          * </code></pre></p>
3498          * </p>
3499          */
3500         public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
3501                 new AccessibilityAction(
3502                         AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
3503 
3504         /**
3505          * Action to move to the previous HTML element of a given type. For example, move
3506          * to the BUTTON, INPUT, TABLE, etc.
3507          * <p>
3508          * <strong>Arguments:</strong>
3509          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3510          *  AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3511          * <strong>Example:</strong>
3512          * <code><pre><p>
3513          *   Bundle arguments = new Bundle();
3514          *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3515          *   info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
3516          * </code></pre></p>
3517          * </p>
3518          */
3519         public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
3520                 new AccessibilityAction(
3521                         AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
3522 
3523         /**
3524          * Action to scroll the node content forward.
3525          */
3526         public static final AccessibilityAction ACTION_SCROLL_FORWARD =
3527                 new AccessibilityAction(
3528                         AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
3529 
3530         /**
3531          * Action to scroll the node content backward.
3532          */
3533         public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
3534                 new AccessibilityAction(
3535                         AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
3536 
3537         /**
3538          * Action to copy the current selection to the clipboard.
3539          */
3540         public static final AccessibilityAction ACTION_COPY =
3541                 new AccessibilityAction(
3542                         AccessibilityNodeInfo.ACTION_COPY, null);
3543 
3544         /**
3545          * Action to paste the current clipboard content.
3546          */
3547         public static final AccessibilityAction ACTION_PASTE =
3548                 new AccessibilityAction(
3549                         AccessibilityNodeInfo.ACTION_PASTE, null);
3550 
3551         /**
3552          * Action to cut the current selection and place it to the clipboard.
3553          */
3554         public static final AccessibilityAction ACTION_CUT =
3555                 new AccessibilityAction(
3556                         AccessibilityNodeInfo.ACTION_CUT, null);
3557 
3558         /**
3559          * Action to set the selection. Performing this action with no arguments
3560          * clears the selection.
3561          * <p>
3562          * <strong>Arguments:</strong>
3563          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3564          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
3565          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3566          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
3567          * <strong>Example:</strong>
3568          * <code><pre><p>
3569          *   Bundle arguments = new Bundle();
3570          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
3571          *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
3572          *   info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
3573          * </code></pre></p>
3574          * </p>
3575          *
3576          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3577          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
3578          * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3579          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
3580          */
3581         public static final AccessibilityAction ACTION_SET_SELECTION =
3582                 new AccessibilityAction(
3583                         AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
3584 
3585         /**
3586          * Action to expand an expandable node.
3587          */
3588         public static final AccessibilityAction ACTION_EXPAND =
3589                 new AccessibilityAction(
3590                         AccessibilityNodeInfo.ACTION_EXPAND, null);
3591 
3592         /**
3593          * Action to collapse an expandable node.
3594          */
3595         public static final AccessibilityAction ACTION_COLLAPSE =
3596                 new AccessibilityAction(
3597                         AccessibilityNodeInfo.ACTION_COLLAPSE, null);
3598 
3599         /**
3600          * Action to dismiss a dismissable node.
3601          */
3602         public static final AccessibilityAction ACTION_DISMISS =
3603                 new AccessibilityAction(
3604                         AccessibilityNodeInfo.ACTION_DISMISS, null);
3605 
3606         /**
3607          * Action that sets the text of the node. Performing the action without argument,
3608          * using <code> null</code> or empty {@link CharSequence} will clear the text. This
3609          * action will also put the cursor at the end of text.
3610          * <p>
3611          * <strong>Arguments:</strong>
3612          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
3613          *  AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
3614          * <strong>Example:</strong>
3615          * <code><pre><p>
3616          *   Bundle arguments = new Bundle();
3617          *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
3618          *       "android");
3619          *   info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
3620          * </code></pre></p>
3621          */
3622         public static final AccessibilityAction ACTION_SET_TEXT =
3623                 new AccessibilityAction(
3624                         AccessibilityNodeInfo.ACTION_SET_TEXT, null);
3625 
3626         /**
3627          * Action that requests the node make its bounding rectangle visible
3628          * on the screen, scrolling if necessary just enough.
3629          *
3630          * @see View#requestRectangleOnScreen(Rect)
3631          */
3632         public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
3633                 new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
3634 
3635         /**
3636          * Action that scrolls the node to make the specified collection
3637          * position visible on screen.
3638          * <p>
3639          * <strong>Arguments:</strong>
3640          * <ul>
3641          *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
3642          *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
3643          * <ul>
3644          *
3645          * @see AccessibilityNodeInfo#getCollectionInfo()
3646          */
3647         public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
3648                 new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
3649 
3650         /**
3651          * Action to scroll the node content up.
3652          */
3653         public static final AccessibilityAction ACTION_SCROLL_UP =
3654                 new AccessibilityAction(R.id.accessibilityActionScrollUp, null);
3655 
3656         /**
3657          * Action to scroll the node content left.
3658          */
3659         public static final AccessibilityAction ACTION_SCROLL_LEFT =
3660                 new AccessibilityAction(R.id.accessibilityActionScrollLeft, null);
3661 
3662         /**
3663          * Action to scroll the node content down.
3664          */
3665         public static final AccessibilityAction ACTION_SCROLL_DOWN =
3666                 new AccessibilityAction(R.id.accessibilityActionScrollDown, null);
3667 
3668         /**
3669          * Action to scroll the node content right.
3670          */
3671         public static final AccessibilityAction ACTION_SCROLL_RIGHT =
3672                 new AccessibilityAction(R.id.accessibilityActionScrollRight, null);
3673 
3674         /**
3675          * Action that context clicks the node.
3676          */
3677         public static final AccessibilityAction ACTION_CONTEXT_CLICK =
3678                 new AccessibilityAction(R.id.accessibilityActionContextClick, null);
3679 
3680         /**
3681          * Action that sets progress between {@link  RangeInfo#getMin() RangeInfo.getMin()} and
3682          * {@link  RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as
3683          * {@link RangeInfo#getType() RangeInfo.getType()}
3684          * <p>
3685          * <strong>Arguments:</strong>
3686          * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE}
3687          *
3688          * @see RangeInfo
3689          */
3690         public static final AccessibilityAction ACTION_SET_PROGRESS =
3691                 new AccessibilityAction(R.id.accessibilityActionSetProgress, null);
3692 
3693         private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
3694         static {
3695             sStandardActions.add(ACTION_FOCUS);
3696             sStandardActions.add(ACTION_CLEAR_FOCUS);
3697             sStandardActions.add(ACTION_SELECT);
3698             sStandardActions.add(ACTION_CLEAR_SELECTION);
3699             sStandardActions.add(ACTION_CLICK);
3700             sStandardActions.add(ACTION_LONG_CLICK);
3701             sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
3702             sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
3703             sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
3704             sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
3705             sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
3706             sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
3707             sStandardActions.add(ACTION_SCROLL_FORWARD);
3708             sStandardActions.add(ACTION_SCROLL_BACKWARD);
3709             sStandardActions.add(ACTION_COPY);
3710             sStandardActions.add(ACTION_PASTE);
3711             sStandardActions.add(ACTION_CUT);
3712             sStandardActions.add(ACTION_SET_SELECTION);
3713             sStandardActions.add(ACTION_EXPAND);
3714             sStandardActions.add(ACTION_COLLAPSE);
3715             sStandardActions.add(ACTION_DISMISS);
3716             sStandardActions.add(ACTION_SET_TEXT);
3717             sStandardActions.add(ACTION_SHOW_ON_SCREEN);
3718             sStandardActions.add(ACTION_SCROLL_TO_POSITION);
3719             sStandardActions.add(ACTION_SCROLL_UP);
3720             sStandardActions.add(ACTION_SCROLL_LEFT);
3721             sStandardActions.add(ACTION_SCROLL_DOWN);
3722             sStandardActions.add(ACTION_SCROLL_RIGHT);
3723             sStandardActions.add(ACTION_SET_PROGRESS);
3724             sStandardActions.add(ACTION_CONTEXT_CLICK);
3725         }
3726 
3727         private final int mActionId;
3728         private final CharSequence mLabel;
3729 
3730         /**
3731          * Creates a new AccessibilityAction. For adding a standard action without a specific label,
3732          * use the static constants.
3733          *
3734          * You can also override the description for one the standard actions. Below is an example
3735          * how to override the standard click action by adding a custom label:
3736          * <pre>
3737          *   AccessibilityAction action = new AccessibilityAction(
3738          *           AccessibilityAction.ACTION_ACTION_CLICK, getLocalizedLabel());
3739          *   node.addAction(action);
3740          * </pre>
3741          *
3742          * @param actionId The id for this action. This should either be one of the
3743          *                 standard actions or a specific action for your app. In that case it is
3744          *                 required to use a resource identifier.
3745          * @param label The label for the new AccessibilityAction.
3746          */
AccessibilityAction(int actionId, @Nullable CharSequence label)3747         public AccessibilityAction(int actionId, @Nullable CharSequence label) {
3748             if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
3749                 throw new IllegalArgumentException("Invalid standard action id");
3750             }
3751 
3752             mActionId = actionId;
3753             mLabel = label;
3754         }
3755 
3756         /**
3757          * Gets the id for this action.
3758          *
3759          * @return The action id.
3760          */
getId()3761         public int getId() {
3762             return mActionId;
3763         }
3764 
3765         /**
3766          * Gets the label for this action. Its purpose is to describe the
3767          * action to user.
3768          *
3769          * @return The label.
3770          */
getLabel()3771         public CharSequence getLabel() {
3772             return mLabel;
3773         }
3774 
3775         @Override
hashCode()3776         public int hashCode() {
3777             return mActionId;
3778         }
3779 
3780         @Override
equals(Object other)3781         public boolean equals(Object other) {
3782             if (other == null) {
3783                 return false;
3784             }
3785 
3786             if (other == this) {
3787                 return true;
3788             }
3789 
3790             if (getClass() != other.getClass()) {
3791                 return false;
3792             }
3793 
3794             return mActionId == ((AccessibilityAction)other).mActionId;
3795         }
3796 
3797         @Override
toString()3798         public String toString() {
3799             return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
3800         }
3801     }
3802 
3803     /**
3804      * Class with information if a node is a range. Use
3805      * {@link RangeInfo#obtain(int, float, float, float)} to get an instance.
3806      */
3807     public static final class RangeInfo {
3808         private static final int MAX_POOL_SIZE = 10;
3809 
3810         /** Range type: integer. */
3811         public static final int RANGE_TYPE_INT = 0;
3812         /** Range type: float. */
3813         public static final int RANGE_TYPE_FLOAT = 1;
3814         /** Range type: percent with values from zero to one.*/
3815         public static final int RANGE_TYPE_PERCENT = 2;
3816 
3817         private static final SynchronizedPool<RangeInfo> sPool =
3818                 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
3819 
3820         private int mType;
3821         private float mMin;
3822         private float mMax;
3823         private float mCurrent;
3824 
3825         /**
3826          * Obtains a pooled instance that is a clone of another one.
3827          *
3828          * @param other The instance to clone.
3829          *
3830          * @hide
3831          */
obtain(RangeInfo other)3832         public static RangeInfo obtain(RangeInfo other) {
3833             return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
3834         }
3835 
3836         /**
3837          * Obtains a pooled instance.
3838          *
3839          * @param type The type of the range.
3840          * @param min The min value.
3841          * @param max The max value.
3842          * @param current The current value.
3843          */
obtain(int type, float min, float max, float current)3844         public static RangeInfo obtain(int type, float min, float max, float current) {
3845             RangeInfo info = sPool.acquire();
3846             if (info == null) {
3847                 return new RangeInfo(type, min, max, current);
3848             }
3849 
3850             info.mType = type;
3851             info.mMin = min;
3852             info.mMax = max;
3853             info.mCurrent = current;
3854             return info;
3855         }
3856 
3857         /**
3858          * Creates a new range.
3859          *
3860          * @param type The type of the range.
3861          * @param min The min value.
3862          * @param max The max value.
3863          * @param current The current value.
3864          */
RangeInfo(int type, float min, float max, float current)3865         private RangeInfo(int type, float min, float max, float current) {
3866             mType = type;
3867             mMin = min;
3868             mMax = max;
3869             mCurrent = current;
3870         }
3871 
3872         /**
3873          * Gets the range type.
3874          *
3875          * @return The range type.
3876          *
3877          * @see #RANGE_TYPE_INT
3878          * @see #RANGE_TYPE_FLOAT
3879          * @see #RANGE_TYPE_PERCENT
3880          */
getType()3881         public int getType() {
3882             return mType;
3883         }
3884 
3885         /**
3886          * Gets the min value.
3887          *
3888          * @return The min value.
3889          */
getMin()3890         public float getMin() {
3891             return mMin;
3892         }
3893 
3894         /**
3895          * Gets the max value.
3896          *
3897          * @return The max value.
3898          */
getMax()3899         public float getMax() {
3900             return mMax;
3901         }
3902 
3903         /**
3904          * Gets the current value.
3905          *
3906          * @return The current value.
3907          */
getCurrent()3908         public float getCurrent() {
3909             return mCurrent;
3910         }
3911 
3912         /**
3913          * Recycles this instance.
3914          */
recycle()3915         void recycle() {
3916             clear();
3917             sPool.release(this);
3918         }
3919 
clear()3920         private void clear() {
3921             mType = 0;
3922             mMin = 0;
3923             mMax = 0;
3924             mCurrent = 0;
3925         }
3926     }
3927 
3928     /**
3929      * Class with information if a node is a collection. Use
3930      * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance.
3931      * <p>
3932      * A collection of items has rows and columns and may be hierarchical.
3933      * For example, a horizontal list is a collection with one column, as
3934      * many rows as the list items, and is not hierarchical; A table is a
3935      * collection with several rows, several columns, and is not hierarchical;
3936      * A vertical tree is a hierarchical collection with one column and
3937      * as many rows as the first level children.
3938      * </p>
3939      */
3940     public static final class CollectionInfo {
3941         /** Selection mode where items are not selectable. */
3942         public static final int SELECTION_MODE_NONE = 0;
3943 
3944         /** Selection mode where a single item may be selected. */
3945         public static final int SELECTION_MODE_SINGLE = 1;
3946 
3947         /** Selection mode where multiple items may be selected. */
3948         public static final int SELECTION_MODE_MULTIPLE = 2;
3949 
3950         private static final int MAX_POOL_SIZE = 20;
3951 
3952         private static final SynchronizedPool<CollectionInfo> sPool =
3953                 new SynchronizedPool<>(MAX_POOL_SIZE);
3954 
3955         private int mRowCount;
3956         private int mColumnCount;
3957         private boolean mHierarchical;
3958         private int mSelectionMode;
3959 
3960         /**
3961          * Obtains a pooled instance that is a clone of another one.
3962          *
3963          * @param other The instance to clone.
3964          * @hide
3965          */
obtain(CollectionInfo other)3966         public static CollectionInfo obtain(CollectionInfo other) {
3967             return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
3968                     other.mSelectionMode);
3969         }
3970 
3971         /**
3972          * Obtains a pooled instance.
3973          *
3974          * @param rowCount The number of rows.
3975          * @param columnCount The number of columns.
3976          * @param hierarchical Whether the collection is hierarchical.
3977          */
obtain(int rowCount, int columnCount, boolean hierarchical)3978         public static CollectionInfo obtain(int rowCount, int columnCount,
3979                 boolean hierarchical) {
3980             return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
3981         }
3982 
3983         /**
3984          * Obtains a pooled instance.
3985          *
3986          * @param rowCount The number of rows.
3987          * @param columnCount The number of columns.
3988          * @param hierarchical Whether the collection is hierarchical.
3989          * @param selectionMode The collection's selection mode, one of:
3990          *            <ul>
3991          *            <li>{@link #SELECTION_MODE_NONE}
3992          *            <li>{@link #SELECTION_MODE_SINGLE}
3993          *            <li>{@link #SELECTION_MODE_MULTIPLE}
3994          *            </ul>
3995          */
obtain(int rowCount, int columnCount, boolean hierarchical, int selectionMode)3996         public static CollectionInfo obtain(int rowCount, int columnCount,
3997                 boolean hierarchical, int selectionMode) {
3998            final CollectionInfo info = sPool.acquire();
3999             if (info == null) {
4000                 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
4001             }
4002 
4003             info.mRowCount = rowCount;
4004             info.mColumnCount = columnCount;
4005             info.mHierarchical = hierarchical;
4006             info.mSelectionMode = selectionMode;
4007             return info;
4008         }
4009 
4010         /**
4011          * Creates a new instance.
4012          *
4013          * @param rowCount The number of rows.
4014          * @param columnCount The number of columns.
4015          * @param hierarchical Whether the collection is hierarchical.
4016          * @param selectionMode The collection's selection mode.
4017          */
CollectionInfo(int rowCount, int columnCount, boolean hierarchical, int selectionMode)4018         private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
4019                 int selectionMode) {
4020             mRowCount = rowCount;
4021             mColumnCount = columnCount;
4022             mHierarchical = hierarchical;
4023             mSelectionMode = selectionMode;
4024         }
4025 
4026         /**
4027          * Gets the number of rows.
4028          *
4029          * @return The row count.
4030          */
getRowCount()4031         public int getRowCount() {
4032             return mRowCount;
4033         }
4034 
4035         /**
4036          * Gets the number of columns.
4037          *
4038          * @return The column count.
4039          */
getColumnCount()4040         public int getColumnCount() {
4041             return mColumnCount;
4042         }
4043 
4044         /**
4045          * Gets if the collection is a hierarchically ordered.
4046          *
4047          * @return Whether the collection is hierarchical.
4048          */
isHierarchical()4049         public boolean isHierarchical() {
4050             return mHierarchical;
4051         }
4052 
4053         /**
4054          * Gets the collection's selection mode.
4055          *
4056          * @return The collection's selection mode, one of:
4057          *         <ul>
4058          *         <li>{@link #SELECTION_MODE_NONE}
4059          *         <li>{@link #SELECTION_MODE_SINGLE}
4060          *         <li>{@link #SELECTION_MODE_MULTIPLE}
4061          *         </ul>
4062          */
getSelectionMode()4063         public int getSelectionMode() {
4064             return mSelectionMode;
4065         }
4066 
4067         /**
4068          * Recycles this instance.
4069          */
recycle()4070         void recycle() {
4071             clear();
4072             sPool.release(this);
4073         }
4074 
clear()4075         private void clear() {
4076             mRowCount = 0;
4077             mColumnCount = 0;
4078             mHierarchical = false;
4079             mSelectionMode = SELECTION_MODE_NONE;
4080         }
4081     }
4082 
4083     /**
4084      * Class with information if a node is a collection item. Use
4085      * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
4086      * to get an instance.
4087      * <p>
4088      * A collection item is contained in a collection, it starts at
4089      * a given row and column in the collection, and spans one or
4090      * more rows and columns. For example, a header of two related
4091      * table columns starts at the first row and the first column,
4092      * spans one row and two columns.
4093      * </p>
4094      */
4095     public static final class CollectionItemInfo {
4096         private static final int MAX_POOL_SIZE = 20;
4097 
4098         private static final SynchronizedPool<CollectionItemInfo> sPool =
4099                 new SynchronizedPool<>(MAX_POOL_SIZE);
4100 
4101         /**
4102          * Obtains a pooled instance that is a clone of another one.
4103          *
4104          * @param other The instance to clone.
4105          * @hide
4106          */
obtain(CollectionItemInfo other)4107         public static CollectionItemInfo obtain(CollectionItemInfo other) {
4108             return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
4109                     other.mColumnSpan, other.mHeading, other.mSelected);
4110         }
4111 
4112         /**
4113          * Obtains a pooled instance.
4114          *
4115          * @param rowIndex The row index at which the item is located.
4116          * @param rowSpan The number of rows the item spans.
4117          * @param columnIndex The column index at which the item is located.
4118          * @param columnSpan The number of columns the item spans.
4119          * @param heading Whether the item is a heading.
4120          */
obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading)4121         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4122                 int columnIndex, int columnSpan, boolean heading) {
4123             return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
4124         }
4125 
4126         /**
4127          * Obtains a pooled instance.
4128          *
4129          * @param rowIndex The row index at which the item is located.
4130          * @param rowSpan The number of rows the item spans.
4131          * @param columnIndex The column index at which the item is located.
4132          * @param columnSpan The number of columns the item spans.
4133          * @param heading Whether the item is a heading.
4134          * @param selected Whether the item is selected.
4135          */
obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected)4136         public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4137                 int columnIndex, int columnSpan, boolean heading, boolean selected) {
4138             final CollectionItemInfo info = sPool.acquire();
4139             if (info == null) {
4140                 return new CollectionItemInfo(
4141                         rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
4142             }
4143 
4144             info.mRowIndex = rowIndex;
4145             info.mRowSpan = rowSpan;
4146             info.mColumnIndex = columnIndex;
4147             info.mColumnSpan = columnSpan;
4148             info.mHeading = heading;
4149             info.mSelected = selected;
4150             return info;
4151         }
4152 
4153         private boolean mHeading;
4154         private int mColumnIndex;
4155         private int mRowIndex;
4156         private int mColumnSpan;
4157         private int mRowSpan;
4158         private boolean mSelected;
4159 
4160         /**
4161          * Creates a new instance.
4162          *
4163          * @param rowIndex The row index at which the item is located.
4164          * @param rowSpan The number of rows the item spans.
4165          * @param columnIndex The column index at which the item is located.
4166          * @param columnSpan The number of columns the item spans.
4167          * @param heading Whether the item is a heading.
4168          */
CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected)4169         private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
4170                 boolean heading, boolean selected) {
4171             mRowIndex = rowIndex;
4172             mRowSpan = rowSpan;
4173             mColumnIndex = columnIndex;
4174             mColumnSpan = columnSpan;
4175             mHeading = heading;
4176             mSelected = selected;
4177         }
4178 
4179         /**
4180          * Gets the column index at which the item is located.
4181          *
4182          * @return The column index.
4183          */
getColumnIndex()4184         public int getColumnIndex() {
4185             return mColumnIndex;
4186         }
4187 
4188         /**
4189          * Gets the row index at which the item is located.
4190          *
4191          * @return The row index.
4192          */
getRowIndex()4193         public int getRowIndex() {
4194             return mRowIndex;
4195         }
4196 
4197         /**
4198          * Gets the number of columns the item spans.
4199          *
4200          * @return The column span.
4201          */
getColumnSpan()4202         public int getColumnSpan() {
4203             return mColumnSpan;
4204         }
4205 
4206         /**
4207          * Gets the number of rows the item spans.
4208          *
4209          * @return The row span.
4210          */
getRowSpan()4211         public int getRowSpan() {
4212             return mRowSpan;
4213         }
4214 
4215         /**
4216          * Gets if the collection item is a heading. For example, section
4217          * heading, table header, etc.
4218          *
4219          * @return If the item is a heading.
4220          */
isHeading()4221         public boolean isHeading() {
4222             return mHeading;
4223         }
4224 
4225         /**
4226          * Gets if the collection item is selected.
4227          *
4228          * @return If the item is selected.
4229          */
isSelected()4230         public boolean isSelected() {
4231             return mSelected;
4232         }
4233 
4234         /**
4235          * Recycles this instance.
4236          */
recycle()4237         void recycle() {
4238             clear();
4239             sPool.release(this);
4240         }
4241 
clear()4242         private void clear() {
4243             mColumnIndex = 0;
4244             mColumnSpan = 0;
4245             mRowIndex = 0;
4246             mRowSpan = 0;
4247             mHeading = false;
4248             mSelected = false;
4249         }
4250     }
4251 
4252     /**
4253      * @see android.os.Parcelable.Creator
4254      */
4255     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
4256             new Parcelable.Creator<AccessibilityNodeInfo>() {
4257         @Override
4258         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
4259             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
4260             info.initFromParcel(parcel);
4261             return info;
4262         }
4263 
4264         @Override
4265         public AccessibilityNodeInfo[] newArray(int size) {
4266             return new AccessibilityNodeInfo[size];
4267         }
4268     };
4269 }
4270