blob: c0696a91115d3b16df7742ade531d15c978c925e [file] [log] [blame]
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001/*
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
17package android.view.accessibility;
18
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070019import android.graphics.Rect;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -070020import android.os.Bundle;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070021import android.os.Parcel;
22import android.os.Parcelable;
Svetoslav Ganov02107852011-10-03 17:06:56 -070023import android.util.SparseLongArray;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070024import android.view.View;
25
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070026import java.util.Collections;
27import java.util.List;
28
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070029/**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070030 * This class represents a node of the window content as well as actions that
31 * can be requested from its source. From the point of view of an
32 * {@link android.accessibilityservice.AccessibilityService} a window content is
33 * presented as tree of accessibility node info which may or may not map one-to-one
34 * to the view hierarchy. In other words, a custom view is free to report itself as
35 * a tree of accessibility node info.
36 * </p>
37 * <p>
38 * Once an accessibility node info is delivered to an accessibility service it is
39 * made immutable and calling a state mutation method generates an error.
40 * </p>
41 * <p>
42 * Please refer to {@link android.accessibilityservice.AccessibilityService} for
43 * details about how to obtain a handle to window content as a tree of accessibility
44 * node info as well as familiarizing with the security model.
45 * </p>
Joe Fernandeze1302ed2012-02-06 14:30:15 -080046 * <div class="special reference">
47 * <h3>Developer Guides</h3>
48 * <p>For more information about making applications accessible, read the
49 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
50 * developer guide.</p>
51 * </div>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070052 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070053 * @see android.accessibilityservice.AccessibilityService
54 * @see AccessibilityEvent
55 * @see AccessibilityManager
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070056 */
57public class AccessibilityNodeInfo implements Parcelable {
58
59 private static final boolean DEBUG = false;
60
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080061 /** @hide */
62 public static final int UNDEFINED = -1;
63
64 /** @hide */
65 public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
66
67 /** @hide */
68 public static final int ACTIVE_WINDOW_ID = UNDEFINED;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080069
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -080070 /** @hide */
71 public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
72
73 /** @hide */
74 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
75
76 /** @hide */
Svetoslav Ganov42138042012-03-20 11:51:39 -070077 public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
78
79 /** @hide */
80 public static final int INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -080081
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070082 // Actions.
83
84 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -070085 * Action that gives input focus to the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070086 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -070087 public static final int ACTION_FOCUS = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070088
89 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -070090 * Action that clears input focus of the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070091 */
Svetoslav Ganov42138042012-03-20 11:51:39 -070092 public static final int ACTION_CLEAR_FOCUS = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070093
94 /**
95 * Action that selects the node.
96 */
Svetoslav Ganov42138042012-03-20 11:51:39 -070097 public static final int ACTION_SELECT = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070098
99 /**
100 * Action that unselects the node.
101 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700102 public static final int ACTION_CLEAR_SELECTION = 0x00000008;
103
104 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700105 * Action that long clicks on the node info.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700106 */
107 public static final int ACTION_CLICK = 0x00000010;
108
109 /**
110 * Action that clicks on the node.
111 */
112 public static final int ACTION_LONG_CLICK = 0x00000020;
113
114 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700115 * Action that gives accessibility focus to the node.
116 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700117 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700118
119 /**
120 * Action that clears accessibility focus of the node.
121 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700122 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700123
124 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700125 * Action that requests to go to the next entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700126 * at a given movement granularity. For example, move to the next character,
127 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700128 * <p>
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700129 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<br>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700130 * <strong>Example:</strong>
131 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700132 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700133 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
134 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
135 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700136 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700137 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700138 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700139 * @see #setMovementGranularities(int)
140 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700141 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700142 * @see #MOVEMENT_GRANULARITY_CHARACTER
143 * @see #MOVEMENT_GRANULARITY_WORD
144 * @see #MOVEMENT_GRANULARITY_LINE
145 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
146 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700147 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700148 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700149
150 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700151 * Action that requests to go to the previous entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700152 * at a given movement granularity. For example, move to the next character,
153 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700154 * <p>
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700155 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<br>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700156 * <strong>Example:</strong>
157 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700158 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700159 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
160 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
161 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
162 * arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700163 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700164 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700165 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700166 * @see #setMovementGranularities(int)
167 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700168 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700169 * @see #MOVEMENT_GRANULARITY_CHARACTER
170 * @see #MOVEMENT_GRANULARITY_WORD
171 * @see #MOVEMENT_GRANULARITY_LINE
172 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
173 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700174 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700175 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700176
177 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700178 * Action to move to the next HTML element of a given type. For example, move
179 * to the BUTTON, INPUT, TABLE, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700180 * <p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700181 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
182 * <strong>Example:</strong>
183 * <code><pre><p>
184 * Bundle arguments = new Bundle();
185 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
186 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
187 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700188 * </p>
189 */
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700190 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
191
192 /**
193 * Action to move to the previous HTML element of a given type. For example, move
194 * to the BUTTON, INPUT, TABLE, etc.
195 * <p>
196 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
197 * <strong>Example:</strong>
198 * <code><pre><p>
199 * Bundle arguments = new Bundle();
200 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
201 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
202 * </code></pre></p>
203 * </p>
204 */
205 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
206
207 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700208 * Argument for which movement granularity to be used when traversing the node text.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700209 * <p>
210 * <strong>Type:</strong> int<br>
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700211 * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
212 * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700213 * </p>
214 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700215 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
216 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700217
218 /**
219 * Argument for which HTML element to get moving to the next/previous HTML element.
220 * <p>
221 * <strong>Type:</strong> String<br>
222 * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
223 * {@link #ACTION_PREVIOUS_HTML_ELEMENT}
224 * </p>
225 */
226 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
227 "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700228
229 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700230 * The input focus.
231 */
232 public static final int FOCUS_INPUT = 1;
233
234 /**
235 * The accessibility focus.
236 */
237 public static final int FOCUS_ACCESSIBILITY = 2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700238
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700239 // Movement granularities
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700240
241 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700242 * Movement granularity bit for traversing the text of a node by character.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700243 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700244 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700245
246 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700247 * Movement granularity bit for traversing the text of a node by word.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700248 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700249 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700250
251 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700252 * Movement granularity bit for traversing the text of a node by line.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700253 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700254 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700255
256 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700257 * Movement granularity bit for traversing the text of a node by paragraph.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700258 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700259 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700260
261 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700262 * Movement granularity bit for traversing the text of a node by page.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700263 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700264 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700265
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700266 // Boolean attributes.
267
268 private static final int PROPERTY_CHECKABLE = 0x00000001;
269
270 private static final int PROPERTY_CHECKED = 0x00000002;
271
272 private static final int PROPERTY_FOCUSABLE = 0x00000004;
273
274 private static final int PROPERTY_FOCUSED = 0x00000008;
275
276 private static final int PROPERTY_SELECTED = 0x00000010;
277
278 private static final int PROPERTY_CLICKABLE = 0x00000020;
279
280 private static final int PROPERTY_LONG_CLICKABLE = 0x00000040;
281
282 private static final int PROPERTY_ENABLED = 0x00000080;
283
284 private static final int PROPERTY_PASSWORD = 0x00000100;
285
Svetoslav Ganova0156172011-06-26 17:55:44 -0700286 private static final int PROPERTY_SCROLLABLE = 0x00000200;
287
Svetoslav Ganov42138042012-03-20 11:51:39 -0700288 private static final int PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
289
Svetoslav Ganov02107852011-10-03 17:06:56 -0700290 /**
291 * Bits that provide the id of a virtual descendant of a view.
292 */
293 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
294
295 /**
296 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
297 * virtual descendant of a view. Such a descendant does not exist in the view
298 * hierarchy and is only reported via the accessibility APIs.
299 */
300 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
301
302 /**
303 * Gets the accessibility view id which identifies a View in the view three.
304 *
305 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
306 * @return The accessibility view id part of the node id.
307 *
308 * @hide
309 */
310 public static int getAccessibilityViewId(long accessibilityNodeId) {
311 return (int) accessibilityNodeId;
312 }
313
314 /**
315 * Gets the virtual descendant id which identifies an imaginary view in a
316 * containing View.
317 *
318 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
319 * @return The virtual view id part of the node id.
320 *
321 * @hide
322 */
323 public static int getVirtualDescendantId(long accessibilityNodeId) {
324 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
325 >> VIRTUAL_DESCENDANT_ID_SHIFT);
326 }
327
328 /**
329 * Makes a node id by shifting the <code>virtualDescendantId</code>
330 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
331 * the bitwise or with the <code>accessibilityViewId</code>.
332 *
333 * @param accessibilityViewId A View accessibility id.
334 * @param virtualDescendantId A virtual descendant id.
335 * @return The node id.
336 *
337 * @hide
338 */
339 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
340 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
341 }
342
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700343 // Housekeeping.
344 private static final int MAX_POOL_SIZE = 50;
345 private static final Object sPoolLock = new Object();
346 private static AccessibilityNodeInfo sPool;
347 private static int sPoolSize;
348 private AccessibilityNodeInfo mNext;
349 private boolean mIsInPool;
350 private boolean mSealed;
351
352 // Data.
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800353 private int mWindowId = UNDEFINED;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -0800354 private long mSourceNodeId = ROOT_NODE_ID;
355 private long mParentNodeId = ROOT_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800356
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700357 private int mBooleanProperties;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700358 private final Rect mBoundsInParent = new Rect();
359 private final Rect mBoundsInScreen = new Rect();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700360
361 private CharSequence mPackageName;
362 private CharSequence mClassName;
363 private CharSequence mText;
364 private CharSequence mContentDescription;
365
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700366 private final SparseLongArray mChildNodeIds = new SparseLongArray();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700367 private int mActions;
368
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700369 private int mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700370
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800371 private int mConnectionId = UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700372
373 /**
374 * Hide constructor from clients.
375 */
376 private AccessibilityNodeInfo() {
377 /* do nothing */
378 }
379
380 /**
381 * Sets the source.
Svetoslav Ganov02107852011-10-03 17:06:56 -0700382 * <p>
383 * <strong>Note:</strong> Cannot be called from an
384 * {@link android.accessibilityservice.AccessibilityService}.
385 * This class is made immutable before being delivered to an AccessibilityService.
386 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700387 *
388 * @param source The info source.
389 */
390 public void setSource(View source) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800391 setSource(source, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700392 }
393
394 /**
395 * Sets the source to be a virtual descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700396 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700397 * is set as the source.
398 * <p>
399 * A virtual descendant is an imaginary View that is reported as a part of the view
400 * hierarchy for accessibility purposes. This enables custom views that draw complex
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700401 * content to report themselves as a tree of virtual views, thus conveying their
Svetoslav Ganov02107852011-10-03 17:06:56 -0700402 * logical structure.
403 * </p>
404 * <p>
405 * <strong>Note:</strong> Cannot be called from an
406 * {@link android.accessibilityservice.AccessibilityService}.
407 * This class is made immutable before being delivered to an AccessibilityService.
408 * </p>
409 *
410 * @param root The root of the virtual subtree.
411 * @param virtualDescendantId The id of the virtual descendant.
412 */
413 public void setSource(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700414 enforceNotSealed();
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800415 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700416 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800417 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700418 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700419 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700420
Svetoslav Ganov42138042012-03-20 11:51:39 -0700421 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700422 * Find the view that has the specified focus type. The search starts from
Svetoslav Ganov42138042012-03-20 11:51:39 -0700423 * the view represented by this node info.
424 *
425 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
426 * {@link #FOCUS_ACCESSIBILITY}.
427 * @return The node info of the focused view or null.
428 *
429 * @see #FOCUS_INPUT
430 * @see #FOCUS_ACCESSIBILITY
431 */
432 public AccessibilityNodeInfo findFocus(int focus) {
433 enforceSealed();
434 if (!canPerformRequestOverConnection(mSourceNodeId)) {
435 return null;
436 }
437 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
438 mSourceNodeId, focus);
439 }
440
441 /**
442 * Searches for the nearest view in the specified direction that can take
443 * the input focus.
444 *
445 * @param direction The direction. Can be one of:
446 * {@link View#FOCUS_DOWN},
447 * {@link View#FOCUS_UP},
448 * {@link View#FOCUS_LEFT},
449 * {@link View#FOCUS_RIGHT},
450 * {@link View#FOCUS_FORWARD},
451 * {@link View#FOCUS_BACKWARD},
Svetoslav Ganov42138042012-03-20 11:51:39 -0700452 * {@link View#ACCESSIBILITY_FOCUS_FORWARD},
453 * {@link View#ACCESSIBILITY_FOCUS_BACKWARD},
454 * {@link View#ACCESSIBILITY_FOCUS_UP},
455 * {@link View#ACCESSIBILITY_FOCUS_RIGHT},
456 * {@link View#ACCESSIBILITY_FOCUS_DOWN},
457 * {@link View#ACCESSIBILITY_FOCUS_LEFT}.
458 *
459 * @return The node info for the view that can take accessibility focus.
460 */
461 public AccessibilityNodeInfo focusSearch(int direction) {
462 enforceSealed();
463 if (!canPerformRequestOverConnection(mSourceNodeId)) {
464 return null;
465 }
466 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
467 mSourceNodeId, direction);
468 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700469
470 /**
471 * Gets the id of the window from which the info comes from.
472 *
473 * @return The window id.
474 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700475 public int getWindowId() {
Svetoslav Ganov02107852011-10-03 17:06:56 -0700476 return mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700477 }
478
479 /**
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800480 * @return The ids of the children.
481 *
482 * @hide
483 */
484 public SparseLongArray getChildNodeIds() {
485 return mChildNodeIds;
486 }
487
488 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700489 * Gets the number of children.
490 *
491 * @return The child count.
492 */
493 public int getChildCount() {
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800494 return mChildNodeIds.size();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700495 }
496
497 /**
498 * Get the child at given index.
499 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700500 * <strong>Note:</strong> It is a client responsibility to recycle the
501 * received info by calling {@link AccessibilityNodeInfo#recycle()}
502 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700503 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700504 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700505 * @param index The child index.
506 * @return The child node.
507 *
508 * @throws IllegalStateException If called outside of an AccessibilityService.
509 *
510 */
511 public AccessibilityNodeInfo getChild(int index) {
512 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700513 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700514 return null;
515 }
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800516 final long childId = mChildNodeIds.get(index);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700517 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800518 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
519 childId, FLAG_PREFETCH_DESCENDANTS);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700520 }
521
522 /**
523 * Adds a child.
524 * <p>
Svetoslav Ganov02107852011-10-03 17:06:56 -0700525 * <strong>Note:</strong> Cannot be called from an
526 * {@link android.accessibilityservice.AccessibilityService}.
527 * This class is made immutable before being delivered to an AccessibilityService.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700528 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700529 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700530 * @param child The child.
531 *
532 * @throws IllegalStateException If called from an AccessibilityService.
533 */
534 public void addChild(View child) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800535 addChild(child, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700536 }
537
538 /**
539 * Adds a virtual child which is a descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700540 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700541 * is added as a child.
542 * <p>
543 * A virtual descendant is an imaginary View that is reported as a part of the view
544 * hierarchy for accessibility purposes. This enables custom views that draw complex
545 * content to report them selves as a tree of virtual views, thus conveying their
546 * logical structure.
547 * </p>
548 *
549 * @param root The root of the virtual subtree.
550 * @param virtualDescendantId The id of the virtual child.
551 */
552 public void addChild(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700553 enforceNotSealed();
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800554 final int index = mChildNodeIds.size();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700555 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800556 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700557 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800558 mChildNodeIds.put(index, childNodeId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700559 }
560
561 /**
562 * Gets the actions that can be performed on the node.
563 *
564 * @return The bit mask of with actions.
565 *
566 * @see AccessibilityNodeInfo#ACTION_FOCUS
567 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
568 * @see AccessibilityNodeInfo#ACTION_SELECT
569 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
570 */
571 public int getActions() {
572 return mActions;
573 }
574
575 /**
576 * Adds an action that can be performed on the node.
577 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700578 * <strong>Note:</strong> Cannot be called from an
579 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700580 * This class is made immutable before being delivered to an AccessibilityService.
581 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700582 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700583 * @param action The action.
584 *
585 * @throws IllegalStateException If called from an AccessibilityService.
586 */
587 public void addAction(int action) {
588 enforceNotSealed();
589 mActions |= action;
590 }
591
592 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700593 * Sets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700594 * <p>
595 * <strong>Note:</strong> Cannot be called from an
596 * {@link android.accessibilityservice.AccessibilityService}.
597 * This class is made immutable before being delivered to an AccessibilityService.
598 * </p>
599 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700600 * @param granularities The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700601 *
602 * @throws IllegalStateException If called from an AccessibilityService.
603 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700604 public void setMovementGranularities(int granularities) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700605 enforceNotSealed();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700606 mMovementGranularities = granularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700607 }
608
609 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700610 * Gets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700611 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700612 * @return The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700613 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700614 public int getMovementGranularities() {
615 return mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700616 }
617
618 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700619 * Performs an action on the node.
620 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700621 * <strong>Note:</strong> An action can be performed only if the request is made
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700622 * from an {@link android.accessibilityservice.AccessibilityService}.
623 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700624 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700625 * @param action The action to perform.
626 * @return True if the action was performed.
627 *
628 * @throws IllegalStateException If called outside of an AccessibilityService.
629 */
630 public boolean performAction(int action) {
631 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700632 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700633 return false;
634 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700635 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700636 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
637 action, null);
638 }
639
640 /**
641 * Performs an action on the node.
642 * <p>
643 * <strong>Note:</strong> An action can be performed only if the request is made
644 * from an {@link android.accessibilityservice.AccessibilityService}.
645 * </p>
646 *
647 * @param action The action to perform.
648 * @param arguments A bundle with additional arguments.
649 * @return True if the action was performed.
650 *
651 * @throws IllegalStateException If called outside of an AccessibilityService.
652 */
653 public boolean performAction(int action, Bundle arguments) {
654 enforceSealed();
655 if (!canPerformRequestOverConnection(mSourceNodeId)) {
656 return false;
657 }
658 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
659 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
660 action, arguments);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700661 }
662
663 /**
664 * Finds {@link AccessibilityNodeInfo}s by text. The match is case
Svetoslav Ganov86398bd2011-06-21 17:38:43 -0700665 * insensitive containment. The search is relative to this info i.e.
666 * this info is the root of the traversed tree.
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700667 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700668 * <p>
669 * <strong>Note:</strong> It is a client responsibility to recycle the
670 * received info by calling {@link AccessibilityNodeInfo#recycle()}
671 * to avoid creating of multiple instances.
672 * </p>
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700673 *
674 * @param text The searched text.
675 * @return A list of node info.
676 */
677 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
678 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700679 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganov86398bd2011-06-21 17:38:43 -0700680 return Collections.emptyList();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700681 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700682 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800683 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
684 text);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700685 }
686
687 /**
Svetoslav Ganov00aabf72011-07-21 11:35:03 -0700688 * Gets the parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700689 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700690 * <strong>Note:</strong> It is a client responsibility to recycle the
691 * received info by calling {@link AccessibilityNodeInfo#recycle()}
692 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700693 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700694 *
Svetoslav Ganov00aabf72011-07-21 11:35:03 -0700695 * @return The parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700696 */
697 public AccessibilityNodeInfo getParent() {
698 enforceSealed();
Svetoslav Ganovaf0d9842011-10-26 15:29:26 -0700699 if (!canPerformRequestOverConnection(mParentNodeId)) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700700 return null;
701 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700702 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800703 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800704 mWindowId, mParentNodeId, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
705 }
706
707 /**
708 * @return The parent node id.
709 *
710 * @hide
711 */
712 public long getParentNodeId() {
713 return mParentNodeId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700714 }
715
716 /**
717 * Sets the parent.
718 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700719 * <strong>Note:</strong> Cannot be called from an
720 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700721 * This class is made immutable before being delivered to an AccessibilityService.
722 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700723 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700724 * @param parent The parent.
725 *
726 * @throws IllegalStateException If called from an AccessibilityService.
727 */
728 public void setParent(View parent) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800729 setParent(parent, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700730 }
731
732 /**
733 * Sets the parent to be a virtual descendant of the given <code>root</code>.
734 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
735 * is set as the parent.
736 * <p>
737 * A virtual descendant is an imaginary View that is reported as a part of the view
738 * hierarchy for accessibility purposes. This enables custom views that draw complex
739 * content to report them selves as a tree of virtual views, thus conveying their
740 * logical structure.
741 * </p>
742 * <p>
743 * <strong>Note:</strong> Cannot be called from an
744 * {@link android.accessibilityservice.AccessibilityService}.
745 * This class is made immutable before being delivered to an AccessibilityService.
746 * </p>
747 *
748 * @param root The root of the virtual subtree.
749 * @param virtualDescendantId The id of the virtual descendant.
750 */
751 public void setParent(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700752 enforceNotSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700753 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800754 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700755 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700756 }
757
758 /**
759 * Gets the node bounds in parent coordinates.
760 *
761 * @param outBounds The output node bounds.
762 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700763 public void getBoundsInParent(Rect outBounds) {
764 outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
765 mBoundsInParent.right, mBoundsInParent.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700766 }
767
768 /**
769 * Sets the node bounds in parent coordinates.
770 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700771 * <strong>Note:</strong> Cannot be called from an
772 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700773 * This class is made immutable before being delivered to an AccessibilityService.
774 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700775 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700776 * @param bounds The node bounds.
777 *
778 * @throws IllegalStateException If called from an AccessibilityService.
779 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700780 public void setBoundsInParent(Rect bounds) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700781 enforceNotSealed();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700782 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
783 }
784
785 /**
786 * Gets the node bounds in screen coordinates.
787 *
788 * @param outBounds The output node bounds.
789 */
790 public void getBoundsInScreen(Rect outBounds) {
791 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
792 mBoundsInScreen.right, mBoundsInScreen.bottom);
793 }
794
795 /**
796 * Sets the node bounds in screen coordinates.
797 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700798 * <strong>Note:</strong> Cannot be called from an
799 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700800 * This class is made immutable before being delivered to an AccessibilityService.
801 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700802 *
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700803 * @param bounds The node bounds.
804 *
805 * @throws IllegalStateException If called from an AccessibilityService.
806 */
807 public void setBoundsInScreen(Rect bounds) {
808 enforceNotSealed();
809 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700810 }
811
812 /**
813 * Gets whether this node is checkable.
814 *
815 * @return True if the node is checkable.
816 */
817 public boolean isCheckable() {
818 return getBooleanProperty(PROPERTY_CHECKABLE);
819 }
820
821 /**
822 * Sets whether this node is checkable.
823 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700824 * <strong>Note:</strong> Cannot be called from an
825 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700826 * This class is made immutable before being delivered to an AccessibilityService.
827 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700828 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700829 * @param checkable True if the node is checkable.
830 *
831 * @throws IllegalStateException If called from an AccessibilityService.
832 */
833 public void setCheckable(boolean checkable) {
834 setBooleanProperty(PROPERTY_CHECKABLE, checkable);
835 }
836
837 /**
838 * Gets whether this node is checked.
839 *
840 * @return True if the node is checked.
841 */
842 public boolean isChecked() {
843 return getBooleanProperty(PROPERTY_CHECKED);
844 }
845
846 /**
847 * Sets whether this node is checked.
848 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700849 * <strong>Note:</strong> Cannot be called from an
850 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700851 * This class is made immutable before being delivered to an AccessibilityService.
852 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700853 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700854 * @param checked True if the node is checked.
855 *
856 * @throws IllegalStateException If called from an AccessibilityService.
857 */
858 public void setChecked(boolean checked) {
859 setBooleanProperty(PROPERTY_CHECKED, checked);
860 }
861
862 /**
863 * Gets whether this node is focusable.
864 *
865 * @return True if the node is focusable.
866 */
867 public boolean isFocusable() {
868 return getBooleanProperty(PROPERTY_FOCUSABLE);
869 }
870
871 /**
872 * Sets whether this node is focusable.
873 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700874 * <strong>Note:</strong> Cannot be called from an
875 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700876 * This class is made immutable before being delivered to an AccessibilityService.
877 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700878 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700879 * @param focusable True if the node is focusable.
880 *
881 * @throws IllegalStateException If called from an AccessibilityService.
882 */
883 public void setFocusable(boolean focusable) {
884 setBooleanProperty(PROPERTY_FOCUSABLE, focusable);
885 }
886
887 /**
888 * Gets whether this node is focused.
889 *
890 * @return True if the node is focused.
891 */
892 public boolean isFocused() {
893 return getBooleanProperty(PROPERTY_FOCUSED);
894 }
895
896 /**
897 * Sets whether this node is focused.
898 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700899 * <strong>Note:</strong> Cannot be called from an
900 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700901 * This class is made immutable before being delivered to an AccessibilityService.
902 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700903 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700904 * @param focused True if the node is focused.
905 *
906 * @throws IllegalStateException If called from an AccessibilityService.
907 */
908 public void setFocused(boolean focused) {
909 setBooleanProperty(PROPERTY_FOCUSED, focused);
910 }
911
912 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700913 * Gets whether this node is accessibility focused.
914 *
915 * @return True if the node is accessibility focused.
916 */
917 public boolean isAccessibilityFocused() {
918 return getBooleanProperty(PROPERTY_ACCESSIBILITY_FOCUSED);
919 }
920
921 /**
922 * Sets whether this node is accessibility focused.
923 * <p>
924 * <strong>Note:</strong> Cannot be called from an
925 * {@link android.accessibilityservice.AccessibilityService}.
926 * This class is made immutable before being delivered to an AccessibilityService.
927 * </p>
928 *
929 * @param focused True if the node is accessibility focused.
930 *
931 * @throws IllegalStateException If called from an AccessibilityService.
932 */
933 public void setAccessibilityFocused(boolean focused) {
934 setBooleanProperty(PROPERTY_ACCESSIBILITY_FOCUSED, focused);
935 }
936
937 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700938 * Gets whether this node is selected.
939 *
940 * @return True if the node is selected.
941 */
942 public boolean isSelected() {
943 return getBooleanProperty(PROPERTY_SELECTED);
944 }
945
946 /**
947 * Sets whether this node is selected.
948 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700949 * <strong>Note:</strong> Cannot be called from an
950 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700951 * This class is made immutable before being delivered to an AccessibilityService.
952 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700953 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700954 * @param selected True if the node is selected.
955 *
956 * @throws IllegalStateException If called from an AccessibilityService.
957 */
958 public void setSelected(boolean selected) {
959 setBooleanProperty(PROPERTY_SELECTED, selected);
960 }
961
962 /**
963 * Gets whether this node is clickable.
964 *
965 * @return True if the node is clickable.
966 */
967 public boolean isClickable() {
968 return getBooleanProperty(PROPERTY_CLICKABLE);
969 }
970
971 /**
972 * Sets whether this node is clickable.
973 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700974 * <strong>Note:</strong> Cannot be called from an
975 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700976 * This class is made immutable before being delivered to an AccessibilityService.
977 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700978 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700979 * @param clickable True if the node is clickable.
980 *
981 * @throws IllegalStateException If called from an AccessibilityService.
982 */
983 public void setClickable(boolean clickable) {
984 setBooleanProperty(PROPERTY_CLICKABLE, clickable);
985 }
986
987 /**
988 * Gets whether this node is long clickable.
989 *
990 * @return True if the node is long clickable.
991 */
992 public boolean isLongClickable() {
993 return getBooleanProperty(PROPERTY_LONG_CLICKABLE);
994 }
995
996 /**
997 * Sets whether this node is long clickable.
998 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700999 * <strong>Note:</strong> Cannot be called from an
1000 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001001 * This class is made immutable before being delivered to an AccessibilityService.
1002 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001003 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001004 * @param longClickable True if the node is long clickable.
1005 *
1006 * @throws IllegalStateException If called from an AccessibilityService.
1007 */
1008 public void setLongClickable(boolean longClickable) {
1009 setBooleanProperty(PROPERTY_LONG_CLICKABLE, longClickable);
1010 }
1011
1012 /**
1013 * Gets whether this node is enabled.
1014 *
1015 * @return True if the node is enabled.
1016 */
1017 public boolean isEnabled() {
1018 return getBooleanProperty(PROPERTY_ENABLED);
1019 }
1020
1021 /**
1022 * Sets whether this node is enabled.
1023 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001024 * <strong>Note:</strong> Cannot be called from an
1025 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001026 * This class is made immutable before being delivered to an AccessibilityService.
1027 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001028 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001029 * @param enabled True if the node is enabled.
1030 *
1031 * @throws IllegalStateException If called from an AccessibilityService.
1032 */
1033 public void setEnabled(boolean enabled) {
1034 setBooleanProperty(PROPERTY_ENABLED, enabled);
1035 }
1036
1037 /**
1038 * Gets whether this node is a password.
1039 *
1040 * @return True if the node is a password.
1041 */
1042 public boolean isPassword() {
1043 return getBooleanProperty(PROPERTY_PASSWORD);
1044 }
1045
1046 /**
1047 * Sets whether this node is a password.
1048 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001049 * <strong>Note:</strong> Cannot be called from an
1050 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001051 * This class is made immutable before being delivered to an AccessibilityService.
1052 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001053 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001054 * @param password True if the node is a password.
1055 *
1056 * @throws IllegalStateException If called from an AccessibilityService.
1057 */
1058 public void setPassword(boolean password) {
1059 setBooleanProperty(PROPERTY_PASSWORD, password);
1060 }
1061
1062 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -07001063 * Gets if the node is scrollable.
1064 *
1065 * @return True if the node is scrollable, false otherwise.
1066 */
1067 public boolean isScrollable() {
1068 return getBooleanProperty(PROPERTY_SCROLLABLE);
1069 }
1070
1071 /**
1072 * Sets if the node is scrollable.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001073 * <p>
1074 * <strong>Note:</strong> Cannot be called from an
1075 * {@link android.accessibilityservice.AccessibilityService}.
1076 * This class is made immutable before being delivered to an AccessibilityService.
1077 * </p>
Svetoslav Ganova0156172011-06-26 17:55:44 -07001078 *
1079 * @param scrollable True if the node is scrollable, false otherwise.
1080 *
1081 * @throws IllegalStateException If called from an AccessibilityService.
1082 */
1083 public void setScrollable(boolean scrollable) {
1084 enforceNotSealed();
1085 setBooleanProperty(PROPERTY_SCROLLABLE, scrollable);
1086 }
1087
1088 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001089 * Gets the package this node comes from.
1090 *
1091 * @return The package name.
1092 */
1093 public CharSequence getPackageName() {
1094 return mPackageName;
1095 }
1096
1097 /**
1098 * Sets the package this node comes from.
1099 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001100 * <strong>Note:</strong> Cannot be called from an
1101 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001102 * This class is made immutable before being delivered to an AccessibilityService.
1103 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001104 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001105 * @param packageName The package name.
1106 *
1107 * @throws IllegalStateException If called from an AccessibilityService.
1108 */
1109 public void setPackageName(CharSequence packageName) {
1110 enforceNotSealed();
1111 mPackageName = packageName;
1112 }
1113
1114 /**
1115 * Gets the class this node comes from.
1116 *
1117 * @return The class name.
1118 */
1119 public CharSequence getClassName() {
1120 return mClassName;
1121 }
1122
1123 /**
1124 * Sets the class this node comes from.
1125 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001126 * <strong>Note:</strong> Cannot be called from an
1127 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001128 * This class is made immutable before being delivered to an AccessibilityService.
1129 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001130 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001131 * @param className The class name.
1132 *
1133 * @throws IllegalStateException If called from an AccessibilityService.
1134 */
1135 public void setClassName(CharSequence className) {
1136 enforceNotSealed();
1137 mClassName = className;
1138 }
1139
1140 /**
1141 * Gets the text of this node.
1142 *
1143 * @return The text.
1144 */
1145 public CharSequence getText() {
1146 return mText;
1147 }
1148
1149 /**
1150 * Sets the text of this node.
1151 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001152 * <strong>Note:</strong> Cannot be called from an
1153 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001154 * This class is made immutable before being delivered to an AccessibilityService.
1155 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001156 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001157 * @param text The text.
1158 *
1159 * @throws IllegalStateException If called from an AccessibilityService.
1160 */
1161 public void setText(CharSequence text) {
1162 enforceNotSealed();
1163 mText = text;
1164 }
1165
1166 /**
1167 * Gets the content description of this node.
1168 *
1169 * @return The content description.
1170 */
1171 public CharSequence getContentDescription() {
1172 return mContentDescription;
1173 }
1174
1175 /**
1176 * Sets the content description of this node.
1177 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001178 * <strong>Note:</strong> Cannot be called from an
1179 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001180 * This class is made immutable before being delivered to an AccessibilityService.
1181 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001182 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001183 * @param contentDescription The content description.
1184 *
1185 * @throws IllegalStateException If called from an AccessibilityService.
1186 */
1187 public void setContentDescription(CharSequence contentDescription) {
1188 enforceNotSealed();
1189 mContentDescription = contentDescription;
1190 }
1191
1192 /**
1193 * Gets the value of a boolean property.
1194 *
1195 * @param property The property.
1196 * @return The value.
1197 */
1198 private boolean getBooleanProperty(int property) {
1199 return (mBooleanProperties & property) != 0;
1200 }
1201
1202 /**
1203 * Sets a boolean property.
1204 *
1205 * @param property The property.
1206 * @param value The value.
1207 *
1208 * @throws IllegalStateException If called from an AccessibilityService.
1209 */
1210 private void setBooleanProperty(int property, boolean value) {
1211 enforceNotSealed();
1212 if (value) {
1213 mBooleanProperties |= property;
1214 } else {
1215 mBooleanProperties &= ~property;
1216 }
1217 }
1218
1219 /**
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001220 * Sets the unique id of the IAccessibilityServiceConnection over which
1221 * this instance can send requests to the system.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001222 *
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001223 * @param connectionId The connection id.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001224 *
1225 * @hide
1226 */
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001227 public void setConnectionId(int connectionId) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001228 enforceNotSealed();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001229 mConnectionId = connectionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001230 }
1231
1232 /**
1233 * {@inheritDoc}
1234 */
1235 public int describeContents() {
1236 return 0;
1237 }
1238
1239 /**
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001240 * Gets the id of the source node.
1241 *
1242 * @return The id.
1243 *
1244 * @hide
1245 */
1246 public long getSourceNodeId() {
1247 return mSourceNodeId;
1248 }
1249
1250 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001251 * Sets if this instance is sealed.
1252 *
1253 * @param sealed Whether is sealed.
1254 *
1255 * @hide
1256 */
1257 public void setSealed(boolean sealed) {
1258 mSealed = sealed;
1259 }
1260
1261 /**
1262 * Gets if this instance is sealed.
1263 *
1264 * @return Whether is sealed.
1265 *
1266 * @hide
1267 */
1268 public boolean isSealed() {
1269 return mSealed;
1270 }
1271
1272 /**
1273 * Enforces that this instance is sealed.
1274 *
1275 * @throws IllegalStateException If this instance is not sealed.
1276 *
1277 * @hide
1278 */
1279 protected void enforceSealed() {
1280 if (!isSealed()) {
1281 throw new IllegalStateException("Cannot perform this "
1282 + "action on a not sealed instance.");
1283 }
1284 }
1285
1286 /**
1287 * Enforces that this instance is not sealed.
1288 *
1289 * @throws IllegalStateException If this instance is sealed.
1290 *
1291 * @hide
1292 */
1293 protected void enforceNotSealed() {
1294 if (isSealed()) {
1295 throw new IllegalStateException("Cannot perform this "
Ken Wakasaf76a50c2012-03-09 19:56:35 +09001296 + "action on a sealed instance.");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001297 }
1298 }
1299
1300 /**
1301 * Returns a cached instance if such is available otherwise a new one
1302 * and sets the source.
1303 *
Svetoslav Ganov02107852011-10-03 17:06:56 -07001304 * @param source The source view.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001305 * @return An instance.
1306 *
1307 * @see #setSource(View)
1308 */
1309 public static AccessibilityNodeInfo obtain(View source) {
1310 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
1311 info.setSource(source);
1312 return info;
1313 }
1314
1315 /**
Svetoslav Ganov02107852011-10-03 17:06:56 -07001316 * Returns a cached instance if such is available otherwise a new one
1317 * and sets the source.
1318 *
1319 * @param root The root of the virtual subtree.
1320 * @param virtualDescendantId The id of the virtual descendant.
1321 * @return An instance.
1322 *
1323 * @see #setSource(View, int)
1324 */
1325 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
1326 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
1327 info.setSource(root, virtualDescendantId);
1328 return info;
1329 }
1330
1331 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001332 * Returns a cached instance if such is available otherwise a new one.
1333 *
1334 * @return An instance.
1335 */
1336 public static AccessibilityNodeInfo obtain() {
1337 synchronized (sPoolLock) {
1338 if (sPool != null) {
1339 AccessibilityNodeInfo info = sPool;
1340 sPool = sPool.mNext;
1341 sPoolSize--;
1342 info.mNext = null;
1343 info.mIsInPool = false;
Svetoslav Ganov9210ccb2011-06-08 19:42:51 -07001344 return info;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001345 }
1346 return new AccessibilityNodeInfo();
1347 }
1348 }
1349
1350 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07001351 * Returns a cached instance if such is available or a new one is
1352 * create. The returned instance is initialized from the given
1353 * <code>info</code>.
1354 *
1355 * @param info The other info.
1356 * @return An instance.
1357 */
1358 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
1359 AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
1360 infoClone.init(info);
1361 return infoClone;
1362 }
1363
1364 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001365 * Return an instance back to be reused.
1366 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001367 * <strong>Note:</strong> You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001368 *
1369 * @throws IllegalStateException If the info is already recycled.
1370 */
1371 public void recycle() {
1372 if (mIsInPool) {
1373 throw new IllegalStateException("Info already recycled!");
1374 }
1375 clear();
1376 synchronized (sPoolLock) {
1377 if (sPoolSize <= MAX_POOL_SIZE) {
1378 mNext = sPool;
1379 sPool = this;
1380 mIsInPool = true;
1381 sPoolSize++;
1382 }
1383 }
1384 }
1385
1386 /**
1387 * {@inheritDoc}
1388 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001389 * <strong>Note:</strong> After the instance is written to a parcel it
1390 * is recycled. You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001391 * </p>
1392 */
1393 public void writeToParcel(Parcel parcel, int flags) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001394 parcel.writeInt(isSealed() ? 1 : 0);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001395 parcel.writeLong(mSourceNodeId);
1396 parcel.writeInt(mWindowId);
1397 parcel.writeLong(mParentNodeId);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001398 parcel.writeInt(mConnectionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001399
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001400 SparseLongArray childIds = mChildNodeIds;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001401 final int childIdsSize = childIds.size();
1402 parcel.writeInt(childIdsSize);
1403 for (int i = 0; i < childIdsSize; i++) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07001404 parcel.writeLong(childIds.valueAt(i));
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001405 }
1406
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001407 parcel.writeInt(mBoundsInParent.top);
1408 parcel.writeInt(mBoundsInParent.bottom);
1409 parcel.writeInt(mBoundsInParent.left);
1410 parcel.writeInt(mBoundsInParent.right);
1411
1412 parcel.writeInt(mBoundsInScreen.top);
1413 parcel.writeInt(mBoundsInScreen.bottom);
1414 parcel.writeInt(mBoundsInScreen.left);
1415 parcel.writeInt(mBoundsInScreen.right);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001416
1417 parcel.writeInt(mActions);
1418
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001419 parcel.writeInt(mMovementGranularities);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001420
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001421 parcel.writeInt(mBooleanProperties);
1422
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001423 parcel.writeCharSequence(mPackageName);
1424 parcel.writeCharSequence(mClassName);
1425 parcel.writeCharSequence(mText);
1426 parcel.writeCharSequence(mContentDescription);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001427
1428 // Since instances of this class are fetched via synchronous i.e. blocking
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001429 // calls in IPCs we always recycle as soon as the instance is marshaled.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001430 recycle();
1431 }
1432
1433 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07001434 * Initializes this instance from another one.
1435 *
1436 * @param other The other instance.
1437 */
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001438 @SuppressWarnings("unchecked")
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07001439 private void init(AccessibilityNodeInfo other) {
1440 mSealed = other.mSealed;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001441 mSourceNodeId = other.mSourceNodeId;
1442 mParentNodeId = other.mParentNodeId;
1443 mWindowId = other.mWindowId;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001444 mConnectionId = other.mConnectionId;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07001445 mBoundsInParent.set(other.mBoundsInParent);
1446 mBoundsInScreen.set(other.mBoundsInScreen);
1447 mPackageName = other.mPackageName;
1448 mClassName = other.mClassName;
1449 mText = other.mText;
1450 mContentDescription = other.mContentDescription;
1451 mActions= other.mActions;
1452 mBooleanProperties = other.mBooleanProperties;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001453 mMovementGranularities = other.mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001454 final int otherChildIdCount = other.mChildNodeIds.size();
1455 for (int i = 0; i < otherChildIdCount; i++) {
1456 mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
1457 }
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07001458 }
1459
1460 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001461 * Creates a new instance from a {@link Parcel}.
1462 *
1463 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
1464 */
1465 private void initFromParcel(Parcel parcel) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001466 mSealed = (parcel.readInt() == 1);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001467 mSourceNodeId = parcel.readLong();
1468 mWindowId = parcel.readInt();
1469 mParentNodeId = parcel.readLong();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001470 mConnectionId = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001471
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001472 SparseLongArray childIds = mChildNodeIds;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001473 final int childrenSize = parcel.readInt();
1474 for (int i = 0; i < childrenSize; i++) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07001475 final long childId = parcel.readLong();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001476 childIds.put(i, childId);
1477 }
1478
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001479 mBoundsInParent.top = parcel.readInt();
1480 mBoundsInParent.bottom = parcel.readInt();
1481 mBoundsInParent.left = parcel.readInt();
1482 mBoundsInParent.right = parcel.readInt();
1483
1484 mBoundsInScreen.top = parcel.readInt();
1485 mBoundsInScreen.bottom = parcel.readInt();
1486 mBoundsInScreen.left = parcel.readInt();
1487 mBoundsInScreen.right = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001488
1489 mActions = parcel.readInt();
1490
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001491 mMovementGranularities = parcel.readInt();
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001492
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001493 mBooleanProperties = parcel.readInt();
1494
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001495 mPackageName = parcel.readCharSequence();
1496 mClassName = parcel.readCharSequence();
1497 mText = parcel.readCharSequence();
1498 mContentDescription = parcel.readCharSequence();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001499 }
1500
1501 /**
1502 * Clears the state of this instance.
1503 */
1504 private void clear() {
1505 mSealed = false;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08001506 mSourceNodeId = ROOT_NODE_ID;
1507 mParentNodeId = ROOT_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08001508 mWindowId = UNDEFINED;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001509 mConnectionId = UNDEFINED;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001510 mMovementGranularities = 0;
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001511 mChildNodeIds.clear();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001512 mBoundsInParent.set(0, 0, 0, 0);
1513 mBoundsInScreen.set(0, 0, 0, 0);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001514 mBooleanProperties = 0;
1515 mPackageName = null;
1516 mClassName = null;
1517 mText = null;
1518 mContentDescription = null;
1519 mActions = 0;
1520 }
1521
1522 /**
1523 * Gets the human readable action symbolic name.
1524 *
1525 * @param action The action.
1526 * @return The symbolic name.
1527 */
1528 private static String getActionSymbolicName(int action) {
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001529 switch (action) {
1530 case ACTION_FOCUS:
1531 return "ACTION_FOCUS";
1532 case ACTION_CLEAR_FOCUS:
1533 return "ACTION_CLEAR_FOCUS";
1534 case ACTION_SELECT:
1535 return "ACTION_SELECT";
1536 case ACTION_CLEAR_SELECTION:
1537 return "ACTION_CLEAR_SELECTION";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07001538 case ACTION_CLICK:
1539 return "ACTION_CLICK";
1540 case ACTION_LONG_CLICK:
1541 return "ACTION_LONG_CLICK";
1542 case ACTION_ACCESSIBILITY_FOCUS:
1543 return "ACTION_ACCESSIBILITY_FOCUS";
1544 case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
1545 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001546 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
1547 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
1548 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
1549 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07001550 case ACTION_NEXT_HTML_ELEMENT:
1551 return "ACTION_NEXT_HTML_ELEMENT";
1552 case ACTION_PREVIOUS_HTML_ELEMENT:
1553 return "ACTION_PREVIOUS_HTML_ELEMENT";
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001554 default:
1555 throw new IllegalArgumentException("Unknown action: " + action);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001556 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001557 }
1558
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001559 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001560 * Gets the human readable movement granularity symbolic name.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001561 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001562 * @param granularity The granularity.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001563 * @return The symbolic name.
1564 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001565 private static String getMovementGranularitySymbolicName(int granularity) {
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001566 switch (granularity) {
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001567 case MOVEMENT_GRANULARITY_CHARACTER:
1568 return "MOVEMENT_GRANULARITY_CHARACTER";
1569 case MOVEMENT_GRANULARITY_WORD:
1570 return "MOVEMENT_GRANULARITY_WORD";
1571 case MOVEMENT_GRANULARITY_LINE:
1572 return "MOVEMENT_GRANULARITY_LINE";
1573 case MOVEMENT_GRANULARITY_PARAGRAPH:
1574 return "MOVEMENT_GRANULARITY_PARAGRAPH";
1575 case MOVEMENT_GRANULARITY_PAGE:
1576 return "MOVEMENT_GRANULARITY_PAGE";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001577 default:
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001578 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001579 }
1580 }
1581
Svetoslav Ganov02107852011-10-03 17:06:56 -07001582 private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08001583 return (mWindowId != UNDEFINED
1584 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED
1585 && mConnectionId != UNDEFINED);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001586 }
1587
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001588 @Override
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07001589 public boolean equals(Object object) {
1590 if (this == object) {
1591 return true;
1592 }
1593 if (object == null) {
1594 return false;
1595 }
1596 if (getClass() != object.getClass()) {
1597 return false;
1598 }
1599 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001600 if (mSourceNodeId != other.mSourceNodeId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07001601 return false;
1602 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07001603 if (mWindowId != other.mWindowId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07001604 return false;
1605 }
1606 return true;
1607 }
1608
1609 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001610 public int hashCode() {
1611 final int prime = 31;
1612 int result = 1;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001613 result = prime * result + getAccessibilityViewId(mSourceNodeId);
1614 result = prime * result + getVirtualDescendantId(mSourceNodeId);
1615 result = prime * result + mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001616 return result;
1617 }
1618
1619 @Override
1620 public String toString() {
1621 StringBuilder builder = new StringBuilder();
1622 builder.append(super.toString());
1623
1624 if (DEBUG) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07001625 builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
1626 builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
1627 builder.append("; mParentNodeId: " + mParentNodeId);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001628
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001629 int granularities = mMovementGranularities;
1630 builder.append("; MovementGranularities: [");
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001631 while (granularities != 0) {
1632 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
1633 granularities &= ~granularity;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001634 builder.append(getMovementGranularitySymbolicName(granularity));
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001635 if (granularities != 0) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001636 builder.append(", ");
1637 }
1638 }
1639 builder.append("]");
1640
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001641 SparseLongArray childIds = mChildNodeIds;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001642 builder.append("; childAccessibilityIds: [");
1643 for (int i = 0, count = childIds.size(); i < count; i++) {
1644 builder.append(childIds.valueAt(i));
1645 if (i < count - 1) {
1646 builder.append(", ");
1647 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001648 }
1649 builder.append("]");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001650 }
1651
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001652 builder.append("; boundsInParent: " + mBoundsInParent);
1653 builder.append("; boundsInScreen: " + mBoundsInScreen);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001654
1655 builder.append("; packageName: ").append(mPackageName);
1656 builder.append("; className: ").append(mClassName);
1657 builder.append("; text: ").append(mText);
1658 builder.append("; contentDescription: ").append(mContentDescription);
1659
1660 builder.append("; checkable: ").append(isCheckable());
1661 builder.append("; checked: ").append(isChecked());
1662 builder.append("; focusable: ").append(isFocusable());
1663 builder.append("; focused: ").append(isFocused());
1664 builder.append("; selected: ").append(isSelected());
1665 builder.append("; clickable: ").append(isClickable());
1666 builder.append("; longClickable: ").append(isLongClickable());
1667 builder.append("; enabled: ").append(isEnabled());
1668 builder.append("; password: ").append(isPassword());
Svetoslav Ganova0156172011-06-26 17:55:44 -07001669 builder.append("; scrollable: " + isScrollable());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001670
1671 builder.append("; [");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001672 for (int actionBits = mActions; actionBits != 0;) {
1673 final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
1674 actionBits &= ~action;
1675 builder.append(getActionSymbolicName(action));
1676 if (actionBits != 0) {
1677 builder.append(", ");
1678 }
1679 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001680 builder.append("]");
1681
1682 return builder.toString();
1683 }
1684
1685 /**
1686 * @see Parcelable.Creator
1687 */
1688 public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
1689 new Parcelable.Creator<AccessibilityNodeInfo>() {
1690 public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
1691 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
1692 info.initFromParcel(parcel);
1693 return info;
1694 }
1695
1696 public AccessibilityNodeInfo[] newArray(int size) {
1697 return new AccessibilityNodeInfo[size];
1698 }
1699 };
1700}