blob: 61aabea57503cbd0c7a44ab562475e5bedad9735 [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 Ganov80943d82013-01-02 10:25:37 -080019import android.accessibilityservice.AccessibilityServiceInfo;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070020import android.graphics.Rect;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -070021import android.os.Bundle;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070022import android.os.Parcel;
23import android.os.Parcelable;
Svetoslav6254f482013-06-04 17:22:14 -070024import android.text.InputType;
Alan Viverettef0aed092013-11-06 15:33:03 -080025import android.util.LongArray;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -080026import android.util.Pools.SynchronizedPool;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070027import android.view.View;
28
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070029import java.util.Collections;
30import java.util.List;
31
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070032/**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070033 * This class represents a node of the window content as well as actions that
34 * can be requested from its source. From the point of view of an
35 * {@link android.accessibilityservice.AccessibilityService} a window content is
36 * presented as tree of accessibility node info which may or may not map one-to-one
37 * to the view hierarchy. In other words, a custom view is free to report itself as
38 * a tree of accessibility node info.
39 * </p>
40 * <p>
41 * Once an accessibility node info is delivered to an accessibility service it is
42 * made immutable and calling a state mutation method generates an error.
43 * </p>
44 * <p>
45 * Please refer to {@link android.accessibilityservice.AccessibilityService} for
46 * details about how to obtain a handle to window content as a tree of accessibility
47 * node info as well as familiarizing with the security model.
48 * </p>
Joe Fernandeze1302ed2012-02-06 14:30:15 -080049 * <div class="special reference">
50 * <h3>Developer Guides</h3>
51 * <p>For more information about making applications accessible, read the
52 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
53 * developer guide.</p>
54 * </div>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070055 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070056 * @see android.accessibilityservice.AccessibilityService
57 * @see AccessibilityEvent
58 * @see AccessibilityManager
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070059 */
60public class AccessibilityNodeInfo implements Parcelable {
61
62 private static final boolean DEBUG = false;
63
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080064 /** @hide */
65 public static final int UNDEFINED = -1;
66
67 /** @hide */
68 public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
69
70 /** @hide */
71 public static final int ACTIVE_WINDOW_ID = UNDEFINED;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -080072
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -080073 /** @hide */
74 public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
75
76 /** @hide */
77 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
78
79 /** @hide */
Svetoslav Ganov42138042012-03-20 11:51:39 -070080 public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
81
82 /** @hide */
Svetoslav Ganov80943d82013-01-02 10:25:37 -080083 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
84
85 /** @hide */
86 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -080087
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070088 // Actions.
89
90 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -070091 * Action that gives input focus to the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070092 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -070093 public static final int ACTION_FOCUS = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070094
95 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -070096 * Action that clears input focus of the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070097 */
Svetoslav Ganov42138042012-03-20 11:51:39 -070098 public static final int ACTION_CLEAR_FOCUS = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070099
100 /**
101 * Action that selects the node.
102 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700103 public static final int ACTION_SELECT = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700104
105 /**
106 * Action that unselects the node.
107 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700108 public static final int ACTION_CLEAR_SELECTION = 0x00000008;
109
110 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700111 * Action that clicks on the node info.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700112 */
113 public static final int ACTION_CLICK = 0x00000010;
114
115 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700116 * Action that long clicks on the node.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700117 */
118 public static final int ACTION_LONG_CLICK = 0x00000020;
119
120 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700121 * Action that gives accessibility focus to the node.
122 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700123 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700124
125 /**
126 * Action that clears accessibility focus of the node.
127 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700128 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700129
130 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700131 * Action that requests to go to the next entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700132 * at a given movement granularity. For example, move to the next character,
133 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700134 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800135 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
136 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
137 * <strong>Example:</strong> Move to the previous character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700138 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700139 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700140 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
141 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800142 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
143 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700144 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700145 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700146 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700147 *
Svetoslav7c512842013-01-30 23:02:08 -0800148 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
149 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
150 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700151 * @see #setMovementGranularities(int)
152 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700153 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700154 * @see #MOVEMENT_GRANULARITY_CHARACTER
155 * @see #MOVEMENT_GRANULARITY_WORD
156 * @see #MOVEMENT_GRANULARITY_LINE
157 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
158 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700159 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700160 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700161
162 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700163 * Action that requests to go to the previous entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700164 * at a given movement granularity. For example, move to the next character,
165 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700166 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800167 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
168 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
169 * <strong>Example:</strong> Move to the next character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700170 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700171 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700172 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
173 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800174 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
175 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700176 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
177 * arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700178 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700179 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700180 *
Svetoslav7c512842013-01-30 23:02:08 -0800181 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
182 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
183 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700184 * @see #setMovementGranularities(int)
185 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700186 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700187 * @see #MOVEMENT_GRANULARITY_CHARACTER
188 * @see #MOVEMENT_GRANULARITY_WORD
189 * @see #MOVEMENT_GRANULARITY_LINE
190 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
191 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700192 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700193 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700194
195 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700196 * Action to move to the next HTML element of a given type. For example, move
197 * to the BUTTON, INPUT, TABLE, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700198 * <p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700199 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
200 * <strong>Example:</strong>
201 * <code><pre><p>
202 * Bundle arguments = new Bundle();
203 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
204 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
205 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700206 * </p>
207 */
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700208 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
209
210 /**
211 * Action to move to the previous HTML element of a given type. For example, move
212 * to the BUTTON, INPUT, TABLE, etc.
213 * <p>
214 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
215 * <strong>Example:</strong>
216 * <code><pre><p>
217 * Bundle arguments = new Bundle();
218 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
219 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
220 * </code></pre></p>
221 * </p>
222 */
223 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
224
225 /**
Svetoslav Ganova1dc7612012-05-10 04:14:53 -0700226 * Action to scroll the node content forward.
227 */
228 public static final int ACTION_SCROLL_FORWARD = 0x00001000;
229
230 /**
231 * Action to scroll the node content backward.
232 */
233 public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
234
235 /**
Svetoslav7c512842013-01-30 23:02:08 -0800236 * Action to copy the current selection to the clipboard.
237 */
238 public static final int ACTION_COPY = 0x00004000;
239
240 /**
241 * Action to paste the current clipboard content.
242 */
243 public static final int ACTION_PASTE = 0x00008000;
244
245 /**
246 * Action to cut the current selection and place it to the clipboard.
247 */
248 public static final int ACTION_CUT = 0x00010000;
249
250 /**
251 * Action to set the selection. Performing this action with no arguments
252 * clears the selection.
253 * <p>
254 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
255 * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
256 * <strong>Example:</strong>
257 * <code><pre><p>
258 * Bundle arguments = new Bundle();
259 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
260 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
261 * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
262 * </code></pre></p>
263 * </p>
264 *
265 * @see #ACTION_ARGUMENT_SELECTION_START_INT
266 * @see #ACTION_ARGUMENT_SELECTION_END_INT
267 */
268 public static final int ACTION_SET_SELECTION = 0x00020000;
269
270 /**
Svetoslav3577a282013-06-06 14:09:10 -0700271 * Action to expand an expandable node.
272 */
273 public static final int ACTION_EXPAND = 0x00040000;
274
275 /**
276 * Action to collapse an expandable node.
277 */
278 public static final int ACTION_COLLAPSE = 0x00080000;
279
280 /**
281 * Action to dismiss a dismissable node.
282 */
283 public static final int ACTION_DISMISS = 0x00100000;
284
285 // Action arguments
286
287 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700288 * Argument for which movement granularity to be used when traversing the node text.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700289 * <p>
290 * <strong>Type:</strong> int<br>
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700291 * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
292 * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700293 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800294 *
295 * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
296 * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700297 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700298 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
Svetoslav7c512842013-01-30 23:02:08 -0800299 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700300
301 /**
302 * Argument for which HTML element to get moving to the next/previous HTML element.
303 * <p>
304 * <strong>Type:</strong> String<br>
305 * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
306 * {@link #ACTION_PREVIOUS_HTML_ELEMENT}
307 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800308 *
309 * @see #ACTION_NEXT_HTML_ELEMENT
310 * @see #ACTION_PREVIOUS_HTML_ELEMENT
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700311 */
312 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
Svetoslav7c512842013-01-30 23:02:08 -0800313 "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
314
315 /**
316 * Argument for whether when moving at granularity to extend the selection
317 * or to move it otherwise.
318 * <p>
319 * <strong>Type:</strong> boolean<br>
320 * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
321 * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
322 * </p>
323 *
324 * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
325 * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
326 */
327 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
328 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
329
330 /**
331 * Argument for specifying the selection start.
332 * <p>
333 * <strong>Type:</strong> int<br>
334 * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
335 * </p>
336 *
337 * @see #ACTION_SET_SELECTION
338 */
339 public static final String ACTION_ARGUMENT_SELECTION_START_INT =
340 "ACTION_ARGUMENT_SELECTION_START_INT";
341
342 /**
343 * Argument for specifying the selection end.
344 * <p>
345 * <strong>Type:</strong> int<br>
346 * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
347 * </p>
348 *
349 * @see #ACTION_SET_SELECTION
350 */
351 public static final String ACTION_ARGUMENT_SELECTION_END_INT =
352 "ACTION_ARGUMENT_SELECTION_END_INT";
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700353
Svetoslav3577a282013-06-06 14:09:10 -0700354 // Focus types
355
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700356 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700357 * The input focus.
358 */
359 public static final int FOCUS_INPUT = 1;
360
361 /**
362 * The accessibility focus.
363 */
364 public static final int FOCUS_ACCESSIBILITY = 2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700365
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700366 // Movement granularities
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700367
368 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700369 * Movement granularity bit for traversing the text of a node by character.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700370 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700371 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700372
373 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700374 * Movement granularity bit for traversing the text of a node by word.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700375 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700376 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700377
378 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700379 * Movement granularity bit for traversing the text of a node by line.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700380 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700381 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700382
383 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700384 * Movement granularity bit for traversing the text of a node by paragraph.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700385 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700386 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700387
388 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700389 * Movement granularity bit for traversing the text of a node by page.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700390 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700391 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700392
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700393 // Boolean attributes.
394
Svetoslavbcc46a02013-02-06 11:56:00 -0800395 private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700396
Svetoslavbcc46a02013-02-06 11:56:00 -0800397 private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700398
Svetoslavbcc46a02013-02-06 11:56:00 -0800399 private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700400
Svetoslavbcc46a02013-02-06 11:56:00 -0800401 private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700402
Svetoslavbcc46a02013-02-06 11:56:00 -0800403 private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700404
Svetoslavbcc46a02013-02-06 11:56:00 -0800405 private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700406
Svetoslavbcc46a02013-02-06 11:56:00 -0800407 private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700408
Svetoslavbcc46a02013-02-06 11:56:00 -0800409 private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700410
Svetoslavbcc46a02013-02-06 11:56:00 -0800411 private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700412
Svetoslavbcc46a02013-02-06 11:56:00 -0800413 private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
Svetoslav Ganova0156172011-06-26 17:55:44 -0700414
Svetoslavbcc46a02013-02-06 11:56:00 -0800415 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700416
Svetoslavbcc46a02013-02-06 11:56:00 -0800417 private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
418
419 private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -0700420
Alan Viverette77e9a282013-09-12 17:16:09 -0700421 private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
Svetoslav3577a282013-06-06 14:09:10 -0700422
Alan Viverette77e9a282013-09-12 17:16:09 -0700423 private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
Svetoslav3577a282013-06-06 14:09:10 -0700424
Alan Viverette77e9a282013-09-12 17:16:09 -0700425 private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
Svetoslav3577a282013-06-06 14:09:10 -0700426
Alan Viverette77e9a282013-09-12 17:16:09 -0700427 private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
Svetoslav3577a282013-06-06 14:09:10 -0700428
Svetoslav Ganov02107852011-10-03 17:06:56 -0700429 /**
430 * Bits that provide the id of a virtual descendant of a view.
431 */
432 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
433
434 /**
435 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
436 * virtual descendant of a view. Such a descendant does not exist in the view
437 * hierarchy and is only reported via the accessibility APIs.
438 */
439 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
440
441 /**
442 * Gets the accessibility view id which identifies a View in the view three.
443 *
444 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
445 * @return The accessibility view id part of the node id.
446 *
447 * @hide
448 */
449 public static int getAccessibilityViewId(long accessibilityNodeId) {
450 return (int) accessibilityNodeId;
451 }
452
453 /**
454 * Gets the virtual descendant id which identifies an imaginary view in a
455 * containing View.
456 *
457 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
458 * @return The virtual view id part of the node id.
459 *
460 * @hide
461 */
462 public static int getVirtualDescendantId(long accessibilityNodeId) {
463 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
464 >> VIRTUAL_DESCENDANT_ID_SHIFT);
465 }
466
467 /**
468 * Makes a node id by shifting the <code>virtualDescendantId</code>
469 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
470 * the bitwise or with the <code>accessibilityViewId</code>.
471 *
472 * @param accessibilityViewId A View accessibility id.
473 * @param virtualDescendantId A virtual descendant id.
474 * @return The node id.
475 *
476 * @hide
477 */
478 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
479 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
480 }
481
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700482 // Housekeeping.
483 private static final int MAX_POOL_SIZE = 50;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -0800484 private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
485 new SynchronizedPool<AccessibilityNodeInfo>(MAX_POOL_SIZE);
486
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700487 private boolean mSealed;
488
489 // Data.
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800490 private int mWindowId = UNDEFINED;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -0800491 private long mSourceNodeId = ROOT_NODE_ID;
492 private long mParentNodeId = ROOT_NODE_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -0700493 private long mLabelForId = ROOT_NODE_ID;
494 private long mLabeledById = ROOT_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800495
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700496 private int mBooleanProperties;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700497 private final Rect mBoundsInParent = new Rect();
498 private final Rect mBoundsInScreen = new Rect();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700499
500 private CharSequence mPackageName;
501 private CharSequence mClassName;
502 private CharSequence mText;
503 private CharSequence mContentDescription;
Svetoslav9fa1ee52013-04-22 12:43:03 -0700504 private String mViewIdResourceName;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700505
Alan Viverettef0aed092013-11-06 15:33:03 -0800506 private LongArray mChildNodeIds;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700507 private int mActions;
508
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700509 private int mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700510
Svetoslavbcc46a02013-02-06 11:56:00 -0800511 private int mTextSelectionStart = UNDEFINED;
512 private int mTextSelectionEnd = UNDEFINED;
Svetoslav6254f482013-06-04 17:22:14 -0700513 private int mInputType = InputType.TYPE_NULL;
Alan Viverette77e9a282013-09-12 17:16:09 -0700514 private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
Svetoslav6254f482013-06-04 17:22:14 -0700515
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -0700516 private Bundle mExtras;
Svetoslavbcc46a02013-02-06 11:56:00 -0800517
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800518 private int mConnectionId = UNDEFINED;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700519
Svetoslav3577a282013-06-06 14:09:10 -0700520 private RangeInfo mRangeInfo;
521 private CollectionInfo mCollectionInfo;
522 private CollectionItemInfo mCollectionItemInfo;
523
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700524 /**
525 * Hide constructor from clients.
526 */
527 private AccessibilityNodeInfo() {
528 /* do nothing */
529 }
530
531 /**
532 * Sets the source.
Svetoslav Ganov02107852011-10-03 17:06:56 -0700533 * <p>
534 * <strong>Note:</strong> Cannot be called from an
535 * {@link android.accessibilityservice.AccessibilityService}.
536 * This class is made immutable before being delivered to an AccessibilityService.
537 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700538 *
539 * @param source The info source.
540 */
541 public void setSource(View source) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800542 setSource(source, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700543 }
544
545 /**
546 * Sets the source to be a virtual descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700547 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700548 * is set as the source.
549 * <p>
550 * A virtual descendant is an imaginary View that is reported as a part of the view
551 * hierarchy for accessibility purposes. This enables custom views that draw complex
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700552 * content to report themselves as a tree of virtual views, thus conveying their
Svetoslav Ganov02107852011-10-03 17:06:56 -0700553 * logical structure.
554 * </p>
555 * <p>
556 * <strong>Note:</strong> Cannot be called from an
557 * {@link android.accessibilityservice.AccessibilityService}.
558 * This class is made immutable before being delivered to an AccessibilityService.
559 * </p>
560 *
561 * @param root The root of the virtual subtree.
562 * @param virtualDescendantId The id of the virtual descendant.
563 */
564 public void setSource(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700565 enforceNotSealed();
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800566 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700567 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800568 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700569 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700570 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700571
Svetoslav Ganov42138042012-03-20 11:51:39 -0700572 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700573 * Find the view that has the specified focus type. The search starts from
Svetoslav Ganov42138042012-03-20 11:51:39 -0700574 * the view represented by this node info.
575 *
576 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
577 * {@link #FOCUS_ACCESSIBILITY}.
578 * @return The node info of the focused view or null.
579 *
580 * @see #FOCUS_INPUT
581 * @see #FOCUS_ACCESSIBILITY
582 */
583 public AccessibilityNodeInfo findFocus(int focus) {
584 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700585 enforceValidFocusType(focus);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700586 if (!canPerformRequestOverConnection(mSourceNodeId)) {
587 return null;
588 }
589 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
590 mSourceNodeId, focus);
591 }
592
593 /**
594 * Searches for the nearest view in the specified direction that can take
595 * the input focus.
596 *
597 * @param direction The direction. Can be one of:
598 * {@link View#FOCUS_DOWN},
599 * {@link View#FOCUS_UP},
600 * {@link View#FOCUS_LEFT},
601 * {@link View#FOCUS_RIGHT},
602 * {@link View#FOCUS_FORWARD},
Svetoslav Ganov8ffe8b32012-06-15 10:31:31 -0700603 * {@link View#FOCUS_BACKWARD}.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700604 *
605 * @return The node info for the view that can take accessibility focus.
606 */
607 public AccessibilityNodeInfo focusSearch(int direction) {
608 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700609 enforceValidFocusDirection(direction);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700610 if (!canPerformRequestOverConnection(mSourceNodeId)) {
611 return null;
612 }
613 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
614 mSourceNodeId, direction);
615 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700616
617 /**
618 * Gets the id of the window from which the info comes from.
619 *
620 * @return The window id.
621 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700622 public int getWindowId() {
Svetoslav Ganov02107852011-10-03 17:06:56 -0700623 return mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700624 }
625
626 /**
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800627 * Refreshes this info with the latest state of the view it represents.
628 * <p>
629 * <strong>Note:</strong> If this method returns false this info is obsolete
630 * since it represents a view that is no longer in the view tree and should
631 * be recycled.
632 * </p>
Svetoslav6254f482013-06-04 17:22:14 -0700633 *
634 * @param bypassCache Whether to bypass the cache.
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800635 * @return Whether the refresh succeeded.
Svetoslav6254f482013-06-04 17:22:14 -0700636 *
637 * @hide
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800638 */
Svetoslav6254f482013-06-04 17:22:14 -0700639 public boolean refresh(boolean bypassCache) {
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800640 enforceSealed();
641 if (!canPerformRequestOverConnection(mSourceNodeId)) {
642 return false;
643 }
644 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
645 AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
Svetoslav6254f482013-06-04 17:22:14 -0700646 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0);
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800647 if (refreshedInfo == null) {
648 return false;
649 }
650 init(refreshedInfo);
651 refreshedInfo.recycle();
652 return true;
653 }
654
655 /**
Svetoslav6254f482013-06-04 17:22:14 -0700656 * Refreshes this info with the latest state of the view it represents.
657 * <p>
658 * <strong>Note:</strong> If this method returns false this info is obsolete
659 * since it represents a view that is no longer in the view tree and should
660 * be recycled.
661 * </p>
662 * @return Whether the refresh succeeded.
663 */
664 public boolean refresh() {
665 return refresh(false);
666 }
667
668 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800669 * Returns the array containing the IDs of this node's children.
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800670 *
671 * @hide
672 */
Alan Viverettef0aed092013-11-06 15:33:03 -0800673 public LongArray getChildNodeIds() {
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800674 return mChildNodeIds;
675 }
676
677 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800678 * Returns the id of the child at the specified index.
679 *
680 * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
681 * getChildCount()
682 * @hide
683 */
684 public long getChildId(int index) {
685 if (mChildNodeIds == null) {
686 throw new IndexOutOfBoundsException();
687 }
688 return mChildNodeIds.get(index);
689 }
690
691 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700692 * Gets the number of children.
693 *
694 * @return The child count.
695 */
696 public int getChildCount() {
Alan Viverettef0aed092013-11-06 15:33:03 -0800697 return mChildNodeIds == null ? 0 : mChildNodeIds.size();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700698 }
699
700 /**
701 * Get the child at given index.
702 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700703 * <strong>Note:</strong> It is a client responsibility to recycle the
704 * received info by calling {@link AccessibilityNodeInfo#recycle()}
705 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700706 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700707 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700708 * @param index The child index.
709 * @return The child node.
710 *
711 * @throws IllegalStateException If called outside of an AccessibilityService.
712 *
713 */
714 public AccessibilityNodeInfo getChild(int index) {
715 enforceSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -0800716 if (mChildNodeIds == null) {
717 return null;
718 }
Svetoslav Ganov02107852011-10-03 17:06:56 -0700719 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700720 return null;
721 }
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800722 final long childId = mChildNodeIds.get(index);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700723 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800724 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
Svetoslav6254f482013-06-04 17:22:14 -0700725 childId, false, FLAG_PREFETCH_DESCENDANTS);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700726 }
727
728 /**
729 * Adds a child.
730 * <p>
Svetoslav Ganov02107852011-10-03 17:06:56 -0700731 * <strong>Note:</strong> Cannot be called from an
732 * {@link android.accessibilityservice.AccessibilityService}.
733 * This class is made immutable before being delivered to an AccessibilityService.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700734 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700735 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700736 * @param child The child.
737 *
738 * @throws IllegalStateException If called from an AccessibilityService.
739 */
740 public void addChild(View child) {
Alan Viverettef0aed092013-11-06 15:33:03 -0800741 addChildInternal(child, UNDEFINED, true);
742 }
743
744 /**
745 * Unchecked version of {@link #addChild(View)} that does not verify
746 * uniqueness. For framework use only.
747 *
748 * @hide
749 */
750 public void addChildUnchecked(View child) {
751 addChildInternal(child, UNDEFINED, false);
752 }
753
754 /**
755 * Removes a child. If the child was not previously added to the node,
756 * calling this method has no effect.
757 * <p>
758 * <strong>Note:</strong> Cannot be called from an
759 * {@link android.accessibilityservice.AccessibilityService}.
760 * This class is made immutable before being delivered to an AccessibilityService.
761 * </p>
762 *
763 * @param child The child.
764 * @return true if the child was present
765 *
766 * @throws IllegalStateException If called from an AccessibilityService.
767 */
768 public boolean removeChild(View child) {
769 return removeChild(child, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700770 }
771
772 /**
773 * Adds a virtual child which is a descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700774 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700775 * is added as a child.
776 * <p>
777 * A virtual descendant is an imaginary View that is reported as a part of the view
778 * hierarchy for accessibility purposes. This enables custom views that draw complex
779 * content to report them selves as a tree of virtual views, thus conveying their
780 * logical structure.
781 * </p>
782 *
783 * @param root The root of the virtual subtree.
784 * @param virtualDescendantId The id of the virtual child.
785 */
786 public void addChild(View root, int virtualDescendantId) {
Alan Viverettef0aed092013-11-06 15:33:03 -0800787 addChildInternal(root, virtualDescendantId, true);
788 }
789
790 private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700791 enforceNotSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -0800792 if (mChildNodeIds == null) {
793 mChildNodeIds = new LongArray();
794 }
Svetoslav Ganov02107852011-10-03 17:06:56 -0700795 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800796 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700797 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Alan Viverettef0aed092013-11-06 15:33:03 -0800798 // If we're checking uniqueness and the ID already exists, abort.
799 if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
800 return;
801 }
802 mChildNodeIds.add(childNodeId);
803 }
804
805 /**
806 * Removes a virtual child which is a descendant of the given
807 * <code>root</code>. If the child was not previously added to the node,
808 * calling this method has no effect.
809 *
810 * @param root The root of the virtual subtree.
811 * @param virtualDescendantId The id of the virtual child.
812 * @return true if the child was present
813 * @see #addChild(View, int)
814 */
815 public boolean removeChild(View root, int virtualDescendantId) {
816 enforceNotSealed();
817 final LongArray childIds = mChildNodeIds;
818 if (childIds == null) {
819 return false;
820 }
821 final int rootAccessibilityViewId =
822 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
823 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
824 final int index = childIds.indexOf(childNodeId);
825 if (index < 0) {
826 return false;
827 }
828 childIds.remove(index);
829 return true;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700830 }
831
832 /**
833 * Gets the actions that can be performed on the node.
834 *
835 * @return The bit mask of with actions.
836 *
837 * @see AccessibilityNodeInfo#ACTION_FOCUS
838 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
839 * @see AccessibilityNodeInfo#ACTION_SELECT
840 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
Svetoslav Ganova1dc7612012-05-10 04:14:53 -0700841 * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
842 * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
843 * @see AccessibilityNodeInfo#ACTION_CLICK
844 * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
845 * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
846 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
847 * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
848 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
849 * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
850 * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700851 */
852 public int getActions() {
853 return mActions;
854 }
855
856 /**
857 * Adds an action that can be performed on the node.
858 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700859 * <strong>Note:</strong> Cannot be called from an
860 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700861 * This class is made immutable before being delivered to an AccessibilityService.
862 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700863 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700864 * @param action The action.
865 *
866 * @throws IllegalStateException If called from an AccessibilityService.
867 */
868 public void addAction(int action) {
869 enforceNotSealed();
870 mActions |= action;
871 }
872
873 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800874 * Removes an action that can be performed on the node. If the action was
875 * not already added to the node, calling this method has no effect.
876 * <p>
877 * <strong>Note:</strong> Cannot be called from an
878 * {@link android.accessibilityservice.AccessibilityService}.
879 * This class is made immutable before being delivered to an AccessibilityService.
880 * </p>
881 *
882 * @param action The action.
883 *
884 * @throws IllegalStateException If called from an AccessibilityService.
885 */
886 public void removeAction(int action) {
887 enforceNotSealed();
888 mActions &= ~action;
889 }
890
891 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700892 * Sets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700893 * <p>
894 * <strong>Note:</strong> Cannot be called from an
895 * {@link android.accessibilityservice.AccessibilityService}.
896 * This class is made immutable before being delivered to an AccessibilityService.
897 * </p>
898 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700899 * @param granularities The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700900 *
901 * @throws IllegalStateException If called from an AccessibilityService.
902 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700903 public void setMovementGranularities(int granularities) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700904 enforceNotSealed();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700905 mMovementGranularities = granularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700906 }
907
908 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700909 * Gets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700910 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700911 * @return The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700912 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700913 public int getMovementGranularities() {
914 return mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700915 }
916
917 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700918 * Performs an action on the node.
919 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700920 * <strong>Note:</strong> An action can be performed only if the request is made
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700921 * from an {@link android.accessibilityservice.AccessibilityService}.
922 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700923 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700924 * @param action The action to perform.
925 * @return True if the action was performed.
926 *
927 * @throws IllegalStateException If called outside of an AccessibilityService.
928 */
929 public boolean performAction(int action) {
930 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700931 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700932 return false;
933 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700934 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700935 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
936 action, null);
937 }
938
939 /**
940 * Performs an action on the node.
941 * <p>
942 * <strong>Note:</strong> An action can be performed only if the request is made
943 * from an {@link android.accessibilityservice.AccessibilityService}.
944 * </p>
945 *
946 * @param action The action to perform.
947 * @param arguments A bundle with additional arguments.
948 * @return True if the action was performed.
949 *
950 * @throws IllegalStateException If called outside of an AccessibilityService.
951 */
952 public boolean performAction(int action, Bundle arguments) {
953 enforceSealed();
954 if (!canPerformRequestOverConnection(mSourceNodeId)) {
955 return false;
956 }
957 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
958 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
959 action, arguments);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700960 }
961
962 /**
963 * Finds {@link AccessibilityNodeInfo}s by text. The match is case
Svetoslav Ganov86398bd2011-06-21 17:38:43 -0700964 * insensitive containment. The search is relative to this info i.e.
965 * this info is the root of the traversed tree.
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700966 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700967 * <p>
968 * <strong>Note:</strong> It is a client responsibility to recycle the
969 * received info by calling {@link AccessibilityNodeInfo#recycle()}
970 * to avoid creating of multiple instances.
971 * </p>
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700972 *
973 * @param text The searched text.
974 * @return A list of node info.
975 */
976 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
977 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -0700978 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganov86398bd2011-06-21 17:38:43 -0700979 return Collections.emptyList();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700980 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700981 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov79311c42012-01-17 20:24:26 -0800982 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
983 text);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700984 }
985
986 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800987 * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
988 * name where a fully qualified id is of the from "package:id/id_resource_name".
989 * For example, if the target application's package is "foo.bar" and the id
990 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
991 *
992 * <p>
993 * <strong>Note:</strong> It is a client responsibility to recycle the
994 * received info by calling {@link AccessibilityNodeInfo#recycle()}
995 * to avoid creating of multiple instances.
996 * </p>
997 * <p>
998 * <strong>Note:</strong> The primary usage of this API is for UI test automation
999 * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
1000 * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08001001 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001002 * </p>
1003 *
1004 * @param viewId The fully qualified resource name of the view id to find.
1005 * @return A list of node info.
1006 */
1007 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
1008 enforceSealed();
1009 if (!canPerformRequestOverConnection(mSourceNodeId)) {
1010 return Collections.emptyList();
1011 }
1012 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1013 return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
1014 viewId);
1015 }
1016
1017 /**
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001018 * Gets the parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001019 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001020 * <strong>Note:</strong> It is a client responsibility to recycle the
1021 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1022 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001023 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001024 *
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001025 * @return The parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001026 */
1027 public AccessibilityNodeInfo getParent() {
1028 enforceSealed();
Svetoslav Ganovaf0d9842011-10-26 15:29:26 -07001029 if (!canPerformRequestOverConnection(mParentNodeId)) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001030 return null;
1031 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07001032 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08001033 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
Svetoslav6254f482013-06-04 17:22:14 -07001034 mWindowId, mParentNodeId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001035 }
1036
1037 /**
1038 * @return The parent node id.
1039 *
1040 * @hide
1041 */
1042 public long getParentNodeId() {
1043 return mParentNodeId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001044 }
1045
1046 /**
1047 * Sets the parent.
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 parent The parent.
1055 *
1056 * @throws IllegalStateException If called from an AccessibilityService.
1057 */
1058 public void setParent(View parent) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08001059 setParent(parent, UNDEFINED);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001060 }
1061
1062 /**
1063 * Sets the parent to be a virtual descendant of the given <code>root</code>.
1064 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
1065 * is set as the parent.
1066 * <p>
1067 * A virtual descendant is an imaginary View that is reported as a part of the view
1068 * hierarchy for accessibility purposes. This enables custom views that draw complex
1069 * content to report them selves as a tree of virtual views, thus conveying their
1070 * logical structure.
1071 * </p>
1072 * <p>
1073 * <strong>Note:</strong> Cannot be called from an
1074 * {@link android.accessibilityservice.AccessibilityService}.
1075 * This class is made immutable before being delivered to an AccessibilityService.
1076 * </p>
1077 *
1078 * @param root The root of the virtual subtree.
1079 * @param virtualDescendantId The id of the virtual descendant.
1080 */
1081 public void setParent(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001082 enforceNotSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -07001083 final int rootAccessibilityViewId =
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08001084 (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001085 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001086 }
1087
1088 /**
1089 * Gets the node bounds in parent coordinates.
1090 *
1091 * @param outBounds The output node bounds.
1092 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001093 public void getBoundsInParent(Rect outBounds) {
1094 outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
1095 mBoundsInParent.right, mBoundsInParent.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001096 }
1097
1098 /**
1099 * Sets the node bounds in parent coordinates.
1100 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001101 * <strong>Note:</strong> Cannot be called from an
1102 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001103 * This class is made immutable before being delivered to an AccessibilityService.
1104 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001105 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001106 * @param bounds The node bounds.
1107 *
1108 * @throws IllegalStateException If called from an AccessibilityService.
1109 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001110 public void setBoundsInParent(Rect bounds) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001111 enforceNotSealed();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001112 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
1113 }
1114
1115 /**
1116 * Gets the node bounds in screen coordinates.
1117 *
1118 * @param outBounds The output node bounds.
1119 */
1120 public void getBoundsInScreen(Rect outBounds) {
1121 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
1122 mBoundsInScreen.right, mBoundsInScreen.bottom);
1123 }
1124
1125 /**
1126 * Sets the node bounds in screen coordinates.
1127 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001128 * <strong>Note:</strong> Cannot be called from an
1129 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001130 * This class is made immutable before being delivered to an AccessibilityService.
1131 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001132 *
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001133 * @param bounds The node bounds.
1134 *
1135 * @throws IllegalStateException If called from an AccessibilityService.
1136 */
1137 public void setBoundsInScreen(Rect bounds) {
1138 enforceNotSealed();
1139 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001140 }
1141
1142 /**
1143 * Gets whether this node is checkable.
1144 *
1145 * @return True if the node is checkable.
1146 */
1147 public boolean isCheckable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001148 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001149 }
1150
1151 /**
1152 * Sets whether this node is checkable.
1153 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001154 * <strong>Note:</strong> Cannot be called from an
1155 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001156 * This class is made immutable before being delivered to an AccessibilityService.
1157 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001158 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001159 * @param checkable True if the node is checkable.
1160 *
1161 * @throws IllegalStateException If called from an AccessibilityService.
1162 */
1163 public void setCheckable(boolean checkable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001164 setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001165 }
1166
1167 /**
1168 * Gets whether this node is checked.
1169 *
1170 * @return True if the node is checked.
1171 */
1172 public boolean isChecked() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001173 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001174 }
1175
1176 /**
1177 * Sets whether this node is checked.
1178 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001179 * <strong>Note:</strong> Cannot be called from an
1180 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001181 * This class is made immutable before being delivered to an AccessibilityService.
1182 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001183 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001184 * @param checked True if the node is checked.
1185 *
1186 * @throws IllegalStateException If called from an AccessibilityService.
1187 */
1188 public void setChecked(boolean checked) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001189 setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001190 }
1191
1192 /**
1193 * Gets whether this node is focusable.
1194 *
1195 * @return True if the node is focusable.
1196 */
1197 public boolean isFocusable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001198 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001199 }
1200
1201 /**
1202 * Sets whether this node is focusable.
1203 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001204 * <strong>Note:</strong> Cannot be called from an
1205 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001206 * This class is made immutable before being delivered to an AccessibilityService.
1207 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001208 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001209 * @param focusable True if the node is focusable.
1210 *
1211 * @throws IllegalStateException If called from an AccessibilityService.
1212 */
1213 public void setFocusable(boolean focusable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001214 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001215 }
1216
1217 /**
1218 * Gets whether this node is focused.
1219 *
1220 * @return True if the node is focused.
1221 */
1222 public boolean isFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001223 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001224 }
1225
1226 /**
1227 * Sets whether this node is focused.
1228 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001229 * <strong>Note:</strong> Cannot be called from an
1230 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001231 * This class is made immutable before being delivered to an AccessibilityService.
1232 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001233 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001234 * @param focused True if the node is focused.
1235 *
1236 * @throws IllegalStateException If called from an AccessibilityService.
1237 */
1238 public void setFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001239 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001240 }
1241
1242 /**
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001243 * Sets whether this node is visible to the user.
1244 *
1245 * @return Whether the node is visible to the user.
1246 */
1247 public boolean isVisibleToUser() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001248 return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001249 }
1250
1251 /**
1252 * Sets whether this node is visible to the user.
1253 * <p>
1254 * <strong>Note:</strong> Cannot be called from an
1255 * {@link android.accessibilityservice.AccessibilityService}.
1256 * This class is made immutable before being delivered to an AccessibilityService.
1257 * </p>
1258 *
1259 * @param visibleToUser Whether the node is visible to the user.
1260 *
1261 * @throws IllegalStateException If called from an AccessibilityService.
1262 */
1263 public void setVisibleToUser(boolean visibleToUser) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001264 setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001265 }
1266
1267 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001268 * Gets whether this node is accessibility focused.
1269 *
1270 * @return True if the node is accessibility focused.
1271 */
1272 public boolean isAccessibilityFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001273 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001274 }
1275
1276 /**
1277 * Sets whether this node is accessibility focused.
1278 * <p>
1279 * <strong>Note:</strong> Cannot be called from an
1280 * {@link android.accessibilityservice.AccessibilityService}.
1281 * This class is made immutable before being delivered to an AccessibilityService.
1282 * </p>
1283 *
1284 * @param focused True if the node is accessibility focused.
1285 *
1286 * @throws IllegalStateException If called from an AccessibilityService.
1287 */
1288 public void setAccessibilityFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001289 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001290 }
1291
1292 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001293 * Gets whether this node is selected.
1294 *
1295 * @return True if the node is selected.
1296 */
1297 public boolean isSelected() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001298 return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001299 }
1300
1301 /**
1302 * Sets whether this node is selected.
1303 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001304 * <strong>Note:</strong> Cannot be called from an
1305 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001306 * This class is made immutable before being delivered to an AccessibilityService.
1307 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001308 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001309 * @param selected True if the node is selected.
1310 *
1311 * @throws IllegalStateException If called from an AccessibilityService.
1312 */
1313 public void setSelected(boolean selected) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001314 setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001315 }
1316
1317 /**
1318 * Gets whether this node is clickable.
1319 *
1320 * @return True if the node is clickable.
1321 */
1322 public boolean isClickable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001323 return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001324 }
1325
1326 /**
1327 * Sets whether this node is clickable.
1328 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001329 * <strong>Note:</strong> Cannot be called from an
1330 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001331 * This class is made immutable before being delivered to an AccessibilityService.
1332 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001333 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001334 * @param clickable True if the node is clickable.
1335 *
1336 * @throws IllegalStateException If called from an AccessibilityService.
1337 */
1338 public void setClickable(boolean clickable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001339 setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001340 }
1341
1342 /**
1343 * Gets whether this node is long clickable.
1344 *
1345 * @return True if the node is long clickable.
1346 */
1347 public boolean isLongClickable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001348 return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001349 }
1350
1351 /**
1352 * Sets whether this node is long clickable.
1353 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001354 * <strong>Note:</strong> Cannot be called from an
1355 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001356 * This class is made immutable before being delivered to an AccessibilityService.
1357 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001358 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001359 * @param longClickable True if the node is long clickable.
1360 *
1361 * @throws IllegalStateException If called from an AccessibilityService.
1362 */
1363 public void setLongClickable(boolean longClickable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001364 setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001365 }
1366
1367 /**
1368 * Gets whether this node is enabled.
1369 *
1370 * @return True if the node is enabled.
1371 */
1372 public boolean isEnabled() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001373 return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001374 }
1375
1376 /**
1377 * Sets whether this node is enabled.
1378 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001379 * <strong>Note:</strong> Cannot be called from an
1380 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001381 * This class is made immutable before being delivered to an AccessibilityService.
1382 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001383 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001384 * @param enabled True if the node is enabled.
1385 *
1386 * @throws IllegalStateException If called from an AccessibilityService.
1387 */
1388 public void setEnabled(boolean enabled) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001389 setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001390 }
1391
1392 /**
1393 * Gets whether this node is a password.
1394 *
1395 * @return True if the node is a password.
1396 */
1397 public boolean isPassword() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001398 return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001399 }
1400
1401 /**
1402 * Sets whether this node is a password.
1403 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001404 * <strong>Note:</strong> Cannot be called from an
1405 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001406 * This class is made immutable before being delivered to an AccessibilityService.
1407 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001408 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001409 * @param password True if the node is a password.
1410 *
1411 * @throws IllegalStateException If called from an AccessibilityService.
1412 */
1413 public void setPassword(boolean password) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001414 setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001415 }
1416
1417 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -07001418 * Gets if the node is scrollable.
1419 *
1420 * @return True if the node is scrollable, false otherwise.
1421 */
1422 public boolean isScrollable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001423 return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
Svetoslav Ganova0156172011-06-26 17:55:44 -07001424 }
1425
1426 /**
1427 * Sets if the node is scrollable.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001428 * <p>
1429 * <strong>Note:</strong> Cannot be called from an
1430 * {@link android.accessibilityservice.AccessibilityService}.
1431 * This class is made immutable before being delivered to an AccessibilityService.
1432 * </p>
Svetoslav Ganova0156172011-06-26 17:55:44 -07001433 *
1434 * @param scrollable True if the node is scrollable, false otherwise.
1435 *
1436 * @throws IllegalStateException If called from an AccessibilityService.
1437 */
1438 public void setScrollable(boolean scrollable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001439 setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
1440 }
1441
1442 /**
1443 * Gets if the node is editable.
1444 *
1445 * @return True if the node is editable, false otherwise.
1446 */
1447 public boolean isEditable() {
1448 return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
1449 }
1450
1451 /**
1452 * Sets whether this node is editable.
1453 * <p>
1454 * <strong>Note:</strong> Cannot be called from an
1455 * {@link android.accessibilityservice.AccessibilityService}.
1456 * This class is made immutable before being delivered to an AccessibilityService.
1457 * </p>
1458 *
1459 * @param editable True if the node is editable.
1460 *
1461 * @throws IllegalStateException If called from an AccessibilityService.
1462 */
1463 public void setEditable(boolean editable) {
1464 setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
Svetoslav Ganova0156172011-06-26 17:55:44 -07001465 }
1466
1467 /**
Svetoslav3577a282013-06-06 14:09:10 -07001468 * Gets the collection info if the node is a collection. A collection
1469 * child is always a collection item.
1470 *
1471 * @return The collection info.
1472 */
1473 public CollectionInfo getCollectionInfo() {
1474 return mCollectionInfo;
1475 }
1476
1477 /**
1478 * Sets the collection info if the node is a collection. A collection
1479 * child is always a collection item.
1480 * <p>
1481 * <strong>Note:</strong> Cannot be called from an
1482 * {@link android.accessibilityservice.AccessibilityService}.
1483 * This class is made immutable before being delivered to an AccessibilityService.
1484 * </p>
1485 *
1486 * @param collectionInfo The collection info.
1487 */
1488 public void setCollectionInfo(CollectionInfo collectionInfo) {
1489 enforceNotSealed();
1490 mCollectionInfo = collectionInfo;
1491 }
1492
1493 /**
1494 * Gets the collection item info if the node is a collection item. A collection
1495 * item is always a child of a collection.
1496 *
1497 * @return The collection item info.
1498 */
1499 public CollectionItemInfo getCollectionItemInfo() {
1500 return mCollectionItemInfo;
1501 }
1502
1503 /**
1504 * Sets the collection item info if the node is a collection item. A collection
1505 * item is always a child of a collection.
1506 * <p>
1507 * <strong>Note:</strong> Cannot be called from an
1508 * {@link android.accessibilityservice.AccessibilityService}.
1509 * This class is made immutable before being delivered to an AccessibilityService.
1510 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07001511 */
1512 public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
1513 enforceNotSealed();
1514 mCollectionItemInfo = collectionItemInfo;
1515 }
1516
1517 /**
1518 * Gets the range info if this node is a range.
1519 *
1520 * @return The range.
1521 */
1522 public RangeInfo getRangeInfo() {
1523 return mRangeInfo;
1524 }
1525
1526 /**
1527 * Sets the range info if this node is a range.
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 rangeInfo The range info.
1535 */
1536 public void setRangeInfo(RangeInfo rangeInfo) {
1537 enforceNotSealed();
1538 mRangeInfo = rangeInfo;
1539 }
1540
1541 /**
1542 * Gets if the content of this node is invalid. For example,
1543 * a date is not well-formed.
1544 *
1545 * @return If the node content is invalid.
1546 */
1547 public boolean isContentInvalid() {
1548 return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
1549 }
1550
1551 /**
1552 * Sets if the content of this node is invalid. For example,
1553 * a date is not well-formed.
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 contentInvalid If the node content is invalid.
1561 */
1562 public void setContentInvalid(boolean contentInvalid) {
1563 setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
1564 }
1565
1566 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07001567 * Gets the node's live region mode.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07001568 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07001569 * A live region is a node that contains information that is important for
1570 * the user and when it changes the user should be notified. For example,
1571 * in a login screen with a TextView that displays an "incorrect password"
1572 * notification, that view should be marked as a live region with mode
1573 * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07001574 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07001575 * It is the responsibility of the accessibility service to monitor
1576 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
1577 * changes to live region nodes and their children.
Svetoslav3577a282013-06-06 14:09:10 -07001578 *
Alan Viverette77e9a282013-09-12 17:16:09 -07001579 * @return The live region mode, or
1580 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
1581 * live region.
1582 * @see android.view.View#getAccessibilityLiveRegion()
Svetoslav3577a282013-06-06 14:09:10 -07001583 */
Alan Viverette77e9a282013-09-12 17:16:09 -07001584 public int getLiveRegion() {
1585 return mLiveRegion;
Svetoslav3577a282013-06-06 14:09:10 -07001586 }
1587
1588 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07001589 * Sets the node's live region mode.
Svetoslav3577a282013-06-06 14:09:10 -07001590 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07001591 * <strong>Note:</strong> Cannot be called from an
1592 * {@link android.accessibilityservice.AccessibilityService}. This class is
1593 * made immutable before being delivered to an AccessibilityService.
Svetoslav3577a282013-06-06 14:09:10 -07001594 *
Alan Viverette77e9a282013-09-12 17:16:09 -07001595 * @param mode The live region mode, or
1596 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
1597 * live region.
1598 * @see android.view.View#setAccessibilityLiveRegion(int)
Svetoslav3577a282013-06-06 14:09:10 -07001599 */
Alan Viverette77e9a282013-09-12 17:16:09 -07001600 public void setLiveRegion(int mode) {
1601 enforceNotSealed();
1602 mLiveRegion = mode;
Svetoslav3577a282013-06-06 14:09:10 -07001603 }
1604
1605 /**
1606 * Gets if the node is a multi line editable text.
1607 *
1608 * @return True if the node is multi line.
1609 */
1610 public boolean isMultiLine() {
1611 return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
1612 }
1613
1614 /**
1615 * Sets if the node is a multi line editable text.
1616 * <p>
1617 * <strong>Note:</strong> Cannot be called from an
1618 * {@link android.accessibilityservice.AccessibilityService}.
1619 * This class is made immutable before being delivered to an AccessibilityService.
1620 * </p>
1621 *
1622 * @param multiLine True if the node is multi line.
1623 */
1624 public void setMultiLine(boolean multiLine) {
Svetoslav3577a282013-06-06 14:09:10 -07001625 setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
1626 }
1627
1628 /**
1629 * Gets if this node opens a popup or a dialog.
1630 *
1631 * @return If the the node opens a popup.
1632 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07001633 public boolean canOpenPopup() {
Svetoslav3577a282013-06-06 14:09:10 -07001634 return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
1635 }
1636
1637 /**
1638 * Sets if this node opens a popup or a dialog.
1639 * <p>
1640 * <strong>Note:</strong> Cannot be called from an
1641 * {@link android.accessibilityservice.AccessibilityService}.
1642 * This class is made immutable before being delivered to an AccessibilityService.
1643 * </p>
1644 *
1645 * @param opensPopup If the the node opens a popup.
1646 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07001647 public void setCanOpenPopup(boolean opensPopup) {
1648 enforceNotSealed();
Svetoslav3577a282013-06-06 14:09:10 -07001649 setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
1650 }
1651
1652 /**
Svetoslav3577a282013-06-06 14:09:10 -07001653 * Gets if the node can be dismissed.
1654 *
1655 * @return If the node can be dismissed.
1656 */
1657 public boolean isDismissable() {
1658 return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
1659 }
1660
1661 /**
1662 * Sets if the node can be dismissed.
1663 * <p>
1664 * <strong>Note:</strong> Cannot be called from an
1665 * {@link android.accessibilityservice.AccessibilityService}.
1666 * This class is made immutable before being delivered to an AccessibilityService.
1667 * </p>
1668 *
1669 * @param dismissable If the node can be dismissed.
1670 */
1671 public void setDismissable(boolean dismissable) {
Svetoslav3577a282013-06-06 14:09:10 -07001672 setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
1673 }
1674
1675 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001676 * Gets the package this node comes from.
1677 *
1678 * @return The package name.
1679 */
1680 public CharSequence getPackageName() {
1681 return mPackageName;
1682 }
1683
1684 /**
1685 * Sets the package this node comes from.
1686 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001687 * <strong>Note:</strong> Cannot be called from an
1688 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001689 * This class is made immutable before being delivered to an AccessibilityService.
1690 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001691 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001692 * @param packageName The package name.
1693 *
1694 * @throws IllegalStateException If called from an AccessibilityService.
1695 */
1696 public void setPackageName(CharSequence packageName) {
1697 enforceNotSealed();
1698 mPackageName = packageName;
1699 }
1700
1701 /**
1702 * Gets the class this node comes from.
1703 *
1704 * @return The class name.
1705 */
1706 public CharSequence getClassName() {
1707 return mClassName;
1708 }
1709
1710 /**
1711 * Sets the class this node comes from.
1712 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001713 * <strong>Note:</strong> Cannot be called from an
1714 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001715 * This class is made immutable before being delivered to an AccessibilityService.
1716 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001717 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001718 * @param className The class name.
1719 *
1720 * @throws IllegalStateException If called from an AccessibilityService.
1721 */
1722 public void setClassName(CharSequence className) {
1723 enforceNotSealed();
1724 mClassName = className;
1725 }
1726
1727 /**
1728 * Gets the text of this node.
1729 *
1730 * @return The text.
1731 */
1732 public CharSequence getText() {
1733 return mText;
1734 }
1735
1736 /**
1737 * Sets the text of this node.
1738 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001739 * <strong>Note:</strong> Cannot be called from an
1740 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001741 * This class is made immutable before being delivered to an AccessibilityService.
1742 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001743 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001744 * @param text The text.
1745 *
1746 * @throws IllegalStateException If called from an AccessibilityService.
1747 */
1748 public void setText(CharSequence text) {
1749 enforceNotSealed();
1750 mText = text;
1751 }
1752
1753 /**
1754 * Gets the content description of this node.
1755 *
1756 * @return The content description.
1757 */
1758 public CharSequence getContentDescription() {
1759 return mContentDescription;
1760 }
1761
1762 /**
1763 * Sets the content description of this node.
1764 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001765 * <strong>Note:</strong> Cannot be called from an
1766 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001767 * This class is made immutable before being delivered to an AccessibilityService.
1768 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001769 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001770 * @param contentDescription The content description.
1771 *
1772 * @throws IllegalStateException If called from an AccessibilityService.
1773 */
1774 public void setContentDescription(CharSequence contentDescription) {
1775 enforceNotSealed();
1776 mContentDescription = contentDescription;
1777 }
1778
1779 /**
Svetoslav Ganov33aef982012-09-13 12:49:03 -07001780 * Sets the view for which the view represented by this info serves as a
1781 * label for accessibility purposes.
1782 *
1783 * @param labeled The view for which this info serves as a label.
1784 */
1785 public void setLabelFor(View labeled) {
1786 setLabelFor(labeled, UNDEFINED);
1787 }
1788
1789 /**
1790 * Sets the view for which the view represented by this info serves as a
1791 * label for accessibility purposes. If <code>virtualDescendantId</code>
1792 * is {@link View#NO_ID} the root is set as the labeled.
1793 * <p>
1794 * A virtual descendant is an imaginary View that is reported as a part of the view
1795 * hierarchy for accessibility purposes. This enables custom views that draw complex
1796 * content to report themselves as a tree of virtual views, thus conveying their
1797 * logical structure.
1798 * </p>
1799 * <p>
1800 * <strong>Note:</strong> Cannot be called from an
1801 * {@link android.accessibilityservice.AccessibilityService}.
1802 * This class is made immutable before being delivered to an AccessibilityService.
1803 * </p>
1804 *
1805 * @param root The root whose virtual descendant serves as a label.
1806 * @param virtualDescendantId The id of the virtual descendant.
1807 */
1808 public void setLabelFor(View root, int virtualDescendantId) {
1809 enforceNotSealed();
1810 final int rootAccessibilityViewId = (root != null)
1811 ? root.getAccessibilityViewId() : UNDEFINED;
1812 mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1813 }
1814
1815 /**
1816 * Gets the node info for which the view represented by this info serves as
1817 * a label for accessibility purposes.
1818 * <p>
1819 * <strong>Note:</strong> It is a client responsibility to recycle the
1820 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1821 * to avoid creating of multiple instances.
1822 * </p>
1823 *
1824 * @return The labeled info.
1825 */
1826 public AccessibilityNodeInfo getLabelFor() {
1827 enforceSealed();
1828 if (!canPerformRequestOverConnection(mLabelForId)) {
1829 return null;
1830 }
1831 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1832 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
Svetoslav6254f482013-06-04 17:22:14 -07001833 mWindowId, mLabelForId, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07001834 }
1835
1836 /**
1837 * Sets the view which serves as the label of the view represented by
1838 * this info for accessibility purposes.
1839 *
1840 * @param label The view that labels this node's source.
1841 */
1842 public void setLabeledBy(View label) {
1843 setLabeledBy(label, UNDEFINED);
1844 }
1845
1846 /**
1847 * Sets the view which serves as the label of the view represented by
1848 * this info for accessibility purposes. If <code>virtualDescendantId</code>
1849 * is {@link View#NO_ID} the root is set as the label.
1850 * <p>
1851 * A virtual descendant is an imaginary View that is reported as a part of the view
1852 * hierarchy for accessibility purposes. This enables custom views that draw complex
1853 * content to report themselves as a tree of virtual views, thus conveying their
1854 * logical structure.
1855 * </p>
1856 * <p>
1857 * <strong>Note:</strong> Cannot be called from an
1858 * {@link android.accessibilityservice.AccessibilityService}.
1859 * This class is made immutable before being delivered to an AccessibilityService.
1860 * </p>
1861 *
1862 * @param root The root whose virtual descendant labels this node's source.
1863 * @param virtualDescendantId The id of the virtual descendant.
1864 */
1865 public void setLabeledBy(View root, int virtualDescendantId) {
1866 enforceNotSealed();
1867 final int rootAccessibilityViewId = (root != null)
1868 ? root.getAccessibilityViewId() : UNDEFINED;
1869 mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1870 }
1871
1872 /**
1873 * Gets the node info which serves as the label of the view represented by
1874 * this info for accessibility purposes.
1875 * <p>
1876 * <strong>Note:</strong> It is a client responsibility to recycle the
1877 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1878 * to avoid creating of multiple instances.
1879 * </p>
1880 *
1881 * @return The label.
1882 */
1883 public AccessibilityNodeInfo getLabeledBy() {
1884 enforceSealed();
1885 if (!canPerformRequestOverConnection(mLabeledById)) {
1886 return null;
1887 }
1888 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1889 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
Svetoslav6254f482013-06-04 17:22:14 -07001890 mWindowId, mLabeledById, false, FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07001891 }
1892
1893 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001894 * Sets the fully qualified resource name of the source view's id.
1895 *
1896 * <p>
1897 * <strong>Note:</strong> Cannot be called from an
1898 * {@link android.accessibilityservice.AccessibilityService}.
1899 * This class is made immutable before being delivered to an AccessibilityService.
1900 * </p>
1901 *
Svetoslav92826452013-02-05 14:57:42 -08001902 * @param viewIdResName The id resource name.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001903 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07001904 public void setViewIdResourceName(String viewIdResName) {
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001905 enforceNotSealed();
Svetoslav22431a32013-02-05 14:30:19 -08001906 mViewIdResourceName = viewIdResName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001907 }
1908
1909 /**
1910 * Gets the fully qualified resource name of the source view's id.
1911 *
1912 * <p>
1913 * <strong>Note:</strong> The primary usage of this API is for UI test automation
1914 * and in order to report the source view id of an {@link AccessibilityNodeInfo} the
1915 * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08001916 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001917 * </p>
1918
1919 * @return The id resource name.
1920 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07001921 public String getViewIdResourceName() {
Svetoslav22431a32013-02-05 14:30:19 -08001922 return mViewIdResourceName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001923 }
1924
1925 /**
Svetoslavbcc46a02013-02-06 11:56:00 -08001926 * Gets the text selection start.
1927 *
1928 * @return The text selection start if there is selection or -1.
1929 */
1930 public int getTextSelectionStart() {
1931 return mTextSelectionStart;
1932 }
1933
1934 /**
1935 * Gets the text selection end.
1936 *
1937 * @return The text selection end if there is selection or -1.
1938 */
1939 public int getTextSelectionEnd() {
1940 return mTextSelectionEnd;
1941 }
1942
1943 /**
1944 * Sets the text selection start and end.
1945 * <p>
1946 * <strong>Note:</strong> Cannot be called from an
1947 * {@link android.accessibilityservice.AccessibilityService}.
1948 * This class is made immutable before being delivered to an AccessibilityService.
1949 * </p>
1950 *
1951 * @param start The text selection start.
1952 * @param end The text selection end.
1953 *
1954 * @throws IllegalStateException If called from an AccessibilityService.
1955 */
1956 public void setTextSelection(int start, int end) {
1957 enforceNotSealed();
1958 mTextSelectionStart = start;
1959 mTextSelectionEnd = end;
1960 }
1961
1962 /**
Svetoslav6254f482013-06-04 17:22:14 -07001963 * Gets the input type of the source as defined by {@link InputType}.
1964 *
1965 * @return The input type.
1966 */
1967 public int getInputType() {
1968 return mInputType;
1969 }
1970
1971 /**
1972 * Sets the input type of the source as defined by {@link InputType}.
1973 * <p>
1974 * <strong>Note:</strong> Cannot be called from an
1975 * {@link android.accessibilityservice.AccessibilityService}.
1976 * This class is made immutable before being delivered to an
1977 * AccessibilityService.
1978 * </p>
1979 *
1980 * @param inputType The input type.
1981 *
1982 * @throws IllegalStateException If called from an AccessibilityService.
1983 */
1984 public void setInputType(int inputType) {
Alan Viverettedf39cb92013-08-19 12:28:04 -07001985 enforceNotSealed();
Svetoslav6254f482013-06-04 17:22:14 -07001986 mInputType = inputType;
1987 }
1988
1989 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07001990 * Gets an optional bundle with extra data. The bundle
Svetoslav6254f482013-06-04 17:22:14 -07001991 * is lazily created and never <code>null</code>.
1992 * <p>
1993 * <strong>Note:</strong> It is recommended to use the package
1994 * name of your application as a prefix for the keys to avoid
1995 * collisions which may confuse an accessibility service if the
1996 * same key has different meaning when emitted from different
1997 * applications.
1998 * </p>
1999 *
2000 * @return The bundle.
2001 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002002 public Bundle getExtras() {
2003 if (mExtras == null) {
2004 mExtras = new Bundle();
Svetoslav6254f482013-06-04 17:22:14 -07002005 }
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002006 return mExtras;
Svetoslav6254f482013-06-04 17:22:14 -07002007 }
2008
2009 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002010 * Gets the value of a boolean property.
2011 *
2012 * @param property The property.
2013 * @return The value.
2014 */
2015 private boolean getBooleanProperty(int property) {
2016 return (mBooleanProperties & property) != 0;
2017 }
2018
2019 /**
2020 * Sets a boolean property.
2021 *
2022 * @param property The property.
2023 * @param value The value.
2024 *
2025 * @throws IllegalStateException If called from an AccessibilityService.
2026 */
2027 private void setBooleanProperty(int property, boolean value) {
2028 enforceNotSealed();
2029 if (value) {
2030 mBooleanProperties |= property;
2031 } else {
2032 mBooleanProperties &= ~property;
2033 }
2034 }
2035
2036 /**
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002037 * Sets the unique id of the IAccessibilityServiceConnection over which
2038 * this instance can send requests to the system.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002039 *
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002040 * @param connectionId The connection id.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002041 *
2042 * @hide
2043 */
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002044 public void setConnectionId(int connectionId) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002045 enforceNotSealed();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002046 mConnectionId = connectionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002047 }
2048
2049 /**
2050 * {@inheritDoc}
2051 */
Alan Viverettef0aed092013-11-06 15:33:03 -08002052 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002053 public int describeContents() {
2054 return 0;
2055 }
2056
2057 /**
Svetoslav Ganov79311c42012-01-17 20:24:26 -08002058 * Gets the id of the source node.
2059 *
2060 * @return The id.
2061 *
2062 * @hide
2063 */
2064 public long getSourceNodeId() {
2065 return mSourceNodeId;
2066 }
2067
2068 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002069 * Sets if this instance is sealed.
2070 *
2071 * @param sealed Whether is sealed.
2072 *
2073 * @hide
2074 */
2075 public void setSealed(boolean sealed) {
2076 mSealed = sealed;
2077 }
2078
2079 /**
2080 * Gets if this instance is sealed.
2081 *
2082 * @return Whether is sealed.
2083 *
2084 * @hide
2085 */
2086 public boolean isSealed() {
2087 return mSealed;
2088 }
2089
2090 /**
2091 * Enforces that this instance is sealed.
2092 *
2093 * @throws IllegalStateException If this instance is not sealed.
2094 *
2095 * @hide
2096 */
2097 protected void enforceSealed() {
2098 if (!isSealed()) {
2099 throw new IllegalStateException("Cannot perform this "
2100 + "action on a not sealed instance.");
2101 }
2102 }
2103
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07002104 private void enforceValidFocusDirection(int direction) {
2105 switch (direction) {
2106 case View.FOCUS_DOWN:
2107 case View.FOCUS_UP:
2108 case View.FOCUS_LEFT:
2109 case View.FOCUS_RIGHT:
2110 case View.FOCUS_FORWARD:
2111 case View.FOCUS_BACKWARD:
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07002112 return;
2113 default:
2114 throw new IllegalArgumentException("Unknown direction: " + direction);
2115 }
2116 }
2117
2118 private void enforceValidFocusType(int focusType) {
2119 switch (focusType) {
2120 case FOCUS_INPUT:
2121 case FOCUS_ACCESSIBILITY:
2122 return;
2123 default:
2124 throw new IllegalArgumentException("Unknown focus type: " + focusType);
2125 }
2126 }
2127
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002128 /**
2129 * Enforces that this instance is not sealed.
2130 *
2131 * @throws IllegalStateException If this instance is sealed.
2132 *
2133 * @hide
2134 */
2135 protected void enforceNotSealed() {
2136 if (isSealed()) {
2137 throw new IllegalStateException("Cannot perform this "
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002138 + "action on a sealed instance.");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002139 }
2140 }
2141
2142 /**
2143 * Returns a cached instance if such is available otherwise a new one
2144 * and sets the source.
2145 *
Svetoslav Ganov02107852011-10-03 17:06:56 -07002146 * @param source The source view.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002147 * @return An instance.
2148 *
2149 * @see #setSource(View)
2150 */
2151 public static AccessibilityNodeInfo obtain(View source) {
2152 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2153 info.setSource(source);
2154 return info;
2155 }
2156
2157 /**
Svetoslav Ganov02107852011-10-03 17:06:56 -07002158 * Returns a cached instance if such is available otherwise a new one
2159 * and sets the source.
2160 *
2161 * @param root The root of the virtual subtree.
2162 * @param virtualDescendantId The id of the virtual descendant.
2163 * @return An instance.
2164 *
2165 * @see #setSource(View, int)
2166 */
2167 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
2168 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2169 info.setSource(root, virtualDescendantId);
2170 return info;
2171 }
2172
2173 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002174 * Returns a cached instance if such is available otherwise a new one.
2175 *
2176 * @return An instance.
2177 */
2178 public static AccessibilityNodeInfo obtain() {
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08002179 AccessibilityNodeInfo info = sPool.acquire();
2180 return (info != null) ? info : new AccessibilityNodeInfo();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002181 }
2182
2183 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07002184 * Returns a cached instance if such is available or a new one is
2185 * create. The returned instance is initialized from the given
2186 * <code>info</code>.
2187 *
2188 * @param info The other info.
2189 * @return An instance.
2190 */
2191 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
2192 AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
2193 infoClone.init(info);
2194 return infoClone;
2195 }
2196
2197 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002198 * Return an instance back to be reused.
2199 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002200 * <strong>Note:</strong> You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002201 *
2202 * @throws IllegalStateException If the info is already recycled.
2203 */
2204 public void recycle() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002205 clear();
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08002206 sPool.release(this);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002207 }
2208
2209 /**
2210 * {@inheritDoc}
2211 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002212 * <strong>Note:</strong> After the instance is written to a parcel it
2213 * is recycled. You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002214 * </p>
2215 */
Alan Viverettef0aed092013-11-06 15:33:03 -08002216 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002217 public void writeToParcel(Parcel parcel, int flags) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002218 parcel.writeInt(isSealed() ? 1 : 0);
Svetoslav Ganov02107852011-10-03 17:06:56 -07002219 parcel.writeLong(mSourceNodeId);
2220 parcel.writeInt(mWindowId);
2221 parcel.writeLong(mParentNodeId);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002222 parcel.writeLong(mLabelForId);
2223 parcel.writeLong(mLabeledById);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002224 parcel.writeInt(mConnectionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002225
Alan Viverettef0aed092013-11-06 15:33:03 -08002226 final LongArray childIds = mChildNodeIds;
2227 if (childIds == null) {
2228 parcel.writeInt(0);
2229 } else {
2230 final int childIdsSize = childIds.size();
2231 parcel.writeInt(childIdsSize);
2232 for (int i = 0; i < childIdsSize; i++) {
2233 parcel.writeLong(childIds.get(i));
2234 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002235 }
2236
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002237 parcel.writeInt(mBoundsInParent.top);
2238 parcel.writeInt(mBoundsInParent.bottom);
2239 parcel.writeInt(mBoundsInParent.left);
2240 parcel.writeInt(mBoundsInParent.right);
2241
2242 parcel.writeInt(mBoundsInScreen.top);
2243 parcel.writeInt(mBoundsInScreen.bottom);
2244 parcel.writeInt(mBoundsInScreen.left);
2245 parcel.writeInt(mBoundsInScreen.right);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002246
2247 parcel.writeInt(mActions);
2248
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002249 parcel.writeInt(mMovementGranularities);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002250
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002251 parcel.writeInt(mBooleanProperties);
2252
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002253 parcel.writeCharSequence(mPackageName);
2254 parcel.writeCharSequence(mClassName);
2255 parcel.writeCharSequence(mText);
2256 parcel.writeCharSequence(mContentDescription);
Svetoslav9fa1ee52013-04-22 12:43:03 -07002257 parcel.writeString(mViewIdResourceName);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002258
Svetoslavbcc46a02013-02-06 11:56:00 -08002259 parcel.writeInt(mTextSelectionStart);
2260 parcel.writeInt(mTextSelectionEnd);
Svetoslav6254f482013-06-04 17:22:14 -07002261 parcel.writeInt(mInputType);
Alan Viverette77e9a282013-09-12 17:16:09 -07002262 parcel.writeInt(mLiveRegion);
Svetoslav6254f482013-06-04 17:22:14 -07002263
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002264 if (mExtras != null) {
Svetoslav6254f482013-06-04 17:22:14 -07002265 parcel.writeInt(1);
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002266 parcel.writeBundle(mExtras);
Svetoslav6254f482013-06-04 17:22:14 -07002267 } else {
2268 parcel.writeInt(0);
2269 }
Svetoslavbcc46a02013-02-06 11:56:00 -08002270
Svetoslav3577a282013-06-06 14:09:10 -07002271 if (mRangeInfo != null) {
2272 parcel.writeInt(1);
2273 parcel.writeInt(mRangeInfo.getType());
2274 parcel.writeFloat(mRangeInfo.getMin());
2275 parcel.writeFloat(mRangeInfo.getMax());
2276 parcel.writeFloat(mRangeInfo.getCurrent());
2277 } else {
2278 parcel.writeInt(0);
2279 }
2280
2281 if (mCollectionInfo != null) {
2282 parcel.writeInt(1);
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002283 parcel.writeInt(mCollectionInfo.getRowCount());
2284 parcel.writeInt(mCollectionInfo.getColumnCount());
Svetoslav3577a282013-06-06 14:09:10 -07002285 parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
2286 } else {
2287 parcel.writeInt(0);
2288 }
2289
2290 if (mCollectionItemInfo != null) {
2291 parcel.writeInt(1);
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002292 parcel.writeInt(mCollectionItemInfo.getColumnIndex());
2293 parcel.writeInt(mCollectionItemInfo.getColumnSpan());
2294 parcel.writeInt(mCollectionItemInfo.getRowIndex());
2295 parcel.writeInt(mCollectionItemInfo.getRowSpan());
Svetoslav3577a282013-06-06 14:09:10 -07002296 parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
2297 } else {
2298 parcel.writeInt(0);
2299 }
2300
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002301 // Since instances of this class are fetched via synchronous i.e. blocking
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002302 // calls in IPCs we always recycle as soon as the instance is marshaled.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002303 recycle();
2304 }
2305
2306 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07002307 * Initializes this instance from another one.
2308 *
2309 * @param other The other instance.
2310 */
2311 private void init(AccessibilityNodeInfo other) {
2312 mSealed = other.mSealed;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002313 mSourceNodeId = other.mSourceNodeId;
2314 mParentNodeId = other.mParentNodeId;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002315 mLabelForId = other.mLabelForId;
2316 mLabeledById = other.mLabeledById;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002317 mWindowId = other.mWindowId;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002318 mConnectionId = other.mConnectionId;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07002319 mBoundsInParent.set(other.mBoundsInParent);
2320 mBoundsInScreen.set(other.mBoundsInScreen);
2321 mPackageName = other.mPackageName;
2322 mClassName = other.mClassName;
2323 mText = other.mText;
2324 mContentDescription = other.mContentDescription;
Svetoslav22431a32013-02-05 14:30:19 -08002325 mViewIdResourceName = other.mViewIdResourceName;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07002326 mActions= other.mActions;
2327 mBooleanProperties = other.mBooleanProperties;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002328 mMovementGranularities = other.mMovementGranularities;
Alan Viverettef0aed092013-11-06 15:33:03 -08002329
2330 final LongArray otherChildNodeIds = other.mChildNodeIds;
2331 if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
2332 if (mChildNodeIds == null) {
2333 mChildNodeIds = otherChildNodeIds.clone();
2334 } else {
2335 mChildNodeIds.addAll(otherChildNodeIds);
2336 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002337 }
Alan Viverettef0aed092013-11-06 15:33:03 -08002338
Svetoslavbcc46a02013-02-06 11:56:00 -08002339 mTextSelectionStart = other.mTextSelectionStart;
2340 mTextSelectionEnd = other.mTextSelectionEnd;
Svetoslav6254f482013-06-04 17:22:14 -07002341 mInputType = other.mInputType;
Alan Viverette77e9a282013-09-12 17:16:09 -07002342 mLiveRegion = other.mLiveRegion;
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002343 if (other.mExtras != null && !other.mExtras.isEmpty()) {
2344 getExtras().putAll(other.mExtras);
Svetoslav6254f482013-06-04 17:22:14 -07002345 }
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07002346 mRangeInfo = (other.mRangeInfo != null)
2347 ? RangeInfo.obtain(other.mRangeInfo) : null;
2348 mCollectionInfo = (other.mCollectionInfo != null)
2349 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
2350 mCollectionItemInfo = (other.mCollectionItemInfo != null)
2351 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07002352 }
2353
2354 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002355 * Creates a new instance from a {@link Parcel}.
2356 *
2357 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
2358 */
2359 private void initFromParcel(Parcel parcel) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002360 mSealed = (parcel.readInt() == 1);
Svetoslav Ganov02107852011-10-03 17:06:56 -07002361 mSourceNodeId = parcel.readLong();
2362 mWindowId = parcel.readInt();
2363 mParentNodeId = parcel.readLong();
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002364 mLabelForId = parcel.readLong();
2365 mLabeledById = parcel.readLong();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002366 mConnectionId = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002367
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002368 final int childrenSize = parcel.readInt();
Alan Viverettef0aed092013-11-06 15:33:03 -08002369 if (childrenSize <= 0) {
2370 mChildNodeIds = null;
2371 } else {
2372 mChildNodeIds = new LongArray(childrenSize);
2373 for (int i = 0; i < childrenSize; i++) {
2374 final long childId = parcel.readLong();
2375 mChildNodeIds.add(childId);
2376 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002377 }
2378
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002379 mBoundsInParent.top = parcel.readInt();
2380 mBoundsInParent.bottom = parcel.readInt();
2381 mBoundsInParent.left = parcel.readInt();
2382 mBoundsInParent.right = parcel.readInt();
2383
2384 mBoundsInScreen.top = parcel.readInt();
2385 mBoundsInScreen.bottom = parcel.readInt();
2386 mBoundsInScreen.left = parcel.readInt();
2387 mBoundsInScreen.right = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002388
2389 mActions = parcel.readInt();
2390
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002391 mMovementGranularities = parcel.readInt();
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002392
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002393 mBooleanProperties = parcel.readInt();
2394
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002395 mPackageName = parcel.readCharSequence();
2396 mClassName = parcel.readCharSequence();
2397 mText = parcel.readCharSequence();
2398 mContentDescription = parcel.readCharSequence();
Svetoslav9fa1ee52013-04-22 12:43:03 -07002399 mViewIdResourceName = parcel.readString();
Svetoslavbcc46a02013-02-06 11:56:00 -08002400
2401 mTextSelectionStart = parcel.readInt();
2402 mTextSelectionEnd = parcel.readInt();
Svetoslav3577a282013-06-06 14:09:10 -07002403
Svetoslav6254f482013-06-04 17:22:14 -07002404 mInputType = parcel.readInt();
Alan Viverette77e9a282013-09-12 17:16:09 -07002405 mLiveRegion = parcel.readInt();
Svetoslav6254f482013-06-04 17:22:14 -07002406
2407 if (parcel.readInt() == 1) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002408 getExtras().putAll(parcel.readBundle());
Svetoslav6254f482013-06-04 17:22:14 -07002409 }
Svetoslav3577a282013-06-06 14:09:10 -07002410
2411 if (parcel.readInt() == 1) {
2412 mRangeInfo = RangeInfo.obtain(
2413 parcel.readInt(),
2414 parcel.readFloat(),
2415 parcel.readFloat(),
2416 parcel.readFloat());
2417 }
2418
2419 if (parcel.readInt() == 1) {
2420 mCollectionInfo = CollectionInfo.obtain(
2421 parcel.readInt(),
2422 parcel.readInt(),
2423 parcel.readInt() == 1);
2424 }
2425
2426 if (parcel.readInt() == 1) {
2427 mCollectionItemInfo = CollectionItemInfo.obtain(
2428 parcel.readInt(),
2429 parcel.readInt(),
2430 parcel.readInt(),
2431 parcel.readInt(),
2432 parcel.readInt() == 1);
2433 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002434 }
2435
2436 /**
2437 * Clears the state of this instance.
2438 */
2439 private void clear() {
2440 mSealed = false;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -08002441 mSourceNodeId = ROOT_NODE_ID;
2442 mParentNodeId = ROOT_NODE_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002443 mLabelForId = ROOT_NODE_ID;
2444 mLabeledById = ROOT_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08002445 mWindowId = UNDEFINED;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002446 mConnectionId = UNDEFINED;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002447 mMovementGranularities = 0;
Alan Viverettef0aed092013-11-06 15:33:03 -08002448 if (mChildNodeIds != null) {
2449 mChildNodeIds.clear();
2450 }
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002451 mBoundsInParent.set(0, 0, 0, 0);
2452 mBoundsInScreen.set(0, 0, 0, 0);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002453 mBooleanProperties = 0;
2454 mPackageName = null;
2455 mClassName = null;
2456 mText = null;
2457 mContentDescription = null;
Svetoslav22431a32013-02-05 14:30:19 -08002458 mViewIdResourceName = null;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002459 mActions = 0;
Svetoslavbcc46a02013-02-06 11:56:00 -08002460 mTextSelectionStart = UNDEFINED;
2461 mTextSelectionEnd = UNDEFINED;
Svetoslav6254f482013-06-04 17:22:14 -07002462 mInputType = InputType.TYPE_NULL;
Alan Viverette77e9a282013-09-12 17:16:09 -07002463 mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002464 if (mExtras != null) {
2465 mExtras.clear();
Svetoslav6254f482013-06-04 17:22:14 -07002466 }
Svetoslav3577a282013-06-06 14:09:10 -07002467 if (mRangeInfo != null) {
2468 mRangeInfo.recycle();
2469 mRangeInfo = null;
2470 }
2471 if (mCollectionInfo != null) {
2472 mCollectionInfo.recycle();
2473 mCollectionInfo = null;
2474 }
2475 if (mCollectionItemInfo != null) {
2476 mCollectionItemInfo.recycle();
2477 mCollectionItemInfo = null;
2478 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002479 }
2480
2481 /**
2482 * Gets the human readable action symbolic name.
2483 *
2484 * @param action The action.
2485 * @return The symbolic name.
2486 */
2487 private static String getActionSymbolicName(int action) {
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002488 switch (action) {
2489 case ACTION_FOCUS:
2490 return "ACTION_FOCUS";
2491 case ACTION_CLEAR_FOCUS:
2492 return "ACTION_CLEAR_FOCUS";
2493 case ACTION_SELECT:
2494 return "ACTION_SELECT";
2495 case ACTION_CLEAR_SELECTION:
2496 return "ACTION_CLEAR_SELECTION";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07002497 case ACTION_CLICK:
2498 return "ACTION_CLICK";
2499 case ACTION_LONG_CLICK:
2500 return "ACTION_LONG_CLICK";
2501 case ACTION_ACCESSIBILITY_FOCUS:
2502 return "ACTION_ACCESSIBILITY_FOCUS";
2503 case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
2504 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002505 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
2506 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
2507 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
2508 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07002509 case ACTION_NEXT_HTML_ELEMENT:
2510 return "ACTION_NEXT_HTML_ELEMENT";
2511 case ACTION_PREVIOUS_HTML_ELEMENT:
2512 return "ACTION_PREVIOUS_HTML_ELEMENT";
Svetoslav Ganova1dc7612012-05-10 04:14:53 -07002513 case ACTION_SCROLL_FORWARD:
2514 return "ACTION_SCROLL_FORWARD";
2515 case ACTION_SCROLL_BACKWARD:
2516 return "ACTION_SCROLL_BACKWARD";
Svetoslav Ganov242724e2013-02-01 14:42:18 -08002517 case ACTION_CUT:
2518 return "ACTION_CUT";
2519 case ACTION_COPY:
2520 return "ACTION_COPY";
2521 case ACTION_PASTE:
2522 return "ACTION_PASTE";
2523 case ACTION_SET_SELECTION:
2524 return "ACTION_SET_SELECTION";
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002525 default:
Svetoslav Ganov242724e2013-02-01 14:42:18 -08002526 return"ACTION_UNKNOWN";
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002527 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002528 }
2529
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002530 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002531 * Gets the human readable movement granularity symbolic name.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002532 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002533 * @param granularity The granularity.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002534 * @return The symbolic name.
2535 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002536 private static String getMovementGranularitySymbolicName(int granularity) {
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002537 switch (granularity) {
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002538 case MOVEMENT_GRANULARITY_CHARACTER:
2539 return "MOVEMENT_GRANULARITY_CHARACTER";
2540 case MOVEMENT_GRANULARITY_WORD:
2541 return "MOVEMENT_GRANULARITY_WORD";
2542 case MOVEMENT_GRANULARITY_LINE:
2543 return "MOVEMENT_GRANULARITY_LINE";
2544 case MOVEMENT_GRANULARITY_PARAGRAPH:
2545 return "MOVEMENT_GRANULARITY_PARAGRAPH";
2546 case MOVEMENT_GRANULARITY_PAGE:
2547 return "MOVEMENT_GRANULARITY_PAGE";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002548 default:
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002549 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002550 }
2551 }
2552
Svetoslav Ganov02107852011-10-03 17:06:56 -07002553 private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -08002554 return (mWindowId != UNDEFINED
2555 && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED
2556 && mConnectionId != UNDEFINED);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002557 }
2558
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002559 @Override
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07002560 public boolean equals(Object object) {
2561 if (this == object) {
2562 return true;
2563 }
2564 if (object == null) {
2565 return false;
2566 }
2567 if (getClass() != object.getClass()) {
2568 return false;
2569 }
2570 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002571 if (mSourceNodeId != other.mSourceNodeId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07002572 return false;
2573 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07002574 if (mWindowId != other.mWindowId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07002575 return false;
2576 }
2577 return true;
2578 }
2579
2580 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002581 public int hashCode() {
2582 final int prime = 31;
2583 int result = 1;
Svetoslav Ganov02107852011-10-03 17:06:56 -07002584 result = prime * result + getAccessibilityViewId(mSourceNodeId);
2585 result = prime * result + getVirtualDescendantId(mSourceNodeId);
2586 result = prime * result + mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002587 return result;
2588 }
2589
2590 @Override
2591 public String toString() {
2592 StringBuilder builder = new StringBuilder();
2593 builder.append(super.toString());
2594
2595 if (DEBUG) {
Svetoslav Ganov02107852011-10-03 17:06:56 -07002596 builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
2597 builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
2598 builder.append("; mParentNodeId: " + mParentNodeId);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002599
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002600 int granularities = mMovementGranularities;
2601 builder.append("; MovementGranularities: [");
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002602 while (granularities != 0) {
2603 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
2604 granularities &= ~granularity;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07002605 builder.append(getMovementGranularitySymbolicName(granularity));
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07002606 if (granularities != 0) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002607 builder.append(", ");
2608 }
2609 }
2610 builder.append("]");
2611
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002612 builder.append("; childAccessibilityIds: [");
Alan Viverettef0aed092013-11-06 15:33:03 -08002613 final LongArray childIds = mChildNodeIds;
2614 if (childIds != null) {
2615 for (int i = 0, count = childIds.size(); i < count; i++) {
2616 builder.append(childIds.get(i));
2617 if (i < count - 1) {
2618 builder.append(", ");
2619 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002620 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07002621 }
2622 builder.append("]");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002623 }
2624
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002625 builder.append("; boundsInParent: " + mBoundsInParent);
2626 builder.append("; boundsInScreen: " + mBoundsInScreen);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002627
2628 builder.append("; packageName: ").append(mPackageName);
2629 builder.append("; className: ").append(mClassName);
2630 builder.append("; text: ").append(mText);
2631 builder.append("; contentDescription: ").append(mContentDescription);
Svetoslav22431a32013-02-05 14:30:19 -08002632 builder.append("; viewIdResName: ").append(mViewIdResourceName);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002633
2634 builder.append("; checkable: ").append(isCheckable());
2635 builder.append("; checked: ").append(isChecked());
2636 builder.append("; focusable: ").append(isFocusable());
2637 builder.append("; focused: ").append(isFocused());
2638 builder.append("; selected: ").append(isSelected());
2639 builder.append("; clickable: ").append(isClickable());
2640 builder.append("; longClickable: ").append(isLongClickable());
2641 builder.append("; enabled: ").append(isEnabled());
2642 builder.append("; password: ").append(isPassword());
Svetoslav Ganova0156172011-06-26 17:55:44 -07002643 builder.append("; scrollable: " + isScrollable());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002644
2645 builder.append("; [");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002646 for (int actionBits = mActions; actionBits != 0;) {
2647 final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
2648 actionBits &= ~action;
2649 builder.append(getActionSymbolicName(action));
2650 if (actionBits != 0) {
2651 builder.append(", ");
2652 }
2653 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002654 builder.append("]");
2655
2656 return builder.toString();
2657 }
2658
2659 /**
Svetoslav3577a282013-06-06 14:09:10 -07002660 * Class with information if a node is a range. Use
Scott Main96844ed2013-10-18 14:43:02 -07002661 * {@link RangeInfo#obtain(int, float, float, float)} to get an instance.
Svetoslav3577a282013-06-06 14:09:10 -07002662 */
2663 public static final class RangeInfo {
2664 private static final int MAX_POOL_SIZE = 10;
2665
2666 /** Range type: integer. */
2667 public static final int RANGE_TYPE_INT = 0;
2668 /** Range type: float. */
2669 public static final int RANGE_TYPE_FLOAT = 1;
2670 /** Range type: percent with values from zero to one.*/
2671 public static final int RANGE_TYPE_PERCENT = 2;
2672
2673 private static final SynchronizedPool<RangeInfo> sPool =
2674 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
2675
2676 private int mType;
2677 private float mMin;
2678 private float mMax;
2679 private float mCurrent;
2680
2681 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07002682 * Obtains a pooled instance that is a clone of another one.
2683 *
2684 * @param other The instance to clone.
2685 *
2686 * @hide
2687 */
2688 public static RangeInfo obtain(RangeInfo other) {
2689 return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
2690 }
2691
2692 /**
Svetoslav3577a282013-06-06 14:09:10 -07002693 * Obtains a pooled instance.
2694 *
2695 * @param type The type of the range.
2696 * @param min The min value.
2697 * @param max The max value.
2698 * @param current The current value.
2699 */
2700 public static RangeInfo obtain(int type, float min, float max, float current) {
2701 RangeInfo info = sPool.acquire();
2702 return (info != null) ? info : new RangeInfo(type, min, max, current);
2703 }
2704
2705 /**
2706 * Creates a new range.
2707 *
2708 * @param type The type of the range.
2709 * @param min The min value.
2710 * @param max The max value.
2711 * @param current The current value.
2712 */
2713 private RangeInfo(int type, float min, float max, float current) {
2714 mType = type;
2715 mMin = min;
2716 mMax = max;
2717 mCurrent = current;
2718 }
2719
2720 /**
2721 * Gets the range type.
2722 *
2723 * @return The range type.
2724 *
2725 * @see #RANGE_TYPE_INT
2726 * @see #RANGE_TYPE_FLOAT
2727 * @see #RANGE_TYPE_PERCENT
2728 */
2729 public int getType() {
2730 return mType;
2731 }
2732
2733 /**
2734 * Gets the min value.
2735 *
2736 * @return The min value.
2737 */
2738 public float getMin() {
2739 return mMin;
2740 }
2741
2742 /**
2743 * Gets the max value.
2744 *
2745 * @return The max value.
2746 */
2747 public float getMax() {
2748 return mMax;
2749 }
2750
2751 /**
2752 * Gets the current value.
2753 *
2754 * @return The current value.
2755 */
2756 public float getCurrent() {
2757 return mCurrent;
2758 }
2759
2760 /**
2761 * Recycles this instance.
2762 */
2763 void recycle() {
2764 clear();
2765 sPool.release(this);
2766 }
2767
2768 private void clear() {
2769 mType = 0;
2770 mMin = 0;
2771 mMax = 0;
2772 mCurrent = 0;
2773 }
2774 }
2775
2776 /**
2777 * Class with information if a node is a collection. Use
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002778 * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance.
2779 * <p>
2780 * A collection of items has rows and columns and may be hierarchical.
2781 * For example, a horizontal list is a collection with one column, as
2782 * many rows as the list items, and is not hierarchical; A table is a
2783 * collection with several rows, several columns, and is not hierarchical;
2784 * A vertical tree is a hierarchical collection with one column and
2785 * as many rows as the first level children.
2786 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07002787 */
2788 public static final class CollectionInfo {
2789 private static final int MAX_POOL_SIZE = 20;
2790
2791 private static final SynchronizedPool<CollectionInfo> sPool =
2792 new SynchronizedPool<CollectionInfo>(MAX_POOL_SIZE);
2793
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002794 private int mRowCount;
2795 private int mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07002796 private boolean mHierarchical;
2797
2798 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07002799 * Obtains a pooled instance that is a clone of another one.
2800 *
2801 * @param other The instance to clone.
2802 *
2803 * @hide
2804 */
2805 public static CollectionInfo obtain(CollectionInfo other) {
2806 return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
2807 other.mHierarchical);
2808 }
2809
2810 /**
Svetoslav3577a282013-06-06 14:09:10 -07002811 * Obtains a pooled instance.
2812 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002813 * @param rowCount The number of rows.
2814 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07002815 * @param hierarchical Whether the collection is hierarchical.
2816 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002817 public static CollectionInfo obtain(int rowCount, int columnCount,
Svetoslav3577a282013-06-06 14:09:10 -07002818 boolean hierarchical) {
2819 CollectionInfo info = sPool.acquire();
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002820 return (info != null) ? info : new CollectionInfo(rowCount,
2821 columnCount, hierarchical);
Svetoslav3577a282013-06-06 14:09:10 -07002822 }
2823
2824 /**
2825 * Creates a new instance.
2826 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002827 * @param rowCount The number of rows.
2828 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07002829 * @param hierarchical Whether the collection is hierarchical.
2830 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002831 private CollectionInfo(int rowCount, int columnCount,
Svetoslav3577a282013-06-06 14:09:10 -07002832 boolean hierarchical) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002833 mRowCount = rowCount;
2834 mColumnCount = columnCount;
Svetoslav3577a282013-06-06 14:09:10 -07002835 mHierarchical = hierarchical;
2836 }
2837
2838 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002839 * Gets the number of rows.
Svetoslav3577a282013-06-06 14:09:10 -07002840 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002841 * @return The row count.
Svetoslav3577a282013-06-06 14:09:10 -07002842 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002843 public int getRowCount() {
2844 return mRowCount;
Svetoslav3577a282013-06-06 14:09:10 -07002845 }
2846
2847 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002848 * Gets the number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07002849 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002850 * @return The column count.
Svetoslav3577a282013-06-06 14:09:10 -07002851 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002852 public int getColumnCount() {
2853 return mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07002854 }
2855
2856 /**
2857 * Gets if the collection is a hierarchically ordered.
2858 *
2859 * @return Whether the collection is hierarchical.
2860 */
2861 public boolean isHierarchical() {
2862 return mHierarchical;
2863 }
2864
2865 /**
2866 * Recycles this instance.
2867 */
2868 void recycle() {
2869 clear();
2870 sPool.release(this);
2871 }
2872
2873 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002874 mRowCount = 0;
2875 mColumnCount = 0;
Svetoslav3577a282013-06-06 14:09:10 -07002876 mHierarchical = false;
2877 }
2878 }
2879
2880 /**
2881 * Class with information if a node is a collection item. Use
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002882 * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
2883 * to get an instance.
2884 * <p>
2885 * A collection item is contained in a collection, it starts at
2886 * a given row and column in the collection, and spans one or
2887 * more rows and columns. For example, a header of two related
2888 * table columns starts at the first row and the first column,
2889 * spans one row and two columns.
2890 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07002891 */
2892 public static final class CollectionItemInfo {
2893 private static final int MAX_POOL_SIZE = 20;
2894
2895 private static final SynchronizedPool<CollectionItemInfo> sPool =
2896 new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
2897
2898 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07002899 * Obtains a pooled instance that is a clone of another one.
2900 *
2901 * @param other The instance to clone.
2902 *
2903 * @hide
2904 */
2905 public static CollectionItemInfo obtain(CollectionItemInfo other) {
2906 return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
2907 other.mColumnIndex, other.mColumnSpan, other.mHeading);
2908 }
2909
2910 /**
Svetoslav3577a282013-06-06 14:09:10 -07002911 * Obtains a pooled instance.
2912 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002913 * @param rowIndex The row index at which the item is located.
2914 * @param rowSpan The number of rows the item spans.
2915 * @param columnIndex The column index at which the item is located.
2916 * @param columnSpan The number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07002917 * @param heading Whether the item is a heading.
2918 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002919 public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
2920 int columnIndex, int columnSpan, boolean heading) {
Svetoslav3577a282013-06-06 14:09:10 -07002921 CollectionItemInfo info = sPool.acquire();
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002922 return (info != null) ? info : new CollectionItemInfo(rowIndex,
2923 rowSpan, columnIndex, columnSpan, heading);
Svetoslav3577a282013-06-06 14:09:10 -07002924 }
2925
2926 private boolean mHeading;
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002927 private int mColumnIndex;
2928 private int mRowIndex;
2929 private int mColumnSpan;
2930 private int mRowSpan;
Svetoslav3577a282013-06-06 14:09:10 -07002931
2932 /**
2933 * Creates a new instance.
2934 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002935 * @param rowIndex The row index at which the item is located.
2936 * @param rowSpan The number of rows the item spans.
2937 * @param columnIndex The column index at which the item is located.
2938 * @param columnSpan The number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07002939 * @param heading Whether the item is a heading.
2940 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002941 private CollectionItemInfo(int rowIndex, int rowSpan,
2942 int columnIndex, int columnSpan, boolean heading) {
2943 mRowIndex = rowIndex;
2944 mRowSpan = rowSpan;
2945 mColumnIndex = columnIndex;
2946 mColumnSpan = columnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07002947 mHeading = heading;
2948 }
2949
2950 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002951 * Gets the column index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07002952 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002953 * @return The column index.
Svetoslav3577a282013-06-06 14:09:10 -07002954 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002955 public int getColumnIndex() {
2956 return mColumnIndex;
Svetoslav3577a282013-06-06 14:09:10 -07002957 }
2958
2959 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002960 * Gets the row index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07002961 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002962 * @return The row index.
Svetoslav3577a282013-06-06 14:09:10 -07002963 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002964 public int getRowIndex() {
2965 return mRowIndex;
Svetoslav3577a282013-06-06 14:09:10 -07002966 }
2967
2968 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002969 * Gets the number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07002970 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002971 * @return The column span.
Svetoslav3577a282013-06-06 14:09:10 -07002972 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002973 public int getColumnSpan() {
2974 return mColumnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07002975 }
2976
2977 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002978 * Gets the number of rows the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07002979 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002980 * @return The row span.
Svetoslav3577a282013-06-06 14:09:10 -07002981 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002982 public int getRowSpan() {
2983 return mRowSpan;
Svetoslav3577a282013-06-06 14:09:10 -07002984 }
2985
2986 /**
2987 * Gets if the collection item is a heading. For example, section
2988 * heading, table header, etc.
2989 *
2990 * @return If the item is a heading.
2991 */
2992 public boolean isHeading() {
2993 return mHeading;
2994 }
2995
2996 /**
2997 * Recycles this instance.
2998 */
2999 void recycle() {
3000 clear();
3001 sPool.release(this);
3002 }
3003
3004 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07003005 mColumnIndex = 0;
3006 mColumnSpan = 0;
3007 mRowIndex = 0;
3008 mRowSpan = 0;
Svetoslav3577a282013-06-06 14:09:10 -07003009 mHeading = false;
3010 }
3011 }
3012
3013 /**
Alan Viverettef0aed092013-11-06 15:33:03 -08003014 * @see android.os.Parcelable.Creator
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003015 */
3016 public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
3017 new Parcelable.Creator<AccessibilityNodeInfo>() {
Alan Viverettef0aed092013-11-06 15:33:03 -08003018 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003019 public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
3020 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
3021 info.initFromParcel(parcel);
3022 return info;
3023 }
3024
Alan Viverettef0aed092013-11-06 15:33:03 -08003025 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003026 public AccessibilityNodeInfo[] newArray(int size) {
3027 return new AccessibilityNodeInfo[size];
3028 }
3029 };
3030}