• 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.graphics.Rect;
21 import android.os.Bundle;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.util.Pools.SynchronizedPool;
25 import android.util.SparseLongArray;
26 import android.view.View;
27 
28 import java.util.Collections;
29 import java.util.List;
30 
31 /**
32  * This class represents a node of the window content as well as actions that
33  * can be requested from its source. From the point of view of an
34  * {@link android.accessibilityservice.AccessibilityService} a window content is
35  * presented as tree of accessibility node info which may or may not map one-to-one
36  * to the view hierarchy. In other words, a custom view is free to report itself as
37  * a tree of accessibility node info.
38  * </p>
39  * <p>
40  * Once an accessibility node info is delivered to an accessibility service it is
41  * made immutable and calling a state mutation method generates an error.
42  * </p>
43  * <p>
44  * Please refer to {@link android.accessibilityservice.AccessibilityService} for
45  * details about how to obtain a handle to window content as a tree of accessibility
46  * node info as well as familiarizing with the security model.
47  * </p>
48  * <div class="special reference">
49  * <h3>Developer Guides</h3>
50  * <p>For more information about making applications accessible, read the
51  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
52  * developer guide.</p>
53  * </div>
54  *
55  * @see android.accessibilityservice.AccessibilityService
56  * @see AccessibilityEvent
57  * @see AccessibilityManager
58  */
59 public class AccessibilityNodeInfo implements Parcelable {
60 
61     private static final boolean DEBUG = false;
62 
63     /** @hide */
64     public static final int UNDEFINED = -1;
65 
66     /** @hide */
67     public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
68 
69     /** @hide */
70     public static final int ACTIVE_WINDOW_ID = UNDEFINED;
71 
72     /** @hide */
73     public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
74 
75     /** @hide */
76     public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
77 
78     /** @hide */
79     public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
80 
81     /** @hide */
82     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
83 
84     /** @hide */
85     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
86 
87     // Actions.
88 
89     /**
90      * Action that gives input focus to the node.
91      */
92     public static final int ACTION_FOCUS =  0x00000001;
93 
94     /**
95      * Action that clears input focus of the node.
96      */
97     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
98 
99     /**
100      * Action that selects the node.
101      */
102     public static final int ACTION_SELECT = 0x00000004;
103 
104     /**
105      * Action that unselects the node.
106      */
107     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
108 
109     /**
110      * Action that clicks on the node info.
111      */
112     public static final int ACTION_CLICK = 0x00000010;
113 
114     /**
115      * Action that long clicks on the node.
116      */
117     public static final int ACTION_LONG_CLICK = 0x00000020;
118 
119     /**
120      * Action that gives accessibility focus to the node.
121      */
122     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
123 
124     /**
125      * Action that clears accessibility focus of the node.
126      */
127     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
128 
129     /**
130      * Action that requests to go to the next entity in this node's text
131      * at a given movement granularity. For example, move to the next character,
132      * word, etc.
133      * <p>
134      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
135      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
136      * <strong>Example:</strong> Move to the previous character and do not extend selection.
137      * <code><pre><p>
138      *   Bundle arguments = new Bundle();
139      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
140      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
141      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
142      *           false);
143      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
144      * </code></pre></p>
145      * </p>
146      *
147      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
148      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
149      *
150      * @see #setMovementGranularities(int)
151      * @see #getMovementGranularities()
152      *
153      * @see #MOVEMENT_GRANULARITY_CHARACTER
154      * @see #MOVEMENT_GRANULARITY_WORD
155      * @see #MOVEMENT_GRANULARITY_LINE
156      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
157      * @see #MOVEMENT_GRANULARITY_PAGE
158      */
159     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
160 
161     /**
162      * Action that requests to go to the previous entity in this node's text
163      * at a given movement granularity. For example, move to the next character,
164      * word, etc.
165      * <p>
166      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
167      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
168      * <strong>Example:</strong> Move to the next character and do not extend selection.
169      * <code><pre><p>
170      *   Bundle arguments = new Bundle();
171      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
172      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
173      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
174      *           false);
175      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
176      *           arguments);
177      * </code></pre></p>
178      * </p>
179      *
180      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
181      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
182      *
183      * @see #setMovementGranularities(int)
184      * @see #getMovementGranularities()
185      *
186      * @see #MOVEMENT_GRANULARITY_CHARACTER
187      * @see #MOVEMENT_GRANULARITY_WORD
188      * @see #MOVEMENT_GRANULARITY_LINE
189      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
190      * @see #MOVEMENT_GRANULARITY_PAGE
191      */
192     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
193 
194     /**
195      * Action to move to the next HTML element of a given type. For example, move
196      * to the BUTTON, INPUT, TABLE, etc.
197      * <p>
198      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
199      * <strong>Example:</strong>
200      * <code><pre><p>
201      *   Bundle arguments = new Bundle();
202      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
203      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
204      * </code></pre></p>
205      * </p>
206      */
207     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
208 
209     /**
210      * Action to move to the previous HTML element of a given type. For example, move
211      * to the BUTTON, INPUT, TABLE, etc.
212      * <p>
213      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
214      * <strong>Example:</strong>
215      * <code><pre><p>
216      *   Bundle arguments = new Bundle();
217      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
218      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
219      * </code></pre></p>
220      * </p>
221      */
222     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
223 
224     /**
225      * Action to scroll the node content forward.
226      */
227     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
228 
229     /**
230      * Action to scroll the node content backward.
231      */
232     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
233 
234     /**
235      * Action to copy the current selection to the clipboard.
236      */
237     public static final int ACTION_COPY = 0x00004000;
238 
239     /**
240      * Action to paste the current clipboard content.
241      */
242     public static final int ACTION_PASTE = 0x00008000;
243 
244     /**
245      * Action to cut the current selection and place it to the clipboard.
246      */
247     public static final int ACTION_CUT = 0x00010000;
248 
249     /**
250      * Action to set the selection. Performing this action with no arguments
251      * clears the selection.
252      * <p>
253      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
254      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
255      * <strong>Example:</strong>
256      * <code><pre><p>
257      *   Bundle arguments = new Bundle();
258      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
259      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
260      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
261      * </code></pre></p>
262      * </p>
263      *
264      * @see #ACTION_ARGUMENT_SELECTION_START_INT
265      * @see #ACTION_ARGUMENT_SELECTION_END_INT
266      */
267     public static final int ACTION_SET_SELECTION = 0x00020000;
268 
269     /**
270      * Argument for which movement granularity to be used when traversing the node text.
271      * <p>
272      * <strong>Type:</strong> int<br>
273      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
274      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
275      * </p>
276      *
277      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
278      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
279      */
280     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
281             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
282 
283     /**
284      * Argument for which HTML element to get moving to the next/previous HTML element.
285      * <p>
286      * <strong>Type:</strong> String<br>
287      * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
288      *         {@link #ACTION_PREVIOUS_HTML_ELEMENT}
289      * </p>
290      *
291      * @see #ACTION_NEXT_HTML_ELEMENT
292      * @see #ACTION_PREVIOUS_HTML_ELEMENT
293      */
294     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
295             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
296 
297     /**
298      * Argument for whether when moving at granularity to extend the selection
299      * or to move it otherwise.
300      * <p>
301      * <strong>Type:</strong> boolean<br>
302      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
303      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
304      * </p>
305      *
306      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
307      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
308      */
309     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
310             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
311 
312     /**
313      * Argument for specifying the selection start.
314      * <p>
315      * <strong>Type:</strong> int<br>
316      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
317      * </p>
318      *
319      * @see #ACTION_SET_SELECTION
320      */
321     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
322             "ACTION_ARGUMENT_SELECTION_START_INT";
323 
324     /**
325      * Argument for specifying the selection end.
326      * <p>
327      * <strong>Type:</strong> int<br>
328      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
329      * </p>
330      *
331      * @see #ACTION_SET_SELECTION
332      */
333     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
334             "ACTION_ARGUMENT_SELECTION_END_INT";
335 
336     /**
337      * The input focus.
338      */
339     public static final int FOCUS_INPUT = 1;
340 
341     /**
342      * The accessibility focus.
343      */
344     public static final int FOCUS_ACCESSIBILITY = 2;
345 
346     // Movement granularities
347 
348     /**
349      * Movement granularity bit for traversing the text of a node by character.
350      */
351     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
352 
353     /**
354      * Movement granularity bit for traversing the text of a node by word.
355      */
356     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
357 
358     /**
359      * Movement granularity bit for traversing the text of a node by line.
360      */
361     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
362 
363     /**
364      * Movement granularity bit for traversing the text of a node by paragraph.
365      */
366     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
367 
368     /**
369      * Movement granularity bit for traversing the text of a node by page.
370      */
371     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
372 
373     // Boolean attributes.
374 
375     private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
376 
377     private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
378 
379     private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
380 
381     private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
382 
383     private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
384 
385     private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
386 
387     private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
388 
389     private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
390 
391     private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
392 
393     private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
394 
395     private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
396 
397     private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
398 
399     private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
400 
401     /**
402      * Bits that provide the id of a virtual descendant of a view.
403      */
404     private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
405 
406     /**
407      * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
408      * virtual descendant of a view. Such a descendant does not exist in the view
409      * hierarchy and is only reported via the accessibility APIs.
410      */
411     private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
412 
413     /**
414      * Gets the accessibility view id which identifies a View in the view three.
415      *
416      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
417      * @return The accessibility view id part of the node id.
418      *
419      * @hide
420      */
getAccessibilityViewId(long accessibilityNodeId)421     public static int getAccessibilityViewId(long accessibilityNodeId) {
422         return (int) accessibilityNodeId;
423     }
424 
425     /**
426      * Gets the virtual descendant id which identifies an imaginary view in a
427      * containing View.
428      *
429      * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
430      * @return The virtual view id part of the node id.
431      *
432      * @hide
433      */
getVirtualDescendantId(long accessibilityNodeId)434     public static int getVirtualDescendantId(long accessibilityNodeId) {
435         return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
436                 >> VIRTUAL_DESCENDANT_ID_SHIFT);
437     }
438 
439     /**
440      * Makes a node id by shifting the <code>virtualDescendantId</code>
441      * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
442      * the bitwise or with the <code>accessibilityViewId</code>.
443      *
444      * @param accessibilityViewId A View accessibility id.
445      * @param virtualDescendantId A virtual descendant id.
446      * @return The node id.
447      *
448      * @hide
449      */
makeNodeId(int accessibilityViewId, int virtualDescendantId)450     public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
451         return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
452     }
453 
454     // Housekeeping.
455     private static final int MAX_POOL_SIZE = 50;
456     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
457             new SynchronizedPool<AccessibilityNodeInfo>(MAX_POOL_SIZE);
458 
459     private boolean mSealed;
460 
461     // Data.
462     private int mWindowId = UNDEFINED;
463     private long mSourceNodeId = ROOT_NODE_ID;
464     private long mParentNodeId = ROOT_NODE_ID;
465     private long mLabelForId = ROOT_NODE_ID;
466     private long mLabeledById = ROOT_NODE_ID;
467 
468     private int mBooleanProperties;
469     private final Rect mBoundsInParent = new Rect();
470     private final Rect mBoundsInScreen = new Rect();
471 
472     private CharSequence mPackageName;
473     private CharSequence mClassName;
474     private CharSequence mText;
475     private CharSequence mContentDescription;
476     private String mViewIdResourceName;
477 
478     private final SparseLongArray mChildNodeIds = new SparseLongArray();
479     private int mActions;
480 
481     private int mMovementGranularities;
482 
483     private int mTextSelectionStart = UNDEFINED;
484     private int mTextSelectionEnd = UNDEFINED;
485 
486     private int mConnectionId = UNDEFINED;
487 
488     /**
489      * Hide constructor from clients.
490      */
AccessibilityNodeInfo()491     private AccessibilityNodeInfo() {
492         /* do nothing */
493     }
494 
495     /**
496      * Sets the source.
497      * <p>
498      *   <strong>Note:</strong> Cannot be called from an
499      *   {@link android.accessibilityservice.AccessibilityService}.
500      *   This class is made immutable before being delivered to an AccessibilityService.
501      * </p>
502      *
503      * @param source The info source.
504      */
setSource(View source)505     public void setSource(View source) {
506         setSource(source, UNDEFINED);
507     }
508 
509     /**
510      * Sets the source to be a virtual descendant of the given <code>root</code>.
511      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
512      * is set as the source.
513      * <p>
514      * A virtual descendant is an imaginary View that is reported as a part of the view
515      * hierarchy for accessibility purposes. This enables custom views that draw complex
516      * content to report themselves as a tree of virtual views, thus conveying their
517      * logical structure.
518      * </p>
519      * <p>
520      *   <strong>Note:</strong> Cannot be called from an
521      *   {@link android.accessibilityservice.AccessibilityService}.
522      *   This class is made immutable before being delivered to an AccessibilityService.
523      * </p>
524      *
525      * @param root The root of the virtual subtree.
526      * @param virtualDescendantId The id of the virtual descendant.
527      */
setSource(View root, int virtualDescendantId)528     public void setSource(View root, int virtualDescendantId) {
529         enforceNotSealed();
530         mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
531         final int rootAccessibilityViewId =
532             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
533         mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
534     }
535 
536     /**
537      * Find the view that has the specified focus type. The search starts from
538      * the view represented by this node info.
539      *
540      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
541      *         {@link #FOCUS_ACCESSIBILITY}.
542      * @return The node info of the focused view or null.
543      *
544      * @see #FOCUS_INPUT
545      * @see #FOCUS_ACCESSIBILITY
546      */
findFocus(int focus)547     public AccessibilityNodeInfo findFocus(int focus) {
548         enforceSealed();
549         enforceValidFocusType(focus);
550         if (!canPerformRequestOverConnection(mSourceNodeId)) {
551             return null;
552         }
553         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
554                 mSourceNodeId, focus);
555     }
556 
557     /**
558      * Searches for the nearest view in the specified direction that can take
559      * the input focus.
560      *
561      * @param direction The direction. Can be one of:
562      *     {@link View#FOCUS_DOWN},
563      *     {@link View#FOCUS_UP},
564      *     {@link View#FOCUS_LEFT},
565      *     {@link View#FOCUS_RIGHT},
566      *     {@link View#FOCUS_FORWARD},
567      *     {@link View#FOCUS_BACKWARD}.
568      *
569      * @return The node info for the view that can take accessibility focus.
570      */
focusSearch(int direction)571     public AccessibilityNodeInfo focusSearch(int direction) {
572         enforceSealed();
573         enforceValidFocusDirection(direction);
574         if (!canPerformRequestOverConnection(mSourceNodeId)) {
575             return null;
576         }
577         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
578                 mSourceNodeId, direction);
579     }
580 
581     /**
582      * Gets the id of the window from which the info comes from.
583      *
584      * @return The window id.
585      */
getWindowId()586     public int getWindowId() {
587         return mWindowId;
588     }
589 
590     /**
591      * Refreshes this info with the latest state of the view it represents.
592      * <p>
593      * <strong>Note:</strong> If this method returns false this info is obsolete
594      * since it represents a view that is no longer in the view tree and should
595      * be recycled.
596      * </p>
597      * @return Whether the refresh succeeded.
598      */
refresh()599     public boolean refresh() {
600         enforceSealed();
601         if (!canPerformRequestOverConnection(mSourceNodeId)) {
602             return false;
603         }
604         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
605         AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
606                 mConnectionId, mWindowId, mSourceNodeId, 0);
607         if (refreshedInfo == null) {
608             return false;
609         }
610         init(refreshedInfo);
611         refreshedInfo.recycle();
612         return true;
613     }
614 
615     /**
616      * @return The ids of the children.
617      *
618      * @hide
619      */
getChildNodeIds()620     public SparseLongArray getChildNodeIds() {
621         return mChildNodeIds;
622     }
623 
624     /**
625      * Gets the number of children.
626      *
627      * @return The child count.
628      */
getChildCount()629     public int getChildCount() {
630         return mChildNodeIds.size();
631     }
632 
633     /**
634      * Get the child at given index.
635      * <p>
636      *   <strong>Note:</strong> It is a client responsibility to recycle the
637      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
638      *     to avoid creating of multiple instances.
639      * </p>
640      *
641      * @param index The child index.
642      * @return The child node.
643      *
644      * @throws IllegalStateException If called outside of an AccessibilityService.
645      *
646      */
getChild(int index)647     public AccessibilityNodeInfo getChild(int index) {
648         enforceSealed();
649         if (!canPerformRequestOverConnection(mSourceNodeId)) {
650             return null;
651         }
652         final long childId = mChildNodeIds.get(index);
653         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
654         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
655                 childId, FLAG_PREFETCH_DESCENDANTS);
656     }
657 
658     /**
659      * Adds a child.
660      * <p>
661      * <strong>Note:</strong> Cannot be called from an
662      * {@link android.accessibilityservice.AccessibilityService}.
663      * This class is made immutable before being delivered to an AccessibilityService.
664      * </p>
665      *
666      * @param child The child.
667      *
668      * @throws IllegalStateException If called from an AccessibilityService.
669      */
addChild(View child)670     public void addChild(View child) {
671         addChild(child, UNDEFINED);
672     }
673 
674     /**
675      * Adds a virtual child which is a descendant of the given <code>root</code>.
676      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
677      * is added as a child.
678      * <p>
679      * A virtual descendant is an imaginary View that is reported as a part of the view
680      * hierarchy for accessibility purposes. This enables custom views that draw complex
681      * content to report them selves as a tree of virtual views, thus conveying their
682      * logical structure.
683      * </p>
684      *
685      * @param root The root of the virtual subtree.
686      * @param virtualDescendantId The id of the virtual child.
687      */
addChild(View root, int virtualDescendantId)688     public void addChild(View root, int virtualDescendantId) {
689         enforceNotSealed();
690         final int index = mChildNodeIds.size();
691         final int rootAccessibilityViewId =
692             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
693         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
694         mChildNodeIds.put(index, childNodeId);
695     }
696 
697     /**
698      * Gets the actions that can be performed on the node.
699      *
700      * @return The bit mask of with actions.
701      *
702      * @see AccessibilityNodeInfo#ACTION_FOCUS
703      * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
704      * @see AccessibilityNodeInfo#ACTION_SELECT
705      * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
706      * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
707      * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
708      * @see AccessibilityNodeInfo#ACTION_CLICK
709      * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
710      * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
711      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
712      * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
713      * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
714      * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
715      * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
716      */
getActions()717     public int getActions() {
718         return mActions;
719     }
720 
721     /**
722      * Adds an action that can be performed on the node.
723      * <p>
724      *   <strong>Note:</strong> Cannot be called from an
725      *   {@link android.accessibilityservice.AccessibilityService}.
726      *   This class is made immutable before being delivered to an AccessibilityService.
727      * </p>
728      *
729      * @param action The action.
730      *
731      * @throws IllegalStateException If called from an AccessibilityService.
732      */
addAction(int action)733     public void addAction(int action) {
734         enforceNotSealed();
735         mActions |= action;
736     }
737 
738     /**
739      * Sets the movement granularities for traversing the text of this node.
740      * <p>
741      *   <strong>Note:</strong> Cannot be called from an
742      *   {@link android.accessibilityservice.AccessibilityService}.
743      *   This class is made immutable before being delivered to an AccessibilityService.
744      * </p>
745      *
746      * @param granularities The bit mask with granularities.
747      *
748      * @throws IllegalStateException If called from an AccessibilityService.
749      */
setMovementGranularities(int granularities)750     public void setMovementGranularities(int granularities) {
751         enforceNotSealed();
752         mMovementGranularities = granularities;
753     }
754 
755     /**
756      * Gets the movement granularities for traversing the text of this node.
757      *
758      * @return The bit mask with granularities.
759      */
getMovementGranularities()760     public int getMovementGranularities() {
761         return mMovementGranularities;
762     }
763 
764     /**
765      * Performs an action on the node.
766      * <p>
767      *   <strong>Note:</strong> An action can be performed only if the request is made
768      *   from an {@link android.accessibilityservice.AccessibilityService}.
769      * </p>
770      *
771      * @param action The action to perform.
772      * @return True if the action was performed.
773      *
774      * @throws IllegalStateException If called outside of an AccessibilityService.
775      */
performAction(int action)776     public boolean performAction(int action) {
777         enforceSealed();
778         if (!canPerformRequestOverConnection(mSourceNodeId)) {
779             return false;
780         }
781         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
782         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
783                 action, null);
784     }
785 
786     /**
787      * Performs an action on the node.
788      * <p>
789      *   <strong>Note:</strong> An action can be performed only if the request is made
790      *   from an {@link android.accessibilityservice.AccessibilityService}.
791      * </p>
792      *
793      * @param action The action to perform.
794      * @param arguments A bundle with additional arguments.
795      * @return True if the action was performed.
796      *
797      * @throws IllegalStateException If called outside of an AccessibilityService.
798      */
performAction(int action, Bundle arguments)799     public boolean performAction(int action, Bundle arguments) {
800         enforceSealed();
801         if (!canPerformRequestOverConnection(mSourceNodeId)) {
802             return false;
803         }
804         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
805         return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
806                 action, arguments);
807     }
808 
809     /**
810      * Finds {@link AccessibilityNodeInfo}s by text. The match is case
811      * insensitive containment. The search is relative to this info i.e.
812      * this info is the root of the traversed tree.
813      *
814      * <p>
815      *   <strong>Note:</strong> It is a client responsibility to recycle the
816      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
817      *     to avoid creating of multiple instances.
818      * </p>
819      *
820      * @param text The searched text.
821      * @return A list of node info.
822      */
findAccessibilityNodeInfosByText(String text)823     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
824         enforceSealed();
825         if (!canPerformRequestOverConnection(mSourceNodeId)) {
826             return Collections.emptyList();
827         }
828         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
829         return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
830                 text);
831     }
832 
833     /**
834      * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
835      * name where a fully qualified id is of the from "package:id/id_resource_name".
836      * For example, if the target application's package is "foo.bar" and the id
837      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
838      *
839      * <p>
840      *   <strong>Note:</strong> It is a client responsibility to recycle the
841      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
842      *     to avoid creating of multiple instances.
843      * </p>
844      * <p>
845      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
846      *   and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
847      *   the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
848      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
849      * </p>
850      *
851      * @param viewId The fully qualified resource name of the view id to find.
852      * @return A list of node info.
853      */
findAccessibilityNodeInfosByViewId(String viewId)854     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
855         enforceSealed();
856         if (!canPerformRequestOverConnection(mSourceNodeId)) {
857             return Collections.emptyList();
858         }
859         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
860         return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
861                 viewId);
862     }
863 
864     /**
865      * Gets the parent.
866      * <p>
867      *   <strong>Note:</strong> It is a client responsibility to recycle the
868      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
869      *     to avoid creating of multiple instances.
870      * </p>
871      *
872      * @return The parent.
873      */
getParent()874     public AccessibilityNodeInfo getParent() {
875         enforceSealed();
876         if (!canPerformRequestOverConnection(mParentNodeId)) {
877             return null;
878         }
879         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
880         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
881                 mWindowId, mParentNodeId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
882     }
883 
884     /**
885      * @return The parent node id.
886      *
887      * @hide
888      */
getParentNodeId()889     public long getParentNodeId() {
890         return mParentNodeId;
891     }
892 
893     /**
894      * Sets the parent.
895      * <p>
896      *   <strong>Note:</strong> Cannot be called from an
897      *   {@link android.accessibilityservice.AccessibilityService}.
898      *   This class is made immutable before being delivered to an AccessibilityService.
899      * </p>
900      *
901      * @param parent The parent.
902      *
903      * @throws IllegalStateException If called from an AccessibilityService.
904      */
setParent(View parent)905     public void setParent(View parent) {
906         setParent(parent, UNDEFINED);
907     }
908 
909     /**
910      * Sets the parent to be a virtual descendant of the given <code>root</code>.
911      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
912      * is set as the parent.
913      * <p>
914      * A virtual descendant is an imaginary View that is reported as a part of the view
915      * hierarchy for accessibility purposes. This enables custom views that draw complex
916      * content to report them selves as a tree of virtual views, thus conveying their
917      * logical structure.
918      * </p>
919      * <p>
920      *   <strong>Note:</strong> Cannot be called from an
921      *   {@link android.accessibilityservice.AccessibilityService}.
922      *   This class is made immutable before being delivered to an AccessibilityService.
923      * </p>
924      *
925      * @param root The root of the virtual subtree.
926      * @param virtualDescendantId The id of the virtual descendant.
927      */
setParent(View root, int virtualDescendantId)928     public void setParent(View root, int virtualDescendantId) {
929         enforceNotSealed();
930         final int rootAccessibilityViewId =
931             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
932         mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
933     }
934 
935     /**
936      * Gets the node bounds in parent coordinates.
937      *
938      * @param outBounds The output node bounds.
939      */
getBoundsInParent(Rect outBounds)940     public void getBoundsInParent(Rect outBounds) {
941         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
942                 mBoundsInParent.right, mBoundsInParent.bottom);
943     }
944 
945     /**
946      * Sets the node bounds in parent coordinates.
947      * <p>
948      *   <strong>Note:</strong> Cannot be called from an
949      *   {@link android.accessibilityservice.AccessibilityService}.
950      *   This class is made immutable before being delivered to an AccessibilityService.
951      * </p>
952      *
953      * @param bounds The node bounds.
954      *
955      * @throws IllegalStateException If called from an AccessibilityService.
956      */
setBoundsInParent(Rect bounds)957     public void setBoundsInParent(Rect bounds) {
958         enforceNotSealed();
959         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
960     }
961 
962     /**
963      * Gets the node bounds in screen coordinates.
964      *
965      * @param outBounds The output node bounds.
966      */
getBoundsInScreen(Rect outBounds)967     public void getBoundsInScreen(Rect outBounds) {
968         outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
969                 mBoundsInScreen.right, mBoundsInScreen.bottom);
970     }
971 
972     /**
973      * Sets the node bounds in screen coordinates.
974      * <p>
975      *   <strong>Note:</strong> Cannot be called from an
976      *   {@link android.accessibilityservice.AccessibilityService}.
977      *   This class is made immutable before being delivered to an AccessibilityService.
978      * </p>
979      *
980      * @param bounds The node bounds.
981      *
982      * @throws IllegalStateException If called from an AccessibilityService.
983      */
setBoundsInScreen(Rect bounds)984     public void setBoundsInScreen(Rect bounds) {
985         enforceNotSealed();
986         mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
987     }
988 
989     /**
990      * Gets whether this node is checkable.
991      *
992      * @return True if the node is checkable.
993      */
isCheckable()994     public boolean isCheckable() {
995         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
996     }
997 
998     /**
999      * Sets whether this node is checkable.
1000      * <p>
1001      *   <strong>Note:</strong> Cannot be called from an
1002      *   {@link android.accessibilityservice.AccessibilityService}.
1003      *   This class is made immutable before being delivered to an AccessibilityService.
1004      * </p>
1005      *
1006      * @param checkable True if the node is checkable.
1007      *
1008      * @throws IllegalStateException If called from an AccessibilityService.
1009      */
setCheckable(boolean checkable)1010     public void setCheckable(boolean checkable) {
1011         setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
1012     }
1013 
1014     /**
1015      * Gets whether this node is checked.
1016      *
1017      * @return True if the node is checked.
1018      */
isChecked()1019     public boolean isChecked() {
1020         return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
1021     }
1022 
1023     /**
1024      * Sets whether this node is checked.
1025      * <p>
1026      *   <strong>Note:</strong> Cannot be called from an
1027      *   {@link android.accessibilityservice.AccessibilityService}.
1028      *   This class is made immutable before being delivered to an AccessibilityService.
1029      * </p>
1030      *
1031      * @param checked True if the node is checked.
1032      *
1033      * @throws IllegalStateException If called from an AccessibilityService.
1034      */
setChecked(boolean checked)1035     public void setChecked(boolean checked) {
1036         setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
1037     }
1038 
1039     /**
1040      * Gets whether this node is focusable.
1041      *
1042      * @return True if the node is focusable.
1043      */
isFocusable()1044     public boolean isFocusable() {
1045         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
1046     }
1047 
1048     /**
1049      * Sets whether this node is focusable.
1050      * <p>
1051      *   <strong>Note:</strong> Cannot be called from an
1052      *   {@link android.accessibilityservice.AccessibilityService}.
1053      *   This class is made immutable before being delivered to an AccessibilityService.
1054      * </p>
1055      *
1056      * @param focusable True if the node is focusable.
1057      *
1058      * @throws IllegalStateException If called from an AccessibilityService.
1059      */
setFocusable(boolean focusable)1060     public void setFocusable(boolean focusable) {
1061         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
1062     }
1063 
1064     /**
1065      * Gets whether this node is focused.
1066      *
1067      * @return True if the node is focused.
1068      */
isFocused()1069     public boolean isFocused() {
1070         return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
1071     }
1072 
1073     /**
1074      * Sets whether this node is focused.
1075      * <p>
1076      *   <strong>Note:</strong> Cannot be called from an
1077      *   {@link android.accessibilityservice.AccessibilityService}.
1078      *   This class is made immutable before being delivered to an AccessibilityService.
1079      * </p>
1080      *
1081      * @param focused True if the node is focused.
1082      *
1083      * @throws IllegalStateException If called from an AccessibilityService.
1084      */
setFocused(boolean focused)1085     public void setFocused(boolean focused) {
1086         setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
1087     }
1088 
1089     /**
1090      * Sets whether this node is visible to the user.
1091      *
1092      * @return Whether the node is visible to the user.
1093      */
isVisibleToUser()1094     public boolean isVisibleToUser() {
1095         return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
1096     }
1097 
1098     /**
1099      * Sets whether this node is visible to the user.
1100      * <p>
1101      *   <strong>Note:</strong> Cannot be called from an
1102      *   {@link android.accessibilityservice.AccessibilityService}.
1103      *   This class is made immutable before being delivered to an AccessibilityService.
1104      * </p>
1105      *
1106      * @param visibleToUser Whether the node is visible to the user.
1107      *
1108      * @throws IllegalStateException If called from an AccessibilityService.
1109      */
setVisibleToUser(boolean visibleToUser)1110     public void setVisibleToUser(boolean visibleToUser) {
1111         setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
1112     }
1113 
1114     /**
1115      * Gets whether this node is accessibility focused.
1116      *
1117      * @return True if the node is accessibility focused.
1118      */
isAccessibilityFocused()1119     public boolean isAccessibilityFocused() {
1120         return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
1121     }
1122 
1123     /**
1124      * Sets whether this node is accessibility focused.
1125      * <p>
1126      *   <strong>Note:</strong> Cannot be called from an
1127      *   {@link android.accessibilityservice.AccessibilityService}.
1128      *   This class is made immutable before being delivered to an AccessibilityService.
1129      * </p>
1130      *
1131      * @param focused True if the node is accessibility focused.
1132      *
1133      * @throws IllegalStateException If called from an AccessibilityService.
1134      */
setAccessibilityFocused(boolean focused)1135     public void setAccessibilityFocused(boolean focused) {
1136         setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
1137     }
1138 
1139     /**
1140      * Gets whether this node is selected.
1141      *
1142      * @return True if the node is selected.
1143      */
isSelected()1144     public boolean isSelected() {
1145         return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
1146     }
1147 
1148     /**
1149      * Sets whether this node is selected.
1150      * <p>
1151      *   <strong>Note:</strong> Cannot be called from an
1152      *   {@link android.accessibilityservice.AccessibilityService}.
1153      *   This class is made immutable before being delivered to an AccessibilityService.
1154      * </p>
1155      *
1156      * @param selected True if the node is selected.
1157      *
1158      * @throws IllegalStateException If called from an AccessibilityService.
1159      */
setSelected(boolean selected)1160     public void setSelected(boolean selected) {
1161         setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
1162     }
1163 
1164     /**
1165      * Gets whether this node is clickable.
1166      *
1167      * @return True if the node is clickable.
1168      */
isClickable()1169     public boolean isClickable() {
1170         return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
1171     }
1172 
1173     /**
1174      * Sets whether this node is clickable.
1175      * <p>
1176      *   <strong>Note:</strong> Cannot be called from an
1177      *   {@link android.accessibilityservice.AccessibilityService}.
1178      *   This class is made immutable before being delivered to an AccessibilityService.
1179      * </p>
1180      *
1181      * @param clickable True if the node is clickable.
1182      *
1183      * @throws IllegalStateException If called from an AccessibilityService.
1184      */
setClickable(boolean clickable)1185     public void setClickable(boolean clickable) {
1186         setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
1187     }
1188 
1189     /**
1190      * Gets whether this node is long clickable.
1191      *
1192      * @return True if the node is long clickable.
1193      */
isLongClickable()1194     public boolean isLongClickable() {
1195         return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
1196     }
1197 
1198     /**
1199      * Sets whether this node is long clickable.
1200      * <p>
1201      *   <strong>Note:</strong> Cannot be called from an
1202      *   {@link android.accessibilityservice.AccessibilityService}.
1203      *   This class is made immutable before being delivered to an AccessibilityService.
1204      * </p>
1205      *
1206      * @param longClickable True if the node is long clickable.
1207      *
1208      * @throws IllegalStateException If called from an AccessibilityService.
1209      */
setLongClickable(boolean longClickable)1210     public void setLongClickable(boolean longClickable) {
1211         setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
1212     }
1213 
1214     /**
1215      * Gets whether this node is enabled.
1216      *
1217      * @return True if the node is enabled.
1218      */
isEnabled()1219     public boolean isEnabled() {
1220         return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
1221     }
1222 
1223     /**
1224      * Sets whether this node is enabled.
1225      * <p>
1226      *   <strong>Note:</strong> Cannot be called from an
1227      *   {@link android.accessibilityservice.AccessibilityService}.
1228      *   This class is made immutable before being delivered to an AccessibilityService.
1229      * </p>
1230      *
1231      * @param enabled True if the node is enabled.
1232      *
1233      * @throws IllegalStateException If called from an AccessibilityService.
1234      */
setEnabled(boolean enabled)1235     public void setEnabled(boolean enabled) {
1236         setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
1237     }
1238 
1239     /**
1240      * Gets whether this node is a password.
1241      *
1242      * @return True if the node is a password.
1243      */
isPassword()1244     public boolean isPassword() {
1245         return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
1246     }
1247 
1248     /**
1249      * Sets whether this node is a password.
1250      * <p>
1251      *   <strong>Note:</strong> Cannot be called from an
1252      *   {@link android.accessibilityservice.AccessibilityService}.
1253      *   This class is made immutable before being delivered to an AccessibilityService.
1254      * </p>
1255      *
1256      * @param password True if the node is a password.
1257      *
1258      * @throws IllegalStateException If called from an AccessibilityService.
1259      */
setPassword(boolean password)1260     public void setPassword(boolean password) {
1261         setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
1262     }
1263 
1264     /**
1265      * Gets if the node is scrollable.
1266      *
1267      * @return True if the node is scrollable, false otherwise.
1268      */
isScrollable()1269     public boolean isScrollable() {
1270         return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
1271     }
1272 
1273     /**
1274      * Sets if the node is scrollable.
1275      * <p>
1276      *   <strong>Note:</strong> Cannot be called from an
1277      *   {@link android.accessibilityservice.AccessibilityService}.
1278      *   This class is made immutable before being delivered to an AccessibilityService.
1279      * </p>
1280      *
1281      * @param scrollable True if the node is scrollable, false otherwise.
1282      *
1283      * @throws IllegalStateException If called from an AccessibilityService.
1284      */
setScrollable(boolean scrollable)1285     public void setScrollable(boolean scrollable) {
1286         enforceNotSealed();
1287         setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
1288     }
1289 
1290     /**
1291      * Gets if the node is editable.
1292      *
1293      * @return True if the node is editable, false otherwise.
1294      */
isEditable()1295     public boolean isEditable() {
1296         return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
1297     }
1298 
1299     /**
1300      * Sets whether this node is editable.
1301      * <p>
1302      *   <strong>Note:</strong> Cannot be called from an
1303      *   {@link android.accessibilityservice.AccessibilityService}.
1304      *   This class is made immutable before being delivered to an AccessibilityService.
1305      * </p>
1306      *
1307      * @param editable True if the node is editable.
1308      *
1309      * @throws IllegalStateException If called from an AccessibilityService.
1310      */
setEditable(boolean editable)1311     public void setEditable(boolean editable) {
1312         setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
1313     }
1314 
1315     /**
1316      * Gets the package this node comes from.
1317      *
1318      * @return The package name.
1319      */
getPackageName()1320     public CharSequence getPackageName() {
1321         return mPackageName;
1322     }
1323 
1324     /**
1325      * Sets the package this node comes from.
1326      * <p>
1327      *   <strong>Note:</strong> Cannot be called from an
1328      *   {@link android.accessibilityservice.AccessibilityService}.
1329      *   This class is made immutable before being delivered to an AccessibilityService.
1330      * </p>
1331      *
1332      * @param packageName The package name.
1333      *
1334      * @throws IllegalStateException If called from an AccessibilityService.
1335      */
setPackageName(CharSequence packageName)1336     public void setPackageName(CharSequence packageName) {
1337         enforceNotSealed();
1338         mPackageName = packageName;
1339     }
1340 
1341     /**
1342      * Gets the class this node comes from.
1343      *
1344      * @return The class name.
1345      */
getClassName()1346     public CharSequence getClassName() {
1347         return mClassName;
1348     }
1349 
1350     /**
1351      * Sets the class this node comes from.
1352      * <p>
1353      *   <strong>Note:</strong> Cannot be called from an
1354      *   {@link android.accessibilityservice.AccessibilityService}.
1355      *   This class is made immutable before being delivered to an AccessibilityService.
1356      * </p>
1357      *
1358      * @param className The class name.
1359      *
1360      * @throws IllegalStateException If called from an AccessibilityService.
1361      */
setClassName(CharSequence className)1362     public void setClassName(CharSequence className) {
1363         enforceNotSealed();
1364         mClassName = className;
1365     }
1366 
1367     /**
1368      * Gets the text of this node.
1369      *
1370      * @return The text.
1371      */
getText()1372     public CharSequence getText() {
1373         return mText;
1374     }
1375 
1376     /**
1377      * Sets the text of this node.
1378      * <p>
1379      *   <strong>Note:</strong> Cannot be called from an
1380      *   {@link android.accessibilityservice.AccessibilityService}.
1381      *   This class is made immutable before being delivered to an AccessibilityService.
1382      * </p>
1383      *
1384      * @param text The text.
1385      *
1386      * @throws IllegalStateException If called from an AccessibilityService.
1387      */
setText(CharSequence text)1388     public void setText(CharSequence text) {
1389         enforceNotSealed();
1390         mText = text;
1391     }
1392 
1393     /**
1394      * Gets the content description of this node.
1395      *
1396      * @return The content description.
1397      */
getContentDescription()1398     public CharSequence getContentDescription() {
1399         return mContentDescription;
1400     }
1401 
1402     /**
1403      * Sets the content description of this node.
1404      * <p>
1405      *   <strong>Note:</strong> Cannot be called from an
1406      *   {@link android.accessibilityservice.AccessibilityService}.
1407      *   This class is made immutable before being delivered to an AccessibilityService.
1408      * </p>
1409      *
1410      * @param contentDescription The content description.
1411      *
1412      * @throws IllegalStateException If called from an AccessibilityService.
1413      */
setContentDescription(CharSequence contentDescription)1414     public void setContentDescription(CharSequence contentDescription) {
1415         enforceNotSealed();
1416         mContentDescription = contentDescription;
1417     }
1418 
1419     /**
1420      * Sets the view for which the view represented by this info serves as a
1421      * label for accessibility purposes.
1422      *
1423      * @param labeled The view for which this info serves as a label.
1424      */
setLabelFor(View labeled)1425     public void setLabelFor(View labeled) {
1426         setLabelFor(labeled, UNDEFINED);
1427     }
1428 
1429     /**
1430      * Sets the view for which the view represented by this info serves as a
1431      * label for accessibility purposes. If <code>virtualDescendantId</code>
1432      * is {@link View#NO_ID} the root is set as the labeled.
1433      * <p>
1434      * A virtual descendant is an imaginary View that is reported as a part of the view
1435      * hierarchy for accessibility purposes. This enables custom views that draw complex
1436      * content to report themselves as a tree of virtual views, thus conveying their
1437      * logical structure.
1438      * </p>
1439      * <p>
1440      *   <strong>Note:</strong> Cannot be called from an
1441      *   {@link android.accessibilityservice.AccessibilityService}.
1442      *   This class is made immutable before being delivered to an AccessibilityService.
1443      * </p>
1444      *
1445      * @param root The root whose virtual descendant serves as a label.
1446      * @param virtualDescendantId The id of the virtual descendant.
1447      */
setLabelFor(View root, int virtualDescendantId)1448     public void setLabelFor(View root, int virtualDescendantId) {
1449         enforceNotSealed();
1450         final int rootAccessibilityViewId = (root != null)
1451                 ? root.getAccessibilityViewId() : UNDEFINED;
1452         mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1453     }
1454 
1455     /**
1456      * Gets the node info for which the view represented by this info serves as
1457      * a label for accessibility purposes.
1458      * <p>
1459      *   <strong>Note:</strong> It is a client responsibility to recycle the
1460      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
1461      *     to avoid creating of multiple instances.
1462      * </p>
1463      *
1464      * @return The labeled info.
1465      */
getLabelFor()1466     public AccessibilityNodeInfo getLabelFor() {
1467         enforceSealed();
1468         if (!canPerformRequestOverConnection(mLabelForId)) {
1469             return null;
1470         }
1471         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1472         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
1473                 mWindowId, mLabelForId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
1474     }
1475 
1476     /**
1477      * Sets the view which serves as the label of the view represented by
1478      * this info for accessibility purposes.
1479      *
1480      * @param label The view that labels this node's source.
1481      */
setLabeledBy(View label)1482     public void setLabeledBy(View label) {
1483         setLabeledBy(label, UNDEFINED);
1484     }
1485 
1486     /**
1487      * Sets the view which serves as the label of the view represented by
1488      * this info for accessibility purposes. If <code>virtualDescendantId</code>
1489      * is {@link View#NO_ID} the root is set as the label.
1490      * <p>
1491      * A virtual descendant is an imaginary View that is reported as a part of the view
1492      * hierarchy for accessibility purposes. This enables custom views that draw complex
1493      * content to report themselves as a tree of virtual views, thus conveying their
1494      * logical structure.
1495      * </p>
1496      * <p>
1497      *   <strong>Note:</strong> Cannot be called from an
1498      *   {@link android.accessibilityservice.AccessibilityService}.
1499      *   This class is made immutable before being delivered to an AccessibilityService.
1500      * </p>
1501      *
1502      * @param root The root whose virtual descendant labels this node's source.
1503      * @param virtualDescendantId The id of the virtual descendant.
1504      */
setLabeledBy(View root, int virtualDescendantId)1505     public void setLabeledBy(View root, int virtualDescendantId) {
1506         enforceNotSealed();
1507         final int rootAccessibilityViewId = (root != null)
1508                 ? root.getAccessibilityViewId() : UNDEFINED;
1509         mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1510     }
1511 
1512     /**
1513      * Gets the node info which serves as the label of the view represented by
1514      * this info for accessibility purposes.
1515      * <p>
1516      *   <strong>Note:</strong> It is a client responsibility to recycle the
1517      *     received info by calling {@link AccessibilityNodeInfo#recycle()}
1518      *     to avoid creating of multiple instances.
1519      * </p>
1520      *
1521      * @return The label.
1522      */
getLabeledBy()1523     public AccessibilityNodeInfo getLabeledBy() {
1524         enforceSealed();
1525         if (!canPerformRequestOverConnection(mLabeledById)) {
1526             return null;
1527         }
1528         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1529         return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
1530                 mWindowId, mLabeledById, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
1531     }
1532 
1533     /**
1534      * Sets the fully qualified resource name of the source view's id.
1535      *
1536      * <p>
1537      *   <strong>Note:</strong> Cannot be called from an
1538      *   {@link android.accessibilityservice.AccessibilityService}.
1539      *   This class is made immutable before being delivered to an AccessibilityService.
1540      * </p>
1541      *
1542      * @param viewIdResName The id resource name.
1543      */
setViewIdResourceName(String viewIdResName)1544     public void setViewIdResourceName(String viewIdResName) {
1545         enforceNotSealed();
1546         mViewIdResourceName = viewIdResName;
1547     }
1548 
1549     /**
1550      * Gets the fully qualified resource name of the source view's id.
1551      *
1552      * <p>
1553      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
1554      *   and in order to report the source view id of an {@link AccessibilityNodeInfo} the
1555      *   client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
1556      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
1557      * </p>
1558 
1559      * @return The id resource name.
1560      */
getViewIdResourceName()1561     public String getViewIdResourceName() {
1562         return mViewIdResourceName;
1563     }
1564 
1565     /**
1566      * Gets the text selection start.
1567      *
1568      * @return The text selection start if there is selection or -1.
1569      */
getTextSelectionStart()1570     public int getTextSelectionStart() {
1571         return mTextSelectionStart;
1572     }
1573 
1574     /**
1575      * Gets the text selection end.
1576      *
1577      * @return The text selection end if there is selection or -1.
1578      */
getTextSelectionEnd()1579     public int getTextSelectionEnd() {
1580         return mTextSelectionEnd;
1581     }
1582 
1583     /**
1584      * Sets the text selection start and end.
1585      * <p>
1586      *   <strong>Note:</strong> Cannot be called from an
1587      *   {@link android.accessibilityservice.AccessibilityService}.
1588      *   This class is made immutable before being delivered to an AccessibilityService.
1589      * </p>
1590      *
1591      * @param start The text selection start.
1592      * @param end The text selection end.
1593      *
1594      * @throws IllegalStateException If called from an AccessibilityService.
1595      */
setTextSelection(int start, int end)1596     public void setTextSelection(int start, int end) {
1597         enforceNotSealed();
1598         mTextSelectionStart = start;
1599         mTextSelectionEnd = end;
1600     }
1601 
1602     /**
1603      * Gets the value of a boolean property.
1604      *
1605      * @param property The property.
1606      * @return The value.
1607      */
getBooleanProperty(int property)1608     private boolean getBooleanProperty(int property) {
1609         return (mBooleanProperties & property) != 0;
1610     }
1611 
1612     /**
1613      * Sets a boolean property.
1614      *
1615      * @param property The property.
1616      * @param value The value.
1617      *
1618      * @throws IllegalStateException If called from an AccessibilityService.
1619      */
setBooleanProperty(int property, boolean value)1620     private void setBooleanProperty(int property, boolean value) {
1621         enforceNotSealed();
1622         if (value) {
1623             mBooleanProperties |= property;
1624         } else {
1625             mBooleanProperties &= ~property;
1626         }
1627     }
1628 
1629     /**
1630      * Sets the unique id of the IAccessibilityServiceConnection over which
1631      * this instance can send requests to the system.
1632      *
1633      * @param connectionId The connection id.
1634      *
1635      * @hide
1636      */
setConnectionId(int connectionId)1637     public void setConnectionId(int connectionId) {
1638         enforceNotSealed();
1639         mConnectionId = connectionId;
1640     }
1641 
1642     /**
1643      * {@inheritDoc}
1644      */
describeContents()1645     public int describeContents() {
1646         return 0;
1647     }
1648 
1649     /**
1650      * Gets the id of the source node.
1651      *
1652      * @return The id.
1653      *
1654      * @hide
1655      */
getSourceNodeId()1656     public long getSourceNodeId() {
1657         return mSourceNodeId;
1658     }
1659 
1660     /**
1661      * Sets if this instance is sealed.
1662      *
1663      * @param sealed Whether is sealed.
1664      *
1665      * @hide
1666      */
setSealed(boolean sealed)1667     public void setSealed(boolean sealed) {
1668         mSealed = sealed;
1669     }
1670 
1671     /**
1672      * Gets if this instance is sealed.
1673      *
1674      * @return Whether is sealed.
1675      *
1676      * @hide
1677      */
isSealed()1678     public boolean isSealed() {
1679         return mSealed;
1680     }
1681 
1682     /**
1683      * Enforces that this instance is sealed.
1684      *
1685      * @throws IllegalStateException If this instance is not sealed.
1686      *
1687      * @hide
1688      */
enforceSealed()1689     protected void enforceSealed() {
1690         if (!isSealed()) {
1691             throw new IllegalStateException("Cannot perform this "
1692                     + "action on a not sealed instance.");
1693         }
1694     }
1695 
enforceValidFocusDirection(int direction)1696     private void enforceValidFocusDirection(int direction) {
1697         switch (direction) {
1698             case View.FOCUS_DOWN:
1699             case View.FOCUS_UP:
1700             case View.FOCUS_LEFT:
1701             case View.FOCUS_RIGHT:
1702             case View.FOCUS_FORWARD:
1703             case View.FOCUS_BACKWARD:
1704                 return;
1705             default:
1706                 throw new IllegalArgumentException("Unknown direction: " + direction);
1707         }
1708     }
1709 
enforceValidFocusType(int focusType)1710     private void enforceValidFocusType(int focusType) {
1711         switch (focusType) {
1712             case FOCUS_INPUT:
1713             case FOCUS_ACCESSIBILITY:
1714                 return;
1715             default:
1716                 throw new IllegalArgumentException("Unknown focus type: " + focusType);
1717         }
1718     }
1719 
1720     /**
1721      * Enforces that this instance is not sealed.
1722      *
1723      * @throws IllegalStateException If this instance is sealed.
1724      *
1725      * @hide
1726      */
enforceNotSealed()1727     protected void enforceNotSealed() {
1728         if (isSealed()) {
1729             throw new IllegalStateException("Cannot perform this "
1730                     + "action on a sealed instance.");
1731         }
1732     }
1733 
1734     /**
1735      * Returns a cached instance if such is available otherwise a new one
1736      * and sets the source.
1737      *
1738      * @param source The source view.
1739      * @return An instance.
1740      *
1741      * @see #setSource(View)
1742      */
obtain(View source)1743     public static AccessibilityNodeInfo obtain(View source) {
1744         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
1745         info.setSource(source);
1746         return info;
1747     }
1748 
1749     /**
1750      * Returns a cached instance if such is available otherwise a new one
1751      * and sets the source.
1752      *
1753      * @param root The root of the virtual subtree.
1754      * @param virtualDescendantId The id of the virtual descendant.
1755      * @return An instance.
1756      *
1757      * @see #setSource(View, int)
1758      */
obtain(View root, int virtualDescendantId)1759     public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
1760         AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
1761         info.setSource(root, virtualDescendantId);
1762         return info;
1763     }
1764 
1765     /**
1766      * Returns a cached instance if such is available otherwise a new one.
1767      *
1768      * @return An instance.
1769      */
obtain()1770     public static AccessibilityNodeInfo obtain() {
1771         AccessibilityNodeInfo info = sPool.acquire();
1772         return (info != null) ? info : new AccessibilityNodeInfo();
1773     }
1774 
1775     /**
1776      * Returns a cached instance if such is available or a new one is
1777      * create. The returned instance is initialized from the given
1778      * <code>info</code>.
1779      *
1780      * @param info The other info.
1781      * @return An instance.
1782      */
obtain(AccessibilityNodeInfo info)1783     public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
1784         AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
1785         infoClone.init(info);
1786         return infoClone;
1787     }
1788 
1789     /**
1790      * Return an instance back to be reused.
1791      * <p>
1792      * <strong>Note:</strong> You must not touch the object after calling this function.
1793      *
1794      * @throws IllegalStateException If the info is already recycled.
1795      */
recycle()1796     public void recycle() {
1797         clear();
1798         sPool.release(this);
1799     }
1800 
1801     /**
1802      * {@inheritDoc}
1803      * <p>
1804      *   <strong>Note:</strong> After the instance is written to a parcel it
1805      *      is recycled. You must not touch the object after calling this function.
1806      * </p>
1807      */
writeToParcel(Parcel parcel, int flags)1808     public void writeToParcel(Parcel parcel, int flags) {
1809         parcel.writeInt(isSealed() ? 1 : 0);
1810         parcel.writeLong(mSourceNodeId);
1811         parcel.writeInt(mWindowId);
1812         parcel.writeLong(mParentNodeId);
1813         parcel.writeLong(mLabelForId);
1814         parcel.writeLong(mLabeledById);
1815         parcel.writeInt(mConnectionId);
1816 
1817         SparseLongArray childIds = mChildNodeIds;
1818         final int childIdsSize = childIds.size();
1819         parcel.writeInt(childIdsSize);
1820         for (int i = 0; i < childIdsSize; i++) {
1821             parcel.writeLong(childIds.valueAt(i));
1822         }
1823 
1824         parcel.writeInt(mBoundsInParent.top);
1825         parcel.writeInt(mBoundsInParent.bottom);
1826         parcel.writeInt(mBoundsInParent.left);
1827         parcel.writeInt(mBoundsInParent.right);
1828 
1829         parcel.writeInt(mBoundsInScreen.top);
1830         parcel.writeInt(mBoundsInScreen.bottom);
1831         parcel.writeInt(mBoundsInScreen.left);
1832         parcel.writeInt(mBoundsInScreen.right);
1833 
1834         parcel.writeInt(mActions);
1835 
1836         parcel.writeInt(mMovementGranularities);
1837 
1838         parcel.writeInt(mBooleanProperties);
1839 
1840         parcel.writeCharSequence(mPackageName);
1841         parcel.writeCharSequence(mClassName);
1842         parcel.writeCharSequence(mText);
1843         parcel.writeCharSequence(mContentDescription);
1844         parcel.writeString(mViewIdResourceName);
1845 
1846         parcel.writeInt(mTextSelectionStart);
1847         parcel.writeInt(mTextSelectionEnd);
1848 
1849         // Since instances of this class are fetched via synchronous i.e. blocking
1850         // calls in IPCs we always recycle as soon as the instance is marshaled.
1851         recycle();
1852     }
1853 
1854     /**
1855      * Initializes this instance from another one.
1856      *
1857      * @param other The other instance.
1858      */
init(AccessibilityNodeInfo other)1859     private void init(AccessibilityNodeInfo other) {
1860         mSealed = other.mSealed;
1861         mSourceNodeId = other.mSourceNodeId;
1862         mParentNodeId = other.mParentNodeId;
1863         mLabelForId = other.mLabelForId;
1864         mLabeledById = other.mLabeledById;
1865         mWindowId = other.mWindowId;
1866         mConnectionId = other.mConnectionId;
1867         mBoundsInParent.set(other.mBoundsInParent);
1868         mBoundsInScreen.set(other.mBoundsInScreen);
1869         mPackageName = other.mPackageName;
1870         mClassName = other.mClassName;
1871         mText = other.mText;
1872         mContentDescription = other.mContentDescription;
1873         mViewIdResourceName = other.mViewIdResourceName;
1874         mActions= other.mActions;
1875         mBooleanProperties = other.mBooleanProperties;
1876         mMovementGranularities = other.mMovementGranularities;
1877         final int otherChildIdCount = other.mChildNodeIds.size();
1878         for (int i = 0; i < otherChildIdCount; i++) {
1879             mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
1880         }
1881         mTextSelectionStart = other.mTextSelectionStart;
1882         mTextSelectionEnd = other.mTextSelectionEnd;
1883     }
1884 
1885     /**
1886      * Creates a new instance from a {@link Parcel}.
1887      *
1888      * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
1889      */
initFromParcel(Parcel parcel)1890     private void initFromParcel(Parcel parcel) {
1891         mSealed = (parcel.readInt()  == 1);
1892         mSourceNodeId = parcel.readLong();
1893         mWindowId = parcel.readInt();
1894         mParentNodeId = parcel.readLong();
1895         mLabelForId = parcel.readLong();
1896         mLabeledById = parcel.readLong();
1897         mConnectionId = parcel.readInt();
1898 
1899         SparseLongArray childIds = mChildNodeIds;
1900         final int childrenSize = parcel.readInt();
1901         for (int i = 0; i < childrenSize; i++) {
1902             final long childId = parcel.readLong();
1903             childIds.put(i, childId);
1904         }
1905 
1906         mBoundsInParent.top = parcel.readInt();
1907         mBoundsInParent.bottom = parcel.readInt();
1908         mBoundsInParent.left = parcel.readInt();
1909         mBoundsInParent.right = parcel.readInt();
1910 
1911         mBoundsInScreen.top = parcel.readInt();
1912         mBoundsInScreen.bottom = parcel.readInt();
1913         mBoundsInScreen.left = parcel.readInt();
1914         mBoundsInScreen.right = parcel.readInt();
1915 
1916         mActions = parcel.readInt();
1917 
1918         mMovementGranularities = parcel.readInt();
1919 
1920         mBooleanProperties = parcel.readInt();
1921 
1922         mPackageName = parcel.readCharSequence();
1923         mClassName = parcel.readCharSequence();
1924         mText = parcel.readCharSequence();
1925         mContentDescription = parcel.readCharSequence();
1926         mViewIdResourceName = parcel.readString();
1927 
1928         mTextSelectionStart = parcel.readInt();
1929         mTextSelectionEnd = parcel.readInt();
1930     }
1931 
1932     /**
1933      * Clears the state of this instance.
1934      */
clear()1935     private void clear() {
1936         mSealed = false;
1937         mSourceNodeId = ROOT_NODE_ID;
1938         mParentNodeId = ROOT_NODE_ID;
1939         mLabelForId = ROOT_NODE_ID;
1940         mLabeledById = ROOT_NODE_ID;
1941         mWindowId = UNDEFINED;
1942         mConnectionId = UNDEFINED;
1943         mMovementGranularities = 0;
1944         mChildNodeIds.clear();
1945         mBoundsInParent.set(0, 0, 0, 0);
1946         mBoundsInScreen.set(0, 0, 0, 0);
1947         mBooleanProperties = 0;
1948         mPackageName = null;
1949         mClassName = null;
1950         mText = null;
1951         mContentDescription = null;
1952         mViewIdResourceName = null;
1953         mActions = 0;
1954         mTextSelectionStart = UNDEFINED;
1955         mTextSelectionEnd = UNDEFINED;
1956     }
1957 
1958     /**
1959      * Gets the human readable action symbolic name.
1960      *
1961      * @param action The action.
1962      * @return The symbolic name.
1963      */
getActionSymbolicName(int action)1964     private static String getActionSymbolicName(int action) {
1965         switch (action) {
1966             case ACTION_FOCUS:
1967                 return "ACTION_FOCUS";
1968             case ACTION_CLEAR_FOCUS:
1969                 return "ACTION_CLEAR_FOCUS";
1970             case ACTION_SELECT:
1971                 return "ACTION_SELECT";
1972             case ACTION_CLEAR_SELECTION:
1973                 return "ACTION_CLEAR_SELECTION";
1974             case ACTION_CLICK:
1975                 return "ACTION_CLICK";
1976             case ACTION_LONG_CLICK:
1977                 return "ACTION_LONG_CLICK";
1978             case ACTION_ACCESSIBILITY_FOCUS:
1979                 return "ACTION_ACCESSIBILITY_FOCUS";
1980             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
1981                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
1982             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
1983                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
1984             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
1985                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
1986             case ACTION_NEXT_HTML_ELEMENT:
1987                 return "ACTION_NEXT_HTML_ELEMENT";
1988             case ACTION_PREVIOUS_HTML_ELEMENT:
1989                 return "ACTION_PREVIOUS_HTML_ELEMENT";
1990             case ACTION_SCROLL_FORWARD:
1991                 return "ACTION_SCROLL_FORWARD";
1992             case ACTION_SCROLL_BACKWARD:
1993                 return "ACTION_SCROLL_BACKWARD";
1994             case ACTION_CUT:
1995                 return "ACTION_CUT";
1996             case ACTION_COPY:
1997                 return "ACTION_COPY";
1998             case ACTION_PASTE:
1999                 return "ACTION_PASTE";
2000             case ACTION_SET_SELECTION:
2001                 return "ACTION_SET_SELECTION";
2002             default:
2003                 return"ACTION_UNKNOWN";
2004         }
2005     }
2006 
2007     /**
2008      * Gets the human readable movement granularity symbolic name.
2009      *
2010      * @param granularity The granularity.
2011      * @return The symbolic name.
2012      */
getMovementGranularitySymbolicName(int granularity)2013     private static String getMovementGranularitySymbolicName(int granularity) {
2014         switch (granularity) {
2015             case MOVEMENT_GRANULARITY_CHARACTER:
2016                 return "MOVEMENT_GRANULARITY_CHARACTER";
2017             case MOVEMENT_GRANULARITY_WORD:
2018                 return "MOVEMENT_GRANULARITY_WORD";
2019             case MOVEMENT_GRANULARITY_LINE:
2020                 return "MOVEMENT_GRANULARITY_LINE";
2021             case MOVEMENT_GRANULARITY_PARAGRAPH:
2022                 return "MOVEMENT_GRANULARITY_PARAGRAPH";
2023             case MOVEMENT_GRANULARITY_PAGE:
2024                 return "MOVEMENT_GRANULARITY_PAGE";
2025             default:
2026                 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
2027         }
2028     }
2029 
canPerformRequestOverConnection(long accessibilityNodeId)2030     private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
2031         return (mWindowId != UNDEFINED
2032                 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED
2033                 && mConnectionId != UNDEFINED);
2034     }
2035 
2036     @Override
equals(Object object)2037     public boolean equals(Object object) {
2038         if (this == object) {
2039             return true;
2040         }
2041         if (object == null) {
2042             return false;
2043         }
2044         if (getClass() != object.getClass()) {
2045             return false;
2046         }
2047         AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
2048         if (mSourceNodeId != other.mSourceNodeId) {
2049             return false;
2050         }
2051         if (mWindowId != other.mWindowId) {
2052             return false;
2053         }
2054         return true;
2055     }
2056 
2057     @Override
hashCode()2058     public int hashCode() {
2059         final int prime = 31;
2060         int result = 1;
2061         result = prime * result + getAccessibilityViewId(mSourceNodeId);
2062         result = prime * result + getVirtualDescendantId(mSourceNodeId);
2063         result = prime * result + mWindowId;
2064         return result;
2065     }
2066 
2067     @Override
toString()2068     public String toString() {
2069         StringBuilder builder = new StringBuilder();
2070         builder.append(super.toString());
2071 
2072         if (DEBUG) {
2073             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
2074             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
2075             builder.append("; mParentNodeId: " + mParentNodeId);
2076 
2077             int granularities = mMovementGranularities;
2078             builder.append("; MovementGranularities: [");
2079             while (granularities != 0) {
2080                 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
2081                 granularities &= ~granularity;
2082                 builder.append(getMovementGranularitySymbolicName(granularity));
2083                 if (granularities != 0) {
2084                     builder.append(", ");
2085                 }
2086             }
2087             builder.append("]");
2088 
2089             SparseLongArray childIds = mChildNodeIds;
2090             builder.append("; childAccessibilityIds: [");
2091             for (int i = 0, count = childIds.size(); i < count; i++) {
2092                 builder.append(childIds.valueAt(i));
2093                 if (i < count - 1) {
2094                     builder.append(", ");
2095                 }
2096             }
2097             builder.append("]");
2098         }
2099 
2100         builder.append("; boundsInParent: " + mBoundsInParent);
2101         builder.append("; boundsInScreen: " + mBoundsInScreen);
2102 
2103         builder.append("; packageName: ").append(mPackageName);
2104         builder.append("; className: ").append(mClassName);
2105         builder.append("; text: ").append(mText);
2106         builder.append("; contentDescription: ").append(mContentDescription);
2107         builder.append("; viewIdResName: ").append(mViewIdResourceName);
2108 
2109         builder.append("; checkable: ").append(isCheckable());
2110         builder.append("; checked: ").append(isChecked());
2111         builder.append("; focusable: ").append(isFocusable());
2112         builder.append("; focused: ").append(isFocused());
2113         builder.append("; selected: ").append(isSelected());
2114         builder.append("; clickable: ").append(isClickable());
2115         builder.append("; longClickable: ").append(isLongClickable());
2116         builder.append("; enabled: ").append(isEnabled());
2117         builder.append("; password: ").append(isPassword());
2118         builder.append("; scrollable: " + isScrollable());
2119 
2120         builder.append("; [");
2121         for (int actionBits = mActions; actionBits != 0;) {
2122             final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
2123             actionBits &= ~action;
2124             builder.append(getActionSymbolicName(action));
2125             if (actionBits != 0) {
2126                 builder.append(", ");
2127             }
2128         }
2129         builder.append("]");
2130 
2131         return builder.toString();
2132     }
2133 
2134     /**
2135      * @see Parcelable.Creator
2136      */
2137     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
2138             new Parcelable.Creator<AccessibilityNodeInfo>() {
2139         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
2140             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2141             info.initFromParcel(parcel);
2142             return info;
2143         }
2144 
2145         public AccessibilityNodeInfo[] newArray(int size) {
2146             return new AccessibilityNodeInfo[size];
2147         }
2148     };
2149 }
2150