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