OSDN Git Service

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