blob: 82a6de7019b204071fd667faa505542ba2402703 [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
Eugene Susla0eb2b6e2017-05-15 14:06:32 -070019import static com.android.internal.util.BitUtils.bitAt;
20import static com.android.internal.util.BitUtils.isBitSet;
21
Phil Weaverc2e28932016-12-08 12:29:25 -080022import static java.util.Collections.EMPTY_LIST;
23
Casey Burkhardt7ef48be2016-01-31 11:51:09 -080024import android.accessibilityservice.AccessibilityService;
Svetoslav Ganov80943d82013-01-02 10:25:37 -080025import android.accessibilityservice.AccessibilityServiceInfo;
Kristian Monsen74bc1942014-04-29 11:00:17 -070026import android.annotation.Nullable;
Phil Weaver62d20fa2016-09-15 11:05:55 -070027import android.annotation.TestApi;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070028import android.graphics.Rect;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -070029import android.os.Bundle;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070030import android.os.Parcel;
31import android.os.Parcelable;
Svetoslav6254f482013-06-04 17:22:14 -070032import android.text.InputType;
Phil Weaver193520e2016-12-13 09:39:06 -080033import android.text.Spannable;
Phil Weaver0ebe6bd2017-02-21 16:24:31 -080034import android.text.SpannableStringBuilder;
Phil Weaver193520e2016-12-13 09:39:06 -080035import android.text.Spanned;
Kristian Monsen74bc1942014-04-29 11:00:17 -070036import android.text.TextUtils;
Phil Weaver193520e2016-12-13 09:39:06 -080037import android.text.style.AccessibilityClickableSpan;
38import android.text.style.AccessibilityURLSpan;
39import android.text.style.ClickableSpan;
40import android.text.style.URLSpan;
Kristian Monsen74bc1942014-04-29 11:00:17 -070041import android.util.ArraySet;
Alan Viverettef0aed092013-11-06 15:33:03 -080042import android.util.LongArray;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -080043import android.util.Pools.SynchronizedPool;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070044import android.view.View;
45
Alan Viverette26c44ee2015-03-25 14:54:13 -070046import com.android.internal.R;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -070047import com.android.internal.util.CollectionUtils;
Alan Viverette26c44ee2015-03-25 14:54:13 -070048
Kristian Monsen74bc1942014-04-29 11:00:17 -070049import java.util.ArrayList;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070050import java.util.Collections;
51import java.util.List;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -070052import java.util.Objects;
Phil Weaverb010b122016-08-17 17:47:48 -070053import java.util.concurrent.atomic.AtomicInteger;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070054
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070055/**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070056 * This class represents a node of the window content as well as actions that
57 * can be requested from its source. From the point of view of an
Phil Weaver40ded282016-01-25 15:49:02 -080058 * {@link android.accessibilityservice.AccessibilityService} a window's content is
59 * presented as a tree of accessibility node infos, which may or may not map one-to-one
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070060 * to the view hierarchy. In other words, a custom view is free to report itself as
61 * a tree of accessibility node info.
62 * </p>
63 * <p>
64 * Once an accessibility node info is delivered to an accessibility service it is
65 * made immutable and calling a state mutation method generates an error.
66 * </p>
67 * <p>
68 * Please refer to {@link android.accessibilityservice.AccessibilityService} for
69 * details about how to obtain a handle to window content as a tree of accessibility
Phil Weaver40ded282016-01-25 15:49:02 -080070 * node info as well as details about the security model.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070071 * </p>
Joe Fernandeze1302ed2012-02-06 14:30:15 -080072 * <div class="special reference">
73 * <h3>Developer Guides</h3>
74 * <p>For more information about making applications accessible, read the
75 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
76 * developer guide.</p>
77 * </div>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070078 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070079 * @see android.accessibilityservice.AccessibilityService
80 * @see AccessibilityEvent
81 * @see AccessibilityManager
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070082 */
83public class AccessibilityNodeInfo implements Parcelable {
84
85 private static final boolean DEBUG = false;
86
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080087 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -080088 public static final int UNDEFINED_CONNECTION_ID = -1;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080089
90 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -080091 public static final int UNDEFINED_SELECTION_INDEX = -1;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080092
93 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -080094 public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE;
95
96 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -080097 public static final int ROOT_ITEM_ID = Integer.MAX_VALUE - 1;
Svetoslav8e3feb12014-02-24 13:46:47 -080098
99 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -0800100 public static final long UNDEFINED_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800101
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800102 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -0800103 public static final long ROOT_NODE_ID = makeNodeId(ROOT_ITEM_ID,
104 AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav1e0d4af2014-04-10 17:41:29 -0700105
106 /** @hide */
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800107 public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
108
109 /** @hide */
110 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
111
112 /** @hide */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700113 public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
114
115 /** @hide */
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800116 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
117
118 /** @hide */
119 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800120
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700121 // Actions.
122
123 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700124 * Action that gives input focus to the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700125 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700126 public static final int ACTION_FOCUS = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700127
128 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700129 * Action that clears input focus of the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700130 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700131 public static final int ACTION_CLEAR_FOCUS = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700132
133 /**
134 * Action that selects the node.
135 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700136 public static final int ACTION_SELECT = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700137
138 /**
Kristian Monsen74bc1942014-04-29 11:00:17 -0700139 * Action that deselects the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700140 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700141 public static final int ACTION_CLEAR_SELECTION = 0x00000008;
142
143 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700144 * Action that clicks on the node info.
Maxim Bogatov219b41d2015-05-01 14:00:24 -0700145 *
146 * See {@link AccessibilityAction#ACTION_CLICK}
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700147 */
148 public static final int ACTION_CLICK = 0x00000010;
149
150 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700151 * Action that long clicks on the node.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700152 */
153 public static final int ACTION_LONG_CLICK = 0x00000020;
154
155 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700156 * Action that gives accessibility focus to the node.
157 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700158 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700159
160 /**
161 * Action that clears accessibility focus of the node.
162 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700163 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700164
165 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700166 * Action that requests to go to the next entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700167 * at a given movement granularity. For example, move to the next character,
168 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700169 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800170 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
171 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
172 * <strong>Example:</strong> Move to the previous character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700173 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700174 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700175 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
176 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800177 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
178 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700179 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700180 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700181 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700182 *
Svetoslav7c512842013-01-30 23:02:08 -0800183 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
184 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
185 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700186 * @see #setMovementGranularities(int)
187 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700188 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700189 * @see #MOVEMENT_GRANULARITY_CHARACTER
190 * @see #MOVEMENT_GRANULARITY_WORD
191 * @see #MOVEMENT_GRANULARITY_LINE
192 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
193 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700194 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700195 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700196
197 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700198 * Action that requests to go to the previous entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700199 * at a given movement granularity. For example, move to the next character,
200 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700201 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800202 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
203 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
204 * <strong>Example:</strong> Move to the next character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700205 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700206 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700207 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
208 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800209 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
210 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700211 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
212 * arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700213 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700214 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700215 *
Svetoslav7c512842013-01-30 23:02:08 -0800216 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
217 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
218 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700219 * @see #setMovementGranularities(int)
220 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700221 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700222 * @see #MOVEMENT_GRANULARITY_CHARACTER
223 * @see #MOVEMENT_GRANULARITY_WORD
224 * @see #MOVEMENT_GRANULARITY_LINE
225 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
226 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700227 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700228 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700229
230 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700231 * Action to move to the next HTML element of a given type. For example, move
232 * to the BUTTON, INPUT, TABLE, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700233 * <p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700234 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
235 * <strong>Example:</strong>
236 * <code><pre><p>
237 * Bundle arguments = new Bundle();
238 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
239 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
240 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700241 * </p>
242 */
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700243 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
244
245 /**
246 * Action to move to the previous HTML element of a given type. For example, move
247 * to the BUTTON, INPUT, TABLE, etc.
248 * <p>
249 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
250 * <strong>Example:</strong>
251 * <code><pre><p>
252 * Bundle arguments = new Bundle();
253 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
254 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
255 * </code></pre></p>
256 * </p>
257 */
258 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
259
260 /**
Svetoslav Ganova1dc7612012-05-10 04:14:53 -0700261 * Action to scroll the node content forward.
262 */
263 public static final int ACTION_SCROLL_FORWARD = 0x00001000;
264
265 /**
266 * Action to scroll the node content backward.
267 */
268 public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
269
270 /**
Svetoslav7c512842013-01-30 23:02:08 -0800271 * Action to copy the current selection to the clipboard.
272 */
273 public static final int ACTION_COPY = 0x00004000;
274
275 /**
276 * Action to paste the current clipboard content.
277 */
278 public static final int ACTION_PASTE = 0x00008000;
279
280 /**
281 * Action to cut the current selection and place it to the clipboard.
282 */
283 public static final int ACTION_CUT = 0x00010000;
284
285 /**
286 * Action to set the selection. Performing this action with no arguments
287 * clears the selection.
288 * <p>
Alan Viverette23f44322015-04-06 16:04:56 -0700289 * <strong>Arguments:</strong>
290 * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
Svetoslav7c512842013-01-30 23:02:08 -0800291 * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
292 * <strong>Example:</strong>
293 * <code><pre><p>
294 * Bundle arguments = new Bundle();
295 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
296 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
297 * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
298 * </code></pre></p>
299 * </p>
300 *
301 * @see #ACTION_ARGUMENT_SELECTION_START_INT
302 * @see #ACTION_ARGUMENT_SELECTION_END_INT
303 */
304 public static final int ACTION_SET_SELECTION = 0x00020000;
305
306 /**
Svetoslav3577a282013-06-06 14:09:10 -0700307 * Action to expand an expandable node.
308 */
309 public static final int ACTION_EXPAND = 0x00040000;
310
311 /**
312 * Action to collapse an expandable node.
313 */
314 public static final int ACTION_COLLAPSE = 0x00080000;
315
316 /**
317 * Action to dismiss a dismissable node.
318 */
319 public static final int ACTION_DISMISS = 0x00100000;
320
Guang Zhu4cd353c2014-02-12 19:54:30 -0800321 /**
322 * Action that sets the text of the node. Performing the action without argument, using <code>
323 * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
324 * cursor at the end of text.
325 * <p>
Alan Viverette23f44322015-04-06 16:04:56 -0700326 * <strong>Arguments:</strong>
327 * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
Guang Zhu4cd353c2014-02-12 19:54:30 -0800328 * <strong>Example:</strong>
329 * <code><pre><p>
330 * Bundle arguments = new Bundle();
331 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
332 * "android");
333 * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
334 * </code></pre></p>
335 */
336 public static final int ACTION_SET_TEXT = 0x00200000;
337
Kristian Monsen74bc1942014-04-29 11:00:17 -0700338 private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
339
340 /**
341 * Mask to see if the value is larger than the largest ACTION_ constant
342 */
343 private static final int ACTION_TYPE_MASK = 0xFF000000;
344
Svetoslav3577a282013-06-06 14:09:10 -0700345 // Action arguments
346
347 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700348 * Argument for which movement granularity to be used when traversing the node text.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700349 * <p>
350 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700351 * <strong>Actions:</strong>
352 * <ul>
353 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
354 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
355 * </ul>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700356 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800357 *
Alan Viverette23f44322015-04-06 16:04:56 -0700358 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
359 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700360 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700361 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
Svetoslav7c512842013-01-30 23:02:08 -0800362 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700363
364 /**
365 * Argument for which HTML element to get moving to the next/previous HTML element.
366 * <p>
367 * <strong>Type:</strong> String<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700368 * <strong>Actions:</strong>
369 * <ul>
370 * <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li>
371 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li>
372 * </ul>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700373 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800374 *
Alan Viverette23f44322015-04-06 16:04:56 -0700375 * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT
376 * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700377 */
378 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
Svetoslav7c512842013-01-30 23:02:08 -0800379 "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
380
381 /**
382 * Argument for whether when moving at granularity to extend the selection
383 * or to move it otherwise.
384 * <p>
385 * <strong>Type:</strong> boolean<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700386 * <strong>Actions:</strong>
387 * <ul>
388 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
389 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
390 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800391 *
Alan Viverette23f44322015-04-06 16:04:56 -0700392 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
393 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
Svetoslav7c512842013-01-30 23:02:08 -0800394 */
395 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
396 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
397
398 /**
399 * Argument for specifying the selection start.
400 * <p>
401 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700402 * <strong>Actions:</strong>
403 * <ul>
404 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
405 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800406 *
Alan Viverette23f44322015-04-06 16:04:56 -0700407 * @see AccessibilityAction#ACTION_SET_SELECTION
Svetoslav7c512842013-01-30 23:02:08 -0800408 */
409 public static final String ACTION_ARGUMENT_SELECTION_START_INT =
410 "ACTION_ARGUMENT_SELECTION_START_INT";
411
412 /**
413 * Argument for specifying the selection end.
414 * <p>
415 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700416 * <strong>Actions:</strong>
417 * <ul>
418 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
419 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800420 *
Alan Viverette23f44322015-04-06 16:04:56 -0700421 * @see AccessibilityAction#ACTION_SET_SELECTION
Svetoslav7c512842013-01-30 23:02:08 -0800422 */
423 public static final String ACTION_ARGUMENT_SELECTION_END_INT =
424 "ACTION_ARGUMENT_SELECTION_END_INT";
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700425
Guang Zhu4cd353c2014-02-12 19:54:30 -0800426 /**
Alan Viverette23f44322015-04-06 16:04:56 -0700427 * Argument for specifying the text content to set.
Guang Zhu4cd353c2014-02-12 19:54:30 -0800428 * <p>
429 * <strong>Type:</strong> CharSequence<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700430 * <strong>Actions:</strong>
431 * <ul>
432 * <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li>
433 * </ul>
Guang Zhu4cd353c2014-02-12 19:54:30 -0800434 *
Alan Viverette23f44322015-04-06 16:04:56 -0700435 * @see AccessibilityAction#ACTION_SET_TEXT
Guang Zhu4cd353c2014-02-12 19:54:30 -0800436 */
437 public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
438 "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
439
Alan Viverette23f44322015-04-06 16:04:56 -0700440 /**
441 * Argument for specifying the collection row to make visible on screen.
442 * <p>
443 * <strong>Type:</strong> int<br>
444 * <strong>Actions:</strong>
445 * <ul>
446 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
447 * </ul>
448 *
449 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
450 */
451 public static final String ACTION_ARGUMENT_ROW_INT =
452 "android.view.accessibility.action.ARGUMENT_ROW_INT";
453
454 /**
455 * Argument for specifying the collection column to make visible on screen.
456 * <p>
457 * <strong>Type:</strong> int<br>
458 * <strong>Actions:</strong>
459 * <ul>
460 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
461 * </ul>
462 *
463 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
464 */
465 public static final String ACTION_ARGUMENT_COLUMN_INT =
466 "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
467
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700468 /**
469 * Argument for specifying the progress value to set.
470 * <p>
471 * <strong>Type:</strong> float<br>
472 * <strong>Actions:</strong>
473 * <ul>
474 * <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li>
475 * </ul>
476 *
477 * @see AccessibilityAction#ACTION_SET_PROGRESS
478 */
479 public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
480 "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
481
Phil Weaver193520e2016-12-13 09:39:06 -0800482 /**
Phil Weaverf00cd142017-03-03 13:44:00 -0800483 * Argument for specifying the x coordinate to which to move a window.
484 * <p>
485 * <strong>Type:</strong> int<br>
486 * <strong>Actions:</strong>
487 * <ul>
488 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
489 * </ul>
490 *
491 * @see AccessibilityAction#ACTION_MOVE_WINDOW
492 */
493 public static final String ACTION_ARGUMENT_MOVE_WINDOW_X =
Phil Weaverbe2922f2017-04-28 14:58:35 -0700494 "ACTION_ARGUMENT_MOVE_WINDOW_X";
Phil Weaverf00cd142017-03-03 13:44:00 -0800495
496 /**
497 * Argument for specifying the y coordinate to which to move a window.
498 * <p>
499 * <strong>Type:</strong> int<br>
500 * <strong>Actions:</strong>
501 * <ul>
502 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
503 * </ul>
504 *
505 * @see AccessibilityAction#ACTION_MOVE_WINDOW
506 */
507 public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y =
Phil Weaverbe2922f2017-04-28 14:58:35 -0700508 "ACTION_ARGUMENT_MOVE_WINDOW_Y";
Phil Weaverf00cd142017-03-03 13:44:00 -0800509
510 /**
Phil Weaver193520e2016-12-13 09:39:06 -0800511 * Argument to pass the {@link AccessibilityClickableSpan}.
512 * For use with R.id.accessibilityActionClickOnClickableSpan
513 * @hide
514 */
515 public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
516 "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
517
Svetoslav3577a282013-06-06 14:09:10 -0700518 // Focus types
519
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700520 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700521 * The input focus.
522 */
523 public static final int FOCUS_INPUT = 1;
524
525 /**
526 * The accessibility focus.
527 */
528 public static final int FOCUS_ACCESSIBILITY = 2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700529
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700530 // Movement granularities
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700531
532 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700533 * Movement granularity bit for traversing the text of a node by character.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700534 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700535 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700536
537 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700538 * Movement granularity bit for traversing the text of a node by word.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700539 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700540 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700541
542 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700543 * Movement granularity bit for traversing the text of a node by line.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700544 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700545 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700546
547 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700548 * Movement granularity bit for traversing the text of a node by paragraph.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700549 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700550 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700551
552 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700553 * Movement granularity bit for traversing the text of a node by page.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700554 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700555 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700556
Phil Weaverc2e28932016-12-08 12:29:25 -0800557 /**
558 * Key used to request and locate extra data for text character location. This key requests that
559 * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with
560 * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two
561 * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and
562 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid
563 * inside the CharSequence returned by {@link #getText()}, and the length must be positive.
564 * <p>
565 * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this
566 * string as a key for {@link Bundle#getParcelableArray(String)}. The
567 * {@link android.graphics.RectF} will be null for characters that either do not exist or are
568 * off the screen.
569 *
570 * {@see #refreshWithExtraData(String, Bundle)}
571 */
572 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY =
573 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
574
575 /**
576 * Integer argument specifying the start index of the requested text location data. Must be
577 * valid inside the CharSequence returned by {@link #getText()}.
578 *
579 * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
580 */
581 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX =
582 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
583
584 /**
585 * Integer argument specifying the end index of the requested text location data. Must be
586 * positive.
587 *
588 * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}
589 */
590 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
591 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
592
593 /** @hide */
594 public static final String EXTRA_DATA_REQUESTED_KEY =
595 "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
596
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700597 // Boolean attributes.
598
Svetoslavbcc46a02013-02-06 11:56:00 -0800599 private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700600
Svetoslavbcc46a02013-02-06 11:56:00 -0800601 private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700602
Svetoslavbcc46a02013-02-06 11:56:00 -0800603 private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700604
Svetoslavbcc46a02013-02-06 11:56:00 -0800605 private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700606
Svetoslavbcc46a02013-02-06 11:56:00 -0800607 private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700608
Svetoslavbcc46a02013-02-06 11:56:00 -0800609 private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700610
Svetoslavbcc46a02013-02-06 11:56:00 -0800611 private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700612
Svetoslavbcc46a02013-02-06 11:56:00 -0800613 private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700614
Svetoslavbcc46a02013-02-06 11:56:00 -0800615 private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700616
Svetoslavbcc46a02013-02-06 11:56:00 -0800617 private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200;
Svetoslav Ganova0156172011-06-26 17:55:44 -0700618
Svetoslavbcc46a02013-02-06 11:56:00 -0800619 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700620
Svetoslavbcc46a02013-02-06 11:56:00 -0800621 private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
622
623 private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -0700624
Alan Viverette77e9a282013-09-12 17:16:09 -0700625 private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
Svetoslav3577a282013-06-06 14:09:10 -0700626
Alan Viverette77e9a282013-09-12 17:16:09 -0700627 private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
Svetoslav3577a282013-06-06 14:09:10 -0700628
Alan Viverette77e9a282013-09-12 17:16:09 -0700629 private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
Svetoslav3577a282013-06-06 14:09:10 -0700630
Alan Viverette77e9a282013-09-12 17:16:09 -0700631 private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
Svetoslav3577a282013-06-06 14:09:10 -0700632
Mady Mellore8608912015-06-05 09:02:55 -0700633 private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 0x00020000;
Mady Mellore82067b2015-04-30 09:58:35 -0700634
Casey Burkhardt2d80ae42016-01-31 12:52:23 -0800635 private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
636
Phil Weaver776afc22016-12-21 10:55:13 -0800637 private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
638
Svetoslav Ganov02107852011-10-03 17:06:56 -0700639 /**
640 * Bits that provide the id of a virtual descendant of a view.
641 */
642 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700643 /**
644 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
645 * virtual descendant of a view. Such a descendant does not exist in the view
646 * hierarchy and is only reported via the accessibility APIs.
647 */
648 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
649
Phil Weaver62d20fa2016-09-15 11:05:55 -0700650 private static AtomicInteger sNumInstancesInUse;
Phil Weaverb010b122016-08-17 17:47:48 -0700651
Svetoslav Ganov02107852011-10-03 17:06:56 -0700652 /**
653 * Gets the accessibility view id which identifies a View in the view three.
654 *
655 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
656 * @return The accessibility view id part of the node id.
657 *
658 * @hide
659 */
660 public static int getAccessibilityViewId(long accessibilityNodeId) {
661 return (int) accessibilityNodeId;
662 }
663
664 /**
665 * Gets the virtual descendant id which identifies an imaginary view in a
666 * containing View.
667 *
668 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
669 * @return The virtual view id part of the node id.
670 *
671 * @hide
672 */
673 public static int getVirtualDescendantId(long accessibilityNodeId) {
674 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
675 >> VIRTUAL_DESCENDANT_ID_SHIFT);
676 }
677
678 /**
679 * Makes a node id by shifting the <code>virtualDescendantId</code>
680 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
681 * the bitwise or with the <code>accessibilityViewId</code>.
682 *
683 * @param accessibilityViewId A View accessibility id.
684 * @param virtualDescendantId A virtual descendant id.
685 * @return The node id.
686 *
687 * @hide
688 */
689 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
690 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
691 }
692
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700693 // Housekeeping.
694 private static final int MAX_POOL_SIZE = 50;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -0800695 private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -0700696 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -0800697
Eugene Susla0eb2b6e2017-05-15 14:06:32 -0700698 private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo();
699
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700700 private boolean mSealed;
701
702 // Data.
Phil Weaver23161e72017-04-19 12:16:36 -0700703 private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Phil Weaverf00cd142017-03-03 13:44:00 -0800704 private long mSourceNodeId = UNDEFINED_NODE_ID;
705 private long mParentNodeId = UNDEFINED_NODE_ID;
706 private long mLabelForId = UNDEFINED_NODE_ID;
707 private long mLabeledById = UNDEFINED_NODE_ID;
708 private long mTraversalBefore = UNDEFINED_NODE_ID;
709 private long mTraversalAfter = UNDEFINED_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800710
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700711 private int mBooleanProperties;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700712 private final Rect mBoundsInParent = new Rect();
713 private final Rect mBoundsInScreen = new Rect();
Phil Weaver1f222542016-01-08 11:49:32 -0800714 private int mDrawingOrderInParent;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700715
716 private CharSequence mPackageName;
717 private CharSequence mClassName;
Phil Weaver193520e2016-12-13 09:39:06 -0800718 // Hidden, unparceled value used to hold the original value passed to setText
719 private CharSequence mOriginalText;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700720 private CharSequence mText;
Phil Weaver776afc22016-12-21 10:55:13 -0800721 private CharSequence mHintText;
Alan Viverettefccbff52014-07-07 15:06:14 -0700722 private CharSequence mError;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700723 private CharSequence mContentDescription;
Svetoslav9fa1ee52013-04-22 12:43:03 -0700724 private String mViewIdResourceName;
Phil Weaverc2e28932016-12-08 12:29:25 -0800725 private ArrayList<String> mExtraDataKeys;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700726
Alan Viverettef0aed092013-11-06 15:33:03 -0800727 private LongArray mChildNodeIds;
Kristian Monsen74bc1942014-04-29 11:00:17 -0700728 private ArrayList<AccessibilityAction> mActions;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700729
Alan Viverette029942f2014-08-12 14:55:56 -0700730 private int mMaxTextLength = -1;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700731 private int mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700732
Svetoslav8e3feb12014-02-24 13:46:47 -0800733 private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
734 private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
Svetoslav6254f482013-06-04 17:22:14 -0700735 private int mInputType = InputType.TYPE_NULL;
Alan Viverette77e9a282013-09-12 17:16:09 -0700736 private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
Svetoslav6254f482013-06-04 17:22:14 -0700737
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -0700738 private Bundle mExtras;
Svetoslavbcc46a02013-02-06 11:56:00 -0800739
Svetoslav8e3feb12014-02-24 13:46:47 -0800740 private int mConnectionId = UNDEFINED_CONNECTION_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700741
Svetoslav3577a282013-06-06 14:09:10 -0700742 private RangeInfo mRangeInfo;
743 private CollectionInfo mCollectionInfo;
744 private CollectionItemInfo mCollectionItemInfo;
745
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700746 /**
747 * Hide constructor from clients.
748 */
749 private AccessibilityNodeInfo() {
750 /* do nothing */
751 }
752
753 /**
754 * Sets the source.
Svetoslav Ganov02107852011-10-03 17:06:56 -0700755 * <p>
756 * <strong>Note:</strong> Cannot be called from an
757 * {@link android.accessibilityservice.AccessibilityService}.
758 * This class is made immutable before being delivered to an AccessibilityService.
759 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700760 *
761 * @param source The info source.
762 */
763 public void setSource(View source) {
Phil Weaverf00cd142017-03-03 13:44:00 -0800764 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700765 }
766
767 /**
768 * Sets the source to be a virtual descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700769 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700770 * is set as the source.
771 * <p>
772 * A virtual descendant is an imaginary View that is reported as a part of the view
773 * hierarchy for accessibility purposes. This enables custom views that draw complex
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700774 * content to report themselves as a tree of virtual views, thus conveying their
Svetoslav Ganov02107852011-10-03 17:06:56 -0700775 * logical structure.
776 * </p>
777 * <p>
778 * <strong>Note:</strong> Cannot be called from an
779 * {@link android.accessibilityservice.AccessibilityService}.
780 * This class is made immutable before being delivered to an AccessibilityService.
781 * </p>
782 *
783 * @param root The root of the virtual subtree.
784 * @param virtualDescendantId The id of the virtual descendant.
785 */
786 public void setSource(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700787 enforceNotSealed();
Svetoslav8e3feb12014-02-24 13:46:47 -0800788 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700789 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -0800790 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700791 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700792 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700793
Svetoslav Ganov42138042012-03-20 11:51:39 -0700794 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700795 * Find the view that has the specified focus type. The search starts from
Svetoslav Ganov42138042012-03-20 11:51:39 -0700796 * the view represented by this node info.
797 *
798 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
799 * {@link #FOCUS_ACCESSIBILITY}.
800 * @return The node info of the focused view or null.
801 *
802 * @see #FOCUS_INPUT
803 * @see #FOCUS_ACCESSIBILITY
804 */
805 public AccessibilityNodeInfo findFocus(int focus) {
806 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700807 enforceValidFocusType(focus);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700808 if (!canPerformRequestOverConnection(mSourceNodeId)) {
809 return null;
810 }
811 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
812 mSourceNodeId, focus);
813 }
814
815 /**
816 * Searches for the nearest view in the specified direction that can take
817 * the input focus.
818 *
819 * @param direction The direction. Can be one of:
820 * {@link View#FOCUS_DOWN},
821 * {@link View#FOCUS_UP},
822 * {@link View#FOCUS_LEFT},
823 * {@link View#FOCUS_RIGHT},
824 * {@link View#FOCUS_FORWARD},
Svetoslav Ganov8ffe8b32012-06-15 10:31:31 -0700825 * {@link View#FOCUS_BACKWARD}.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700826 *
827 * @return The node info for the view that can take accessibility focus.
828 */
829 public AccessibilityNodeInfo focusSearch(int direction) {
830 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700831 enforceValidFocusDirection(direction);
Svetoslav Ganov42138042012-03-20 11:51:39 -0700832 if (!canPerformRequestOverConnection(mSourceNodeId)) {
833 return null;
834 }
835 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
836 mSourceNodeId, direction);
837 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700838
839 /**
840 * Gets the id of the window from which the info comes from.
841 *
842 * @return The window id.
843 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700844 public int getWindowId() {
Svetoslav Ganov02107852011-10-03 17:06:56 -0700845 return mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700846 }
847
848 /**
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800849 * Refreshes this info with the latest state of the view it represents.
850 * <p>
851 * <strong>Note:</strong> If this method returns false this info is obsolete
852 * since it represents a view that is no longer in the view tree and should
853 * be recycled.
854 * </p>
Svetoslav6254f482013-06-04 17:22:14 -0700855 *
856 * @param bypassCache Whether to bypass the cache.
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800857 * @return Whether the refresh succeeded.
Svetoslav6254f482013-06-04 17:22:14 -0700858 *
859 * @hide
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800860 */
Phil Weaverc2e28932016-12-08 12:29:25 -0800861 public boolean refresh(Bundle arguments, boolean bypassCache) {
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800862 enforceSealed();
863 if (!canPerformRequestOverConnection(mSourceNodeId)) {
864 return false;
865 }
866 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
867 AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
Phil Weaverc2e28932016-12-08 12:29:25 -0800868 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments);
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800869 if (refreshedInfo == null) {
870 return false;
871 }
872 init(refreshedInfo);
873 refreshedInfo.recycle();
874 return true;
875 }
876
877 /**
Svetoslav6254f482013-06-04 17:22:14 -0700878 * Refreshes this info with the latest state of the view it represents.
Phil Weaverc2e28932016-12-08 12:29:25 -0800879 *
880 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
881 * by this node is no longer in the view tree (and thus this node is obsolete and should be
882 * recycled).
Svetoslav6254f482013-06-04 17:22:14 -0700883 */
884 public boolean refresh() {
Phil Weaverc2e28932016-12-08 12:29:25 -0800885 return refresh(null, true);
886 }
887
888 /**
889 * Refreshes this info with the latest state of the view it represents, and request new
890 * data be added by the View.
891 *
892 * @param extraDataKey A bitmask of the extra data requested. Data that must be requested
893 * with this mechanism is generally expensive to retrieve, so should only be
894 * requested when needed. See
895 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
896 * {@link #getAvailableExtraData()}.
897 * @param args A bundle of arguments for the request. These depend on the particular request.
898 *
899 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
900 * by this node is no longer in the view tree (and thus this node is obsolete and should be
901 * recycled).
902 */
903 public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
904 args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
905 return refresh(args, true);
Svetoslav6254f482013-06-04 17:22:14 -0700906 }
907
908 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800909 * Returns the array containing the IDs of this node's children.
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800910 *
911 * @hide
912 */
Alan Viverettef0aed092013-11-06 15:33:03 -0800913 public LongArray getChildNodeIds() {
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800914 return mChildNodeIds;
915 }
916
917 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800918 * Returns the id of the child at the specified index.
919 *
920 * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
921 * getChildCount()
922 * @hide
923 */
924 public long getChildId(int index) {
925 if (mChildNodeIds == null) {
926 throw new IndexOutOfBoundsException();
927 }
928 return mChildNodeIds.get(index);
929 }
930
931 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700932 * Gets the number of children.
933 *
934 * @return The child count.
935 */
936 public int getChildCount() {
Alan Viverettef0aed092013-11-06 15:33:03 -0800937 return mChildNodeIds == null ? 0 : mChildNodeIds.size();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700938 }
939
940 /**
941 * Get the child at given index.
942 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700943 * <strong>Note:</strong> It is a client responsibility to recycle the
944 * received info by calling {@link AccessibilityNodeInfo#recycle()}
945 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700946 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700947 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700948 * @param index The child index.
949 * @return The child node.
950 *
951 * @throws IllegalStateException If called outside of an AccessibilityService.
952 *
953 */
954 public AccessibilityNodeInfo getChild(int index) {
955 enforceSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -0800956 if (mChildNodeIds == null) {
957 return null;
958 }
Svetoslav Ganov02107852011-10-03 17:06:56 -0700959 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700960 return null;
961 }
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800962 final long childId = mChildNodeIds.get(index);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700963 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800964 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
Phil Weaverc2e28932016-12-08 12:29:25 -0800965 childId, false, FLAG_PREFETCH_DESCENDANTS, null);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700966 }
967
968 /**
969 * Adds a child.
970 * <p>
Svetoslav Ganov02107852011-10-03 17:06:56 -0700971 * <strong>Note:</strong> Cannot be called from an
972 * {@link android.accessibilityservice.AccessibilityService}.
973 * This class is made immutable before being delivered to an AccessibilityService.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700974 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700975 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700976 * @param child The child.
977 *
978 * @throws IllegalStateException If called from an AccessibilityService.
979 */
980 public void addChild(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -0800981 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, true);
Alan Viverettef0aed092013-11-06 15:33:03 -0800982 }
983
984 /**
985 * Unchecked version of {@link #addChild(View)} that does not verify
986 * uniqueness. For framework use only.
987 *
988 * @hide
989 */
990 public void addChildUnchecked(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -0800991 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, false);
Alan Viverettef0aed092013-11-06 15:33:03 -0800992 }
993
994 /**
995 * Removes a child. If the child was not previously added to the node,
996 * calling this method has no effect.
997 * <p>
998 * <strong>Note:</strong> Cannot be called from an
999 * {@link android.accessibilityservice.AccessibilityService}.
1000 * This class is made immutable before being delivered to an AccessibilityService.
1001 * </p>
1002 *
1003 * @param child The child.
1004 * @return true if the child was present
1005 *
1006 * @throws IllegalStateException If called from an AccessibilityService.
1007 */
1008 public boolean removeChild(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001009 return removeChild(child, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001010 }
1011
1012 /**
1013 * Adds a virtual child which is a descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -07001014 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -07001015 * is added as a child.
1016 * <p>
1017 * A virtual descendant is an imaginary View that is reported as a part of the view
1018 * hierarchy for accessibility purposes. This enables custom views that draw complex
1019 * content to report them selves as a tree of virtual views, thus conveying their
1020 * logical structure.
1021 * </p>
1022 *
1023 * @param root The root of the virtual subtree.
1024 * @param virtualDescendantId The id of the virtual child.
1025 */
1026 public void addChild(View root, int virtualDescendantId) {
Alan Viverettef0aed092013-11-06 15:33:03 -08001027 addChildInternal(root, virtualDescendantId, true);
1028 }
1029
1030 private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001031 enforceNotSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -08001032 if (mChildNodeIds == null) {
1033 mChildNodeIds = new LongArray();
1034 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07001035 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001036 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001037 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Alan Viverettef0aed092013-11-06 15:33:03 -08001038 // If we're checking uniqueness and the ID already exists, abort.
1039 if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
1040 return;
1041 }
1042 mChildNodeIds.add(childNodeId);
1043 }
1044
1045 /**
1046 * Removes a virtual child which is a descendant of the given
1047 * <code>root</code>. If the child was not previously added to the node,
1048 * calling this method has no effect.
1049 *
1050 * @param root The root of the virtual subtree.
1051 * @param virtualDescendantId The id of the virtual child.
1052 * @return true if the child was present
1053 * @see #addChild(View, int)
1054 */
1055 public boolean removeChild(View root, int virtualDescendantId) {
1056 enforceNotSealed();
1057 final LongArray childIds = mChildNodeIds;
1058 if (childIds == null) {
1059 return false;
1060 }
1061 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001062 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Alan Viverettef0aed092013-11-06 15:33:03 -08001063 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1064 final int index = childIds.indexOf(childNodeId);
1065 if (index < 0) {
1066 return false;
1067 }
1068 childIds.remove(index);
1069 return true;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001070 }
1071
1072 /**
1073 * Gets the actions that can be performed on the node.
Kristian Monsen74bc1942014-04-29 11:00:17 -07001074 */
1075 public List<AccessibilityAction> getActionList() {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07001076 return CollectionUtils.emptyIfNull(mActions);
Kristian Monsen74bc1942014-04-29 11:00:17 -07001077 }
1078
1079 /**
1080 * Gets the actions that can be performed on the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001081 *
1082 * @return The bit mask of with actions.
1083 *
1084 * @see AccessibilityNodeInfo#ACTION_FOCUS
1085 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
1086 * @see AccessibilityNodeInfo#ACTION_SELECT
1087 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
Svetoslav Ganova1dc7612012-05-10 04:14:53 -07001088 * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
1089 * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
1090 * @see AccessibilityNodeInfo#ACTION_CLICK
1091 * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
1092 * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1093 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1094 * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
1095 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
1096 * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
1097 * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
Kristian Monsen74bc1942014-04-29 11:00:17 -07001098 *
1099 * @deprecated Use {@link #getActionList()}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001100 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001101 @Deprecated
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001102 public int getActions() {
Kristian Monsen74bc1942014-04-29 11:00:17 -07001103 int returnValue = 0;
1104
1105 if (mActions == null) {
1106 return returnValue;
1107 }
1108
1109 final int actionSize = mActions.size();
1110 for (int i = 0; i < actionSize; i++) {
1111 int actionId = mActions.get(i).getId();
1112 if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
1113 returnValue |= actionId;
1114 }
1115 }
1116
1117 return returnValue;
1118 }
1119
1120 /**
1121 * Adds an action that can be performed on the node.
1122 * <p>
1123 * To add a standard action use the static constants on {@link AccessibilityAction}.
1124 * To add a custom action create a new {@link AccessibilityAction} by passing in a
1125 * resource id from your application as the action id and an optional label that
1126 * describes the action. To override one of the standard actions use as the action
1127 * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
1128 * describes the action.
1129 * </p>
1130 * <p>
1131 * <strong>Note:</strong> Cannot be called from an
1132 * {@link android.accessibilityservice.AccessibilityService}.
1133 * This class is made immutable before being delivered to an AccessibilityService.
1134 * </p>
1135 *
1136 * @param action The action.
1137 *
1138 * @throws IllegalStateException If called from an AccessibilityService.
1139 */
1140 public void addAction(AccessibilityAction action) {
1141 enforceNotSealed();
1142
Alan Viverettec921f272015-05-14 12:26:49 -07001143 addActionUnchecked(action);
1144 }
1145
1146 private void addActionUnchecked(AccessibilityAction action) {
Kristian Monsen74bc1942014-04-29 11:00:17 -07001147 if (action == null) {
1148 return;
1149 }
1150
1151 if (mActions == null) {
Alan Viverette23f44322015-04-06 16:04:56 -07001152 mActions = new ArrayList<>();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001153 }
1154
1155 mActions.remove(action);
1156 mActions.add(action);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001157 }
1158
1159 /**
1160 * Adds an action that can be performed on the node.
1161 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001162 * <strong>Note:</strong> Cannot be called from an
1163 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001164 * This class is made immutable before being delivered to an AccessibilityService.
1165 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001166 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001167 * @param action The action.
1168 *
1169 * @throws IllegalStateException If called from an AccessibilityService.
Kristian Monsen74bc1942014-04-29 11:00:17 -07001170 * @throws IllegalArgumentException If the argument is not one of the standard actions.
1171 *
1172 * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001173 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001174 @Deprecated
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001175 public void addAction(int action) {
1176 enforceNotSealed();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001177
Kristian Monsen8d5f3fa2014-05-20 13:16:19 -07001178 if ((action & ACTION_TYPE_MASK) != 0) {
1179 throw new IllegalArgumentException("Action is not a combination of the standard " +
1180 "actions: " + action);
Kristian Monsen74bc1942014-04-29 11:00:17 -07001181 }
1182
Kristian Monsen8d5f3fa2014-05-20 13:16:19 -07001183 addLegacyStandardActions(action);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001184 }
1185
1186 /**
Alan Viverettef0aed092013-11-06 15:33:03 -08001187 * Removes an action that can be performed on the node. If the action was
1188 * not already added to the node, calling this method has no effect.
1189 * <p>
1190 * <strong>Note:</strong> Cannot be called from an
1191 * {@link android.accessibilityservice.AccessibilityService}.
1192 * This class is made immutable before being delivered to an AccessibilityService.
1193 * </p>
1194 *
Kristian Monsen74bc1942014-04-29 11:00:17 -07001195 * @param action The action to be removed.
1196 *
1197 * @throws IllegalStateException If called from an AccessibilityService.
1198 * @deprecated Use {@link #removeAction(AccessibilityAction)}
1199 */
1200 @Deprecated
1201 public void removeAction(int action) {
1202 enforceNotSealed();
1203
1204 removeAction(getActionSingleton(action));
1205 }
1206
1207 /**
1208 * Removes an action that can be performed on the node. If the action was
1209 * not already added to the node, calling this method has no effect.
1210 * <p>
1211 * <strong>Note:</strong> Cannot be called from an
1212 * {@link android.accessibilityservice.AccessibilityService}.
1213 * This class is made immutable before being delivered to an AccessibilityService.
1214 * </p>
1215 *
1216 * @param action The action to be removed.
1217 * @return The action removed from the list of actions.
Alan Viverettef0aed092013-11-06 15:33:03 -08001218 *
1219 * @throws IllegalStateException If called from an AccessibilityService.
1220 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001221 public boolean removeAction(AccessibilityAction action) {
Alan Viverettef0aed092013-11-06 15:33:03 -08001222 enforceNotSealed();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001223
1224 if (mActions == null || action == null) {
1225 return false;
1226 }
1227
1228 return mActions.remove(action);
Alan Viverettef0aed092013-11-06 15:33:03 -08001229 }
1230
1231 /**
Phil Weaverf00cd142017-03-03 13:44:00 -08001232 * Removes all actions.
1233 *
1234 * @hide
1235 */
1236 public void removeAllActions() {
1237 if (mActions != null) {
1238 mActions.clear();
1239 }
1240 }
1241
1242 /**
Svetoslav6c702902014-10-09 18:40:56 -07001243 * Gets the node before which this one is visited during traversal. A screen-reader
1244 * must visit the content of this node before the content of the one it precedes.
1245 *
1246 * @return The succeeding node if such or <code>null</code>.
1247 *
1248 * @see #setTraversalBefore(android.view.View)
1249 * @see #setTraversalBefore(android.view.View, int)
1250 */
1251 public AccessibilityNodeInfo getTraversalBefore() {
1252 enforceSealed();
1253 return getNodeForAccessibilityId(mTraversalBefore);
1254 }
1255
1256 /**
1257 * Sets the view before whose node this one should be visited during traversal. A
1258 * screen-reader must visit the content of this node before the content of the one
1259 * it precedes.
1260 * <p>
1261 * <strong>Note:</strong> Cannot be called from an
1262 * {@link android.accessibilityservice.AccessibilityService}.
1263 * This class is made immutable before being delivered to an AccessibilityService.
1264 * </p>
1265 *
1266 * @param view The view providing the preceding node.
1267 *
1268 * @see #getTraversalBefore()
1269 */
1270 public void setTraversalBefore(View view) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001271 setTraversalBefore(view, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav6c702902014-10-09 18:40:56 -07001272 }
1273
1274 /**
1275 * Sets the node before which this one is visited during traversal. A screen-reader
1276 * must visit the content of this node before the content of the one it precedes.
1277 * The successor is a virtual descendant of the given <code>root</code>. If
1278 * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
1279 * as the successor.
1280 * <p>
1281 * A virtual descendant is an imaginary View that is reported as a part of the view
1282 * hierarchy for accessibility purposes. This enables custom views that draw complex
1283 * content to report them selves as a tree of virtual views, thus conveying their
1284 * logical structure.
1285 * </p>
1286 * <p>
1287 * <strong>Note:</strong> Cannot be called from an
1288 * {@link android.accessibilityservice.AccessibilityService}.
1289 * This class is made immutable before being delivered to an AccessibilityService.
1290 * </p>
1291 *
1292 * @param root The root of the virtual subtree.
1293 * @param virtualDescendantId The id of the virtual descendant.
1294 */
1295 public void setTraversalBefore(View root, int virtualDescendantId) {
1296 enforceNotSealed();
1297 final int rootAccessibilityViewId = (root != null)
1298 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1299 mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1300 }
1301
1302 /**
1303 * Gets the node after which this one is visited in accessibility traversal.
1304 * A screen-reader must visit the content of the other node before the content
1305 * of this one.
1306 *
1307 * @return The succeeding node if such or <code>null</code>.
1308 *
1309 * @see #setTraversalAfter(android.view.View)
1310 * @see #setTraversalAfter(android.view.View, int)
1311 */
1312 public AccessibilityNodeInfo getTraversalAfter() {
1313 enforceSealed();
1314 return getNodeForAccessibilityId(mTraversalAfter);
1315 }
1316
1317 /**
1318 * Sets the view whose node is visited after this one in accessibility traversal.
1319 * A screen-reader must visit the content of the other node before the content
1320 * of this one.
1321 * <p>
1322 * <strong>Note:</strong> Cannot be called from an
1323 * {@link android.accessibilityservice.AccessibilityService}.
1324 * This class is made immutable before being delivered to an AccessibilityService.
1325 * </p>
1326 *
1327 * @param view The previous view.
1328 *
1329 * @see #getTraversalAfter()
1330 */
1331 public void setTraversalAfter(View view) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001332 setTraversalAfter(view, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav6c702902014-10-09 18:40:56 -07001333 }
1334
1335 /**
1336 * Sets the node after which this one is visited in accessibility traversal.
1337 * A screen-reader must visit the content of the other node before the content
1338 * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
1339 * the root is set as the predecessor.
1340 * <p>
1341 * A virtual descendant is an imaginary View that is reported as a part of the view
1342 * hierarchy for accessibility purposes. This enables custom views that draw complex
1343 * content to report them selves as a tree of virtual views, thus conveying their
1344 * logical structure.
1345 * </p>
1346 * <p>
1347 * <strong>Note:</strong> Cannot be called from an
1348 * {@link android.accessibilityservice.AccessibilityService}.
1349 * This class is made immutable before being delivered to an AccessibilityService.
1350 * </p>
1351 *
1352 * @param root The root of the virtual subtree.
1353 * @param virtualDescendantId The id of the virtual descendant.
1354 */
1355 public void setTraversalAfter(View root, int virtualDescendantId) {
1356 enforceNotSealed();
1357 final int rootAccessibilityViewId = (root != null)
1358 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1359 mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1360 }
1361
1362 /**
Phil Weaverc2e28932016-12-08 12:29:25 -08001363 * Get the extra data available for this node.
1364 * <p>
1365 * Some data that is useful for some accessibility services is expensive to compute, and would
1366 * place undue overhead on apps to compute all the time. That data can be requested with
1367 * {@link #refreshWithExtraData(String, Bundle)}.
1368 *
1369 * @return An unmodifiable list of keys corresponding to extra data that can be requested.
1370 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
1371 */
1372 public List<String> getAvailableExtraData() {
1373 if (mExtraDataKeys != null) {
1374 return Collections.unmodifiableList(mExtraDataKeys);
1375 } else {
1376 return EMPTY_LIST;
1377 }
1378 }
1379
1380 /**
1381 * Set the extra data available for this node.
1382 * <p>
1383 * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that
1384 * it will populate the node's extras with corresponding pieces of information in
1385 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}.
1386 * <p>
1387 * <strong>Note:</strong> Cannot be called from an
1388 * {@link android.accessibilityservice.AccessibilityService}.
1389 * This class is made immutable before being delivered to an AccessibilityService.
1390 *
1391 * @param extraDataKeys A list of types of extra data that are available.
1392 * @see #getAvailableExtraData()
1393 *
1394 * @throws IllegalStateException If called from an AccessibilityService.
1395 */
1396 public void setAvailableExtraData(List<String> extraDataKeys) {
1397 enforceNotSealed();
1398 mExtraDataKeys = new ArrayList<>(extraDataKeys);
1399 }
1400
1401 /**
Alan Viverette029942f2014-08-12 14:55:56 -07001402 * Sets the maximum text length, or -1 for no limit.
1403 * <p>
1404 * Typically used to indicate that an editable text field has a limit on
1405 * the number of characters entered.
1406 * <p>
1407 * <strong>Note:</strong> Cannot be called from an
1408 * {@link android.accessibilityservice.AccessibilityService}.
1409 * This class is made immutable before being delivered to an AccessibilityService.
1410 *
1411 * @param max The maximum text length.
1412 * @see #getMaxTextLength()
1413 *
1414 * @throws IllegalStateException If called from an AccessibilityService.
1415 */
1416 public void setMaxTextLength(int max) {
1417 enforceNotSealed();
1418 mMaxTextLength = max;
1419 }
1420
1421 /**
1422 * Returns the maximum text length for this node.
1423 *
1424 * @return The maximum text length, or -1 for no limit.
1425 * @see #setMaxTextLength(int)
1426 */
1427 public int getMaxTextLength() {
1428 return mMaxTextLength;
1429 }
1430
1431 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001432 * Sets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001433 * <p>
1434 * <strong>Note:</strong> Cannot be called from an
1435 * {@link android.accessibilityservice.AccessibilityService}.
1436 * This class is made immutable before being delivered to an AccessibilityService.
1437 * </p>
1438 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001439 * @param granularities The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001440 *
1441 * @throws IllegalStateException If called from an AccessibilityService.
1442 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001443 public void setMovementGranularities(int granularities) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001444 enforceNotSealed();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001445 mMovementGranularities = granularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001446 }
1447
1448 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001449 * Gets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001450 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001451 * @return The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001452 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001453 public int getMovementGranularities() {
1454 return mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001455 }
1456
1457 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001458 * Performs an action on the node.
1459 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001460 * <strong>Note:</strong> An action can be performed only if the request is made
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001461 * from an {@link android.accessibilityservice.AccessibilityService}.
1462 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001463 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001464 * @param action The action to perform.
1465 * @return True if the action was performed.
1466 *
1467 * @throws IllegalStateException If called outside of an AccessibilityService.
1468 */
1469 public boolean performAction(int action) {
1470 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -07001471 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001472 return false;
1473 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07001474 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001475 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1476 action, null);
1477 }
1478
1479 /**
1480 * Performs an action on the node.
1481 * <p>
1482 * <strong>Note:</strong> An action can be performed only if the request is made
1483 * from an {@link android.accessibilityservice.AccessibilityService}.
1484 * </p>
1485 *
1486 * @param action The action to perform.
1487 * @param arguments A bundle with additional arguments.
1488 * @return True if the action was performed.
1489 *
1490 * @throws IllegalStateException If called outside of an AccessibilityService.
1491 */
1492 public boolean performAction(int action, Bundle arguments) {
1493 enforceSealed();
1494 if (!canPerformRequestOverConnection(mSourceNodeId)) {
1495 return false;
1496 }
1497 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1498 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1499 action, arguments);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001500 }
1501
1502 /**
1503 * Finds {@link AccessibilityNodeInfo}s by text. The match is case
Svetoslav Ganov86398bd2011-06-21 17:38:43 -07001504 * insensitive containment. The search is relative to this info i.e.
1505 * this info is the root of the traversed tree.
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001506 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001507 * <p>
1508 * <strong>Note:</strong> It is a client responsibility to recycle the
1509 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1510 * to avoid creating of multiple instances.
1511 * </p>
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001512 *
1513 * @param text The searched text.
1514 * @return A list of node info.
1515 */
1516 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
1517 enforceSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -07001518 if (!canPerformRequestOverConnection(mSourceNodeId)) {
Svetoslav Ganov86398bd2011-06-21 17:38:43 -07001519 return Collections.emptyList();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001520 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07001521 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001522 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
1523 text);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001524 }
1525
1526 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001527 * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
1528 * name where a fully qualified id is of the from "package:id/id_resource_name".
1529 * For example, if the target application's package is "foo.bar" and the id
1530 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
1531 *
1532 * <p>
1533 * <strong>Note:</strong> It is a client responsibility to recycle the
1534 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1535 * to avoid creating of multiple instances.
1536 * </p>
1537 * <p>
1538 * <strong>Note:</strong> The primary usage of this API is for UI test automation
1539 * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
1540 * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08001541 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001542 * </p>
1543 *
1544 * @param viewId The fully qualified resource name of the view id to find.
1545 * @return A list of node info.
1546 */
1547 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
1548 enforceSealed();
1549 if (!canPerformRequestOverConnection(mSourceNodeId)) {
1550 return Collections.emptyList();
1551 }
1552 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1553 return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
1554 viewId);
1555 }
1556
1557 /**
Svetoslav8e3feb12014-02-24 13:46:47 -08001558 * Gets the window to which this node belongs.
1559 *
1560 * @return The window.
1561 *
1562 * @see android.accessibilityservice.AccessibilityService#getWindows()
1563 */
1564 public AccessibilityWindowInfo getWindow() {
1565 enforceSealed();
1566 if (!canPerformRequestOverConnection(mSourceNodeId)) {
1567 return null;
1568 }
1569 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1570 return client.getWindow(mConnectionId, mWindowId);
1571 }
1572
1573 /**
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001574 * Gets the parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001575 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001576 * <strong>Note:</strong> It is a client responsibility to recycle the
1577 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1578 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001579 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001580 *
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001581 * @return The parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001582 */
1583 public AccessibilityNodeInfo getParent() {
1584 enforceSealed();
Svetoslav6c702902014-10-09 18:40:56 -07001585 return getNodeForAccessibilityId(mParentNodeId);
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001586 }
1587
1588 /**
1589 * @return The parent node id.
1590 *
1591 * @hide
1592 */
1593 public long getParentNodeId() {
1594 return mParentNodeId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001595 }
1596
1597 /**
1598 * Sets the parent.
1599 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001600 * <strong>Note:</strong> Cannot be called from an
1601 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001602 * This class is made immutable before being delivered to an AccessibilityService.
1603 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001604 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001605 * @param parent The parent.
1606 *
1607 * @throws IllegalStateException If called from an AccessibilityService.
1608 */
1609 public void setParent(View parent) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001610 setParent(parent, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001611 }
1612
1613 /**
1614 * Sets the parent to be a virtual descendant of the given <code>root</code>.
1615 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
1616 * is set as the parent.
1617 * <p>
1618 * A virtual descendant is an imaginary View that is reported as a part of the view
1619 * hierarchy for accessibility purposes. This enables custom views that draw complex
1620 * content to report them selves as a tree of virtual views, thus conveying their
1621 * logical structure.
1622 * </p>
1623 * <p>
1624 * <strong>Note:</strong> Cannot be called from an
1625 * {@link android.accessibilityservice.AccessibilityService}.
1626 * This class is made immutable before being delivered to an AccessibilityService.
1627 * </p>
1628 *
1629 * @param root The root of the virtual subtree.
1630 * @param virtualDescendantId The id of the virtual descendant.
1631 */
1632 public void setParent(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001633 enforceNotSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -07001634 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001635 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001636 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001637 }
1638
1639 /**
1640 * Gets the node bounds in parent coordinates.
1641 *
1642 * @param outBounds The output node bounds.
1643 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001644 public void getBoundsInParent(Rect outBounds) {
1645 outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
1646 mBoundsInParent.right, mBoundsInParent.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001647 }
1648
1649 /**
1650 * Sets the node bounds in parent coordinates.
1651 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001652 * <strong>Note:</strong> Cannot be called from an
1653 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001654 * This class is made immutable before being delivered to an AccessibilityService.
1655 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001656 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001657 * @param bounds The node bounds.
1658 *
1659 * @throws IllegalStateException If called from an AccessibilityService.
1660 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001661 public void setBoundsInParent(Rect bounds) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001662 enforceNotSealed();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001663 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
1664 }
1665
1666 /**
1667 * Gets the node bounds in screen coordinates.
1668 *
1669 * @param outBounds The output node bounds.
1670 */
1671 public void getBoundsInScreen(Rect outBounds) {
1672 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
1673 mBoundsInScreen.right, mBoundsInScreen.bottom);
1674 }
1675
1676 /**
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001677 * Returns the actual rect containing the node bounds in screen coordinates.
1678 *
1679 * @hide Not safe to expose outside the framework.
1680 */
1681 public Rect getBoundsInScreen() {
1682 return mBoundsInScreen;
1683 }
1684
1685 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001686 * Sets the node bounds in screen coordinates.
1687 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001688 * <strong>Note:</strong> Cannot be called from an
1689 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001690 * This class is made immutable before being delivered to an AccessibilityService.
1691 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001692 *
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001693 * @param bounds The node bounds.
1694 *
1695 * @throws IllegalStateException If called from an AccessibilityService.
1696 */
1697 public void setBoundsInScreen(Rect bounds) {
1698 enforceNotSealed();
1699 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001700 }
1701
1702 /**
1703 * Gets whether this node is checkable.
1704 *
1705 * @return True if the node is checkable.
1706 */
1707 public boolean isCheckable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001708 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001709 }
1710
1711 /**
1712 * Sets whether this node is checkable.
1713 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001714 * <strong>Note:</strong> Cannot be called from an
1715 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001716 * This class is made immutable before being delivered to an AccessibilityService.
1717 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001718 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001719 * @param checkable True if the node is checkable.
1720 *
1721 * @throws IllegalStateException If called from an AccessibilityService.
1722 */
1723 public void setCheckable(boolean checkable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001724 setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001725 }
1726
1727 /**
1728 * Gets whether this node is checked.
1729 *
1730 * @return True if the node is checked.
1731 */
1732 public boolean isChecked() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001733 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001734 }
1735
1736 /**
1737 * Sets whether this node is checked.
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 checked True if the node is checked.
1745 *
1746 * @throws IllegalStateException If called from an AccessibilityService.
1747 */
1748 public void setChecked(boolean checked) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001749 setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001750 }
1751
1752 /**
1753 * Gets whether this node is focusable.
1754 *
1755 * @return True if the node is focusable.
1756 */
1757 public boolean isFocusable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001758 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001759 }
1760
1761 /**
1762 * Sets whether this node is focusable.
1763 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001764 * <strong>Note:</strong> Cannot be called from an
1765 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001766 * This class is made immutable before being delivered to an AccessibilityService.
1767 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001768 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001769 * @param focusable True if the node is focusable.
1770 *
1771 * @throws IllegalStateException If called from an AccessibilityService.
1772 */
1773 public void setFocusable(boolean focusable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001774 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001775 }
1776
1777 /**
1778 * Gets whether this node is focused.
1779 *
1780 * @return True if the node is focused.
1781 */
1782 public boolean isFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001783 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001784 }
1785
1786 /**
1787 * Sets whether this node is focused.
1788 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001789 * <strong>Note:</strong> Cannot be called from an
1790 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001791 * This class is made immutable before being delivered to an AccessibilityService.
1792 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001793 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001794 * @param focused True if the node is focused.
1795 *
1796 * @throws IllegalStateException If called from an AccessibilityService.
1797 */
1798 public void setFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001799 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001800 }
1801
1802 /**
Alan Viverette1579edc2015-04-01 13:23:06 -07001803 * Gets whether this node is visible to the user.
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001804 *
1805 * @return Whether the node is visible to the user.
1806 */
1807 public boolean isVisibleToUser() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001808 return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001809 }
1810
1811 /**
1812 * Sets whether this node is visible to the user.
1813 * <p>
1814 * <strong>Note:</strong> Cannot be called from an
1815 * {@link android.accessibilityservice.AccessibilityService}.
1816 * This class is made immutable before being delivered to an AccessibilityService.
1817 * </p>
1818 *
1819 * @param visibleToUser Whether the node is visible to the user.
1820 *
1821 * @throws IllegalStateException If called from an AccessibilityService.
1822 */
1823 public void setVisibleToUser(boolean visibleToUser) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001824 setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001825 }
1826
1827 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001828 * Gets whether this node is accessibility focused.
1829 *
1830 * @return True if the node is accessibility focused.
1831 */
1832 public boolean isAccessibilityFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001833 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001834 }
1835
1836 /**
1837 * Sets whether this node is accessibility focused.
1838 * <p>
1839 * <strong>Note:</strong> Cannot be called from an
1840 * {@link android.accessibilityservice.AccessibilityService}.
1841 * This class is made immutable before being delivered to an AccessibilityService.
1842 * </p>
1843 *
1844 * @param focused True if the node is accessibility focused.
1845 *
1846 * @throws IllegalStateException If called from an AccessibilityService.
1847 */
1848 public void setAccessibilityFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001849 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001850 }
1851
1852 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001853 * Gets whether this node is selected.
1854 *
1855 * @return True if the node is selected.
1856 */
1857 public boolean isSelected() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001858 return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001859 }
1860
1861 /**
1862 * Sets whether this node is selected.
1863 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001864 * <strong>Note:</strong> Cannot be called from an
1865 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001866 * This class is made immutable before being delivered to an AccessibilityService.
1867 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001868 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001869 * @param selected True if the node is selected.
1870 *
1871 * @throws IllegalStateException If called from an AccessibilityService.
1872 */
1873 public void setSelected(boolean selected) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001874 setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001875 }
1876
1877 /**
1878 * Gets whether this node is clickable.
1879 *
1880 * @return True if the node is clickable.
1881 */
1882 public boolean isClickable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001883 return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001884 }
1885
1886 /**
1887 * Sets whether this node is clickable.
1888 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001889 * <strong>Note:</strong> Cannot be called from an
1890 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001891 * This class is made immutable before being delivered to an AccessibilityService.
1892 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001893 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001894 * @param clickable True if the node is clickable.
1895 *
1896 * @throws IllegalStateException If called from an AccessibilityService.
1897 */
1898 public void setClickable(boolean clickable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001899 setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001900 }
1901
1902 /**
1903 * Gets whether this node is long clickable.
1904 *
1905 * @return True if the node is long clickable.
1906 */
1907 public boolean isLongClickable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001908 return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001909 }
1910
1911 /**
1912 * Sets whether this node is long clickable.
1913 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001914 * <strong>Note:</strong> Cannot be called from an
1915 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001916 * This class is made immutable before being delivered to an AccessibilityService.
1917 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001918 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001919 * @param longClickable True if the node is long clickable.
1920 *
1921 * @throws IllegalStateException If called from an AccessibilityService.
1922 */
1923 public void setLongClickable(boolean longClickable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001924 setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001925 }
1926
1927 /**
1928 * Gets whether this node is enabled.
1929 *
1930 * @return True if the node is enabled.
1931 */
1932 public boolean isEnabled() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001933 return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001934 }
1935
1936 /**
1937 * Sets whether this node is enabled.
1938 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001939 * <strong>Note:</strong> Cannot be called from an
1940 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001941 * This class is made immutable before being delivered to an AccessibilityService.
1942 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001943 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001944 * @param enabled True if the node is enabled.
1945 *
1946 * @throws IllegalStateException If called from an AccessibilityService.
1947 */
1948 public void setEnabled(boolean enabled) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001949 setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001950 }
1951
1952 /**
1953 * Gets whether this node is a password.
1954 *
1955 * @return True if the node is a password.
1956 */
1957 public boolean isPassword() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001958 return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001959 }
1960
1961 /**
1962 * Sets whether this node is a password.
1963 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001964 * <strong>Note:</strong> Cannot be called from an
1965 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001966 * This class is made immutable before being delivered to an AccessibilityService.
1967 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001968 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001969 * @param password True if the node is a password.
1970 *
1971 * @throws IllegalStateException If called from an AccessibilityService.
1972 */
1973 public void setPassword(boolean password) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001974 setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001975 }
1976
1977 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -07001978 * Gets if the node is scrollable.
1979 *
1980 * @return True if the node is scrollable, false otherwise.
1981 */
1982 public boolean isScrollable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001983 return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE);
Svetoslav Ganova0156172011-06-26 17:55:44 -07001984 }
1985
1986 /**
1987 * Sets if the node is scrollable.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001988 * <p>
1989 * <strong>Note:</strong> Cannot be called from an
1990 * {@link android.accessibilityservice.AccessibilityService}.
1991 * This class is made immutable before being delivered to an AccessibilityService.
1992 * </p>
Svetoslav Ganova0156172011-06-26 17:55:44 -07001993 *
1994 * @param scrollable True if the node is scrollable, false otherwise.
1995 *
1996 * @throws IllegalStateException If called from an AccessibilityService.
1997 */
1998 public void setScrollable(boolean scrollable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001999 setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable);
2000 }
2001
2002 /**
2003 * Gets if the node is editable.
2004 *
2005 * @return True if the node is editable, false otherwise.
2006 */
2007 public boolean isEditable() {
2008 return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
2009 }
2010
2011 /**
2012 * Sets whether this node is editable.
2013 * <p>
2014 * <strong>Note:</strong> Cannot be called from an
2015 * {@link android.accessibilityservice.AccessibilityService}.
2016 * This class is made immutable before being delivered to an AccessibilityService.
2017 * </p>
2018 *
2019 * @param editable True if the node is editable.
2020 *
2021 * @throws IllegalStateException If called from an AccessibilityService.
2022 */
2023 public void setEditable(boolean editable) {
2024 setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
Svetoslav Ganova0156172011-06-26 17:55:44 -07002025 }
2026
2027 /**
Phil Weaver1f222542016-01-08 11:49:32 -08002028 * Get the drawing order of the view corresponding it this node.
2029 * <p>
2030 * Drawing order is determined only within the node's parent, so this index is only relative
2031 * to its siblings.
2032 * <p>
2033 * In some cases, the drawing order is essentially simultaneous, so it is possible for two
2034 * siblings to return the same value. It is also possible that values will be skipped.
2035 *
2036 * @return The drawing position of the view corresponding to this node relative to its siblings.
2037 */
2038 public int getDrawingOrder() {
2039 return mDrawingOrderInParent;
2040 }
2041
2042 /**
2043 * Set the drawing order of the view corresponding it this node.
2044 *
2045 * <p>
2046 * <strong>Note:</strong> Cannot be called from an
2047 * {@link android.accessibilityservice.AccessibilityService}.
2048 * This class is made immutable before being delivered to an AccessibilityService.
2049 * </p>
2050 * @param drawingOrderInParent
2051 * @throws IllegalStateException If called from an AccessibilityService.
2052 */
2053 public void setDrawingOrder(int drawingOrderInParent) {
2054 enforceNotSealed();
2055 mDrawingOrderInParent = drawingOrderInParent;
2056 }
2057
2058 /**
Svetoslav3577a282013-06-06 14:09:10 -07002059 * Gets the collection info if the node is a collection. A collection
2060 * child is always a collection item.
2061 *
2062 * @return The collection info.
2063 */
2064 public CollectionInfo getCollectionInfo() {
2065 return mCollectionInfo;
2066 }
2067
2068 /**
2069 * Sets the collection info if the node is a collection. A collection
2070 * child is always a collection item.
2071 * <p>
2072 * <strong>Note:</strong> Cannot be called from an
2073 * {@link android.accessibilityservice.AccessibilityService}.
2074 * This class is made immutable before being delivered to an AccessibilityService.
2075 * </p>
2076 *
2077 * @param collectionInfo The collection info.
2078 */
2079 public void setCollectionInfo(CollectionInfo collectionInfo) {
2080 enforceNotSealed();
2081 mCollectionInfo = collectionInfo;
2082 }
2083
2084 /**
2085 * Gets the collection item info if the node is a collection item. A collection
2086 * item is always a child of a collection.
2087 *
2088 * @return The collection item info.
2089 */
2090 public CollectionItemInfo getCollectionItemInfo() {
2091 return mCollectionItemInfo;
2092 }
2093
2094 /**
2095 * Sets the collection item info if the node is a collection item. A collection
2096 * item is always a child of a collection.
2097 * <p>
2098 * <strong>Note:</strong> Cannot be called from an
2099 * {@link android.accessibilityservice.AccessibilityService}.
2100 * This class is made immutable before being delivered to an AccessibilityService.
2101 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07002102 */
2103 public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
2104 enforceNotSealed();
2105 mCollectionItemInfo = collectionItemInfo;
2106 }
2107
2108 /**
2109 * Gets the range info if this node is a range.
2110 *
2111 * @return The range.
2112 */
2113 public RangeInfo getRangeInfo() {
2114 return mRangeInfo;
2115 }
2116
2117 /**
2118 * Sets the range info if this node is a range.
2119 * <p>
2120 * <strong>Note:</strong> Cannot be called from an
2121 * {@link android.accessibilityservice.AccessibilityService}.
2122 * This class is made immutable before being delivered to an AccessibilityService.
2123 * </p>
2124 *
2125 * @param rangeInfo The range info.
2126 */
2127 public void setRangeInfo(RangeInfo rangeInfo) {
2128 enforceNotSealed();
2129 mRangeInfo = rangeInfo;
2130 }
2131
2132 /**
2133 * Gets if the content of this node is invalid. For example,
2134 * a date is not well-formed.
2135 *
2136 * @return If the node content is invalid.
2137 */
2138 public boolean isContentInvalid() {
2139 return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
2140 }
2141
2142 /**
2143 * Sets if the content of this node is invalid. For example,
2144 * a date is not well-formed.
2145 * <p>
2146 * <strong>Note:</strong> Cannot be called from an
2147 * {@link android.accessibilityservice.AccessibilityService}.
2148 * This class is made immutable before being delivered to an AccessibilityService.
2149 * </p>
2150 *
2151 * @param contentInvalid If the node content is invalid.
2152 */
2153 public void setContentInvalid(boolean contentInvalid) {
2154 setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
2155 }
2156
2157 /**
Mady Mellore8608912015-06-05 09:02:55 -07002158 * Gets whether this node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002159 *
Mady Mellore8608912015-06-05 09:02:55 -07002160 * @return True if the node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002161 */
Mady Mellore8608912015-06-05 09:02:55 -07002162 public boolean isContextClickable() {
2163 return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE);
Mady Mellore82067b2015-04-30 09:58:35 -07002164 }
2165
2166 /**
Mady Mellore8608912015-06-05 09:02:55 -07002167 * Sets whether this node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002168 * <p>
2169 * <strong>Note:</strong> Cannot be called from an
2170 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
2171 * before being delivered to an AccessibilityService.
2172 * </p>
2173 *
Mady Mellore8608912015-06-05 09:02:55 -07002174 * @param contextClickable True if the node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002175 * @throws IllegalStateException If called from an AccessibilityService.
2176 */
Mady Mellore8608912015-06-05 09:02:55 -07002177 public void setContextClickable(boolean contextClickable) {
2178 setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable);
Mady Mellore82067b2015-04-30 09:58:35 -07002179 }
2180
2181 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07002182 * Gets the node's live region mode.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002183 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002184 * A live region is a node that contains information that is important for
2185 * the user and when it changes the user should be notified. For example,
2186 * in a login screen with a TextView that displays an "incorrect password"
2187 * notification, that view should be marked as a live region with mode
2188 * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002189 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002190 * It is the responsibility of the accessibility service to monitor
2191 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
2192 * changes to live region nodes and their children.
Svetoslav3577a282013-06-06 14:09:10 -07002193 *
Alan Viverette77e9a282013-09-12 17:16:09 -07002194 * @return The live region mode, or
2195 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2196 * live region.
2197 * @see android.view.View#getAccessibilityLiveRegion()
Svetoslav3577a282013-06-06 14:09:10 -07002198 */
Alan Viverette77e9a282013-09-12 17:16:09 -07002199 public int getLiveRegion() {
2200 return mLiveRegion;
Svetoslav3577a282013-06-06 14:09:10 -07002201 }
2202
2203 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07002204 * Sets the node's live region mode.
Svetoslav3577a282013-06-06 14:09:10 -07002205 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002206 * <strong>Note:</strong> Cannot be called from an
2207 * {@link android.accessibilityservice.AccessibilityService}. This class is
2208 * made immutable before being delivered to an AccessibilityService.
Svetoslav3577a282013-06-06 14:09:10 -07002209 *
Alan Viverette77e9a282013-09-12 17:16:09 -07002210 * @param mode The live region mode, or
2211 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2212 * live region.
2213 * @see android.view.View#setAccessibilityLiveRegion(int)
Svetoslav3577a282013-06-06 14:09:10 -07002214 */
Alan Viverette77e9a282013-09-12 17:16:09 -07002215 public void setLiveRegion(int mode) {
2216 enforceNotSealed();
2217 mLiveRegion = mode;
Svetoslav3577a282013-06-06 14:09:10 -07002218 }
2219
2220 /**
2221 * Gets if the node is a multi line editable text.
2222 *
2223 * @return True if the node is multi line.
2224 */
2225 public boolean isMultiLine() {
2226 return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
2227 }
2228
2229 /**
2230 * Sets if the node is a multi line editable text.
2231 * <p>
2232 * <strong>Note:</strong> Cannot be called from an
2233 * {@link android.accessibilityservice.AccessibilityService}.
2234 * This class is made immutable before being delivered to an AccessibilityService.
2235 * </p>
2236 *
2237 * @param multiLine True if the node is multi line.
2238 */
2239 public void setMultiLine(boolean multiLine) {
Svetoslav3577a282013-06-06 14:09:10 -07002240 setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
2241 }
2242
2243 /**
2244 * Gets if this node opens a popup or a dialog.
2245 *
2246 * @return If the the node opens a popup.
2247 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002248 public boolean canOpenPopup() {
Svetoslav3577a282013-06-06 14:09:10 -07002249 return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
2250 }
2251
2252 /**
2253 * Sets if this node opens a popup or a dialog.
2254 * <p>
2255 * <strong>Note:</strong> Cannot be called from an
2256 * {@link android.accessibilityservice.AccessibilityService}.
2257 * This class is made immutable before being delivered to an AccessibilityService.
2258 * </p>
2259 *
2260 * @param opensPopup If the the node opens a popup.
2261 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002262 public void setCanOpenPopup(boolean opensPopup) {
2263 enforceNotSealed();
Svetoslav3577a282013-06-06 14:09:10 -07002264 setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
2265 }
2266
2267 /**
Svetoslav3577a282013-06-06 14:09:10 -07002268 * Gets if the node can be dismissed.
2269 *
2270 * @return If the node can be dismissed.
2271 */
2272 public boolean isDismissable() {
2273 return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
2274 }
2275
2276 /**
2277 * Sets if the node can be dismissed.
2278 * <p>
2279 * <strong>Note:</strong> Cannot be called from an
2280 * {@link android.accessibilityservice.AccessibilityService}.
2281 * This class is made immutable before being delivered to an AccessibilityService.
2282 * </p>
2283 *
2284 * @param dismissable If the node can be dismissed.
2285 */
2286 public void setDismissable(boolean dismissable) {
Svetoslav3577a282013-06-06 14:09:10 -07002287 setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
2288 }
2289
2290 /**
Casey Burkhardt2d80ae42016-01-31 12:52:23 -08002291 * Returns whether the node originates from a view considered important for accessibility.
2292 *
2293 * @return {@code true} if the node originates from a view considered important for
2294 * accessibility, {@code false} otherwise
2295 *
2296 * @see View#isImportantForAccessibility()
2297 */
2298 public boolean isImportantForAccessibility() {
2299 return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE);
2300 }
2301
2302 /**
2303 * Sets whether the node is considered important for accessibility.
2304 * <p>
2305 * <strong>Note:</strong> Cannot be called from an
2306 * {@link android.accessibilityservice.AccessibilityService}.
2307 * This class is made immutable before being delivered to an AccessibilityService.
2308 * </p>
2309 *
2310 * @param important {@code true} if the node is considered important for accessibility,
2311 * {@code false} otherwise
2312 */
2313 public void setImportantForAccessibility(boolean important) {
2314 setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important);
2315 }
2316
2317 /**
Phil Weaver776afc22016-12-21 10:55:13 -08002318 * Returns whether the node's text represents a hint for the user to enter text. It should only
2319 * be {@code true} if the node has editable text.
2320 *
2321 * @return {@code true} if the text in the node represents a hint to the user, {@code false}
2322 * otherwise.
2323 */
2324 public boolean isShowingHintText() {
2325 return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
2326 }
2327
2328 /**
2329 * Sets whether the node's text represents a hint for the user to enter text. It should only
2330 * be {@code true} if the node has editable text.
2331 * <p>
2332 * <strong>Note:</strong> Cannot be called from an
2333 * {@link android.accessibilityservice.AccessibilityService}.
2334 * This class is made immutable before being delivered to an AccessibilityService.
2335 * </p>
2336 *
2337 * @param showingHintText {@code true} if the text in the node represents a hint to the user,
2338 * {@code false} otherwise.
2339 */
2340 public void setShowingHintText(boolean showingHintText) {
2341 setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
2342 }
2343
2344 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002345 * Gets the package this node comes from.
2346 *
2347 * @return The package name.
2348 */
2349 public CharSequence getPackageName() {
2350 return mPackageName;
2351 }
2352
2353 /**
2354 * Sets the package this node comes from.
2355 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002356 * <strong>Note:</strong> Cannot be called from an
2357 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002358 * This class is made immutable before being delivered to an AccessibilityService.
2359 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002360 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002361 * @param packageName The package name.
2362 *
2363 * @throws IllegalStateException If called from an AccessibilityService.
2364 */
2365 public void setPackageName(CharSequence packageName) {
2366 enforceNotSealed();
2367 mPackageName = packageName;
2368 }
2369
2370 /**
2371 * Gets the class this node comes from.
2372 *
2373 * @return The class name.
2374 */
2375 public CharSequence getClassName() {
2376 return mClassName;
2377 }
2378
2379 /**
2380 * Sets the class this node comes from.
2381 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002382 * <strong>Note:</strong> Cannot be called from an
2383 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002384 * This class is made immutable before being delivered to an AccessibilityService.
2385 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002386 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002387 * @param className The class name.
2388 *
2389 * @throws IllegalStateException If called from an AccessibilityService.
2390 */
2391 public void setClassName(CharSequence className) {
2392 enforceNotSealed();
2393 mClassName = className;
2394 }
2395
2396 /**
2397 * Gets the text of this node.
Phil Weaver193520e2016-12-13 09:39:06 -08002398 * <p>
2399 * <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s,
2400 * these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)}
2401 * can be called from an {@link AccessibilityService}. When called from a service, the
2402 * {@link View} argument is ignored and the corresponding span will be found on the view that
2403 * this {@code AccessibilityNodeInfo} represents and called with that view as its argument.
2404 * <p>
2405 * This treatment of {@link ClickableSpan}s means that the text returned from this method may
2406 * different slightly one passed to {@link #setText(CharSequence)}, although they will be
2407 * equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The
2408 * {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside
2409 * of an accessibility service.
2410 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002411 *
2412 * @return The text.
2413 */
2414 public CharSequence getText() {
Phil Weaver193520e2016-12-13 09:39:06 -08002415 // Attach this node to any spans that need it
2416 if (mText instanceof Spanned) {
2417 Spanned spanned = (Spanned) mText;
2418 AccessibilityClickableSpan[] clickableSpans =
2419 spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class);
2420 for (int i = 0; i < clickableSpans.length; i++) {
Phil Weaver23161e72017-04-19 12:16:36 -07002421 clickableSpans[i].copyConnectionDataFrom(this);
Phil Weaver193520e2016-12-13 09:39:06 -08002422 }
2423 AccessibilityURLSpan[] urlSpans =
2424 spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class);
2425 for (int i = 0; i < urlSpans.length; i++) {
Phil Weaver23161e72017-04-19 12:16:36 -07002426 urlSpans[i].copyConnectionDataFrom(this);
Phil Weaver193520e2016-12-13 09:39:06 -08002427 }
2428 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002429 return mText;
2430 }
2431
2432 /**
Phil Weaver193520e2016-12-13 09:39:06 -08002433 * Get the text passed to setText before any changes to the spans.
2434 * @hide
2435 */
2436 public CharSequence getOriginalText() {
2437 return mOriginalText;
2438 }
2439
2440 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002441 * Sets the text of this node.
2442 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002443 * <strong>Note:</strong> Cannot be called from an
2444 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002445 * This class is made immutable before being delivered to an AccessibilityService.
2446 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002447 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002448 * @param text The text.
2449 *
2450 * @throws IllegalStateException If called from an AccessibilityService.
2451 */
2452 public void setText(CharSequence text) {
2453 enforceNotSealed();
Phil Weaver193520e2016-12-13 09:39:06 -08002454 mOriginalText = text;
2455 // Replace any ClickableSpans in mText with placeholders
2456 if (text instanceof Spanned) {
2457 ClickableSpan[] spans =
2458 ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
2459 if (spans.length > 0) {
Phil Weaver0ebe6bd2017-02-21 16:24:31 -08002460 Spannable spannable = new SpannableStringBuilder(text);
Phil Weaver193520e2016-12-13 09:39:06 -08002461 for (int i = 0; i < spans.length; i++) {
2462 ClickableSpan span = spans[i];
2463 if ((span instanceof AccessibilityClickableSpan)
2464 || (span instanceof AccessibilityURLSpan)) {
2465 // We've already done enough
2466 break;
2467 }
2468 int spanToReplaceStart = spannable.getSpanStart(span);
2469 int spanToReplaceEnd = spannable.getSpanEnd(span);
2470 int spanToReplaceFlags = spannable.getSpanFlags(span);
2471 spannable.removeSpan(span);
2472 ClickableSpan replacementSpan = (span instanceof URLSpan)
2473 ? new AccessibilityURLSpan((URLSpan) span)
2474 : new AccessibilityClickableSpan(span.getId());
2475 spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
2476 spanToReplaceFlags);
2477 }
2478 mText = spannable;
2479 return;
2480 }
2481 }
Phil Weaveref955ad2016-08-25 12:58:15 -07002482 mText = (text == null) ? null : text.subSequence(0, text.length());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002483 }
2484
2485 /**
Phil Weaver776afc22016-12-21 10:55:13 -08002486 * Gets the hint text of this node. Only applies to nodes where text can be entered.
2487 *
2488 * @return The hint text.
2489 */
2490 public CharSequence getHintText() {
2491 return mHintText;
2492 }
2493
2494 /**
2495 * Sets the hint text of this node. Only applies to nodes where text can be entered.
2496 * <p>
2497 * <strong>Note:</strong> Cannot be called from an
2498 * {@link android.accessibilityservice.AccessibilityService}.
2499 * This class is made immutable before being delivered to an AccessibilityService.
2500 * </p>
2501 *
2502 * @param hintText The hint text for this mode.
2503 *
2504 * @throws IllegalStateException If called from an AccessibilityService.
2505 */
2506 public void setHintText(CharSequence hintText) {
2507 enforceNotSealed();
2508 mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length());
2509 }
2510
2511 /**
Alan Viverettefccbff52014-07-07 15:06:14 -07002512 * Sets the error text of this node.
2513 * <p>
2514 * <strong>Note:</strong> Cannot be called from an
2515 * {@link android.accessibilityservice.AccessibilityService}.
2516 * This class is made immutable before being delivered to an AccessibilityService.
2517 * </p>
2518 *
2519 * @param error The error text.
2520 *
2521 * @throws IllegalStateException If called from an AccessibilityService.
2522 */
2523 public void setError(CharSequence error) {
2524 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -07002525 mError = (error == null) ? null : error.subSequence(0, error.length());
Alan Viverettefccbff52014-07-07 15:06:14 -07002526 }
2527
2528 /**
2529 * Gets the error text of this node.
2530 *
2531 * @return The error text.
2532 */
2533 public CharSequence getError() {
2534 return mError;
2535 }
2536
2537 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002538 * Gets the content description of this node.
2539 *
2540 * @return The content description.
2541 */
2542 public CharSequence getContentDescription() {
2543 return mContentDescription;
2544 }
2545
2546 /**
2547 * Sets the content description of this node.
2548 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002549 * <strong>Note:</strong> Cannot be called from an
2550 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002551 * This class is made immutable before being delivered to an AccessibilityService.
2552 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002553 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002554 * @param contentDescription The content description.
2555 *
2556 * @throws IllegalStateException If called from an AccessibilityService.
2557 */
2558 public void setContentDescription(CharSequence contentDescription) {
2559 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -07002560 mContentDescription = (contentDescription == null) ? null
2561 : contentDescription.subSequence(0, contentDescription.length());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002562 }
2563
2564 /**
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002565 * Sets the view for which the view represented by this info serves as a
2566 * label for accessibility purposes.
2567 *
2568 * @param labeled The view for which this info serves as a label.
2569 */
2570 public void setLabelFor(View labeled) {
Phil Weaverf00cd142017-03-03 13:44:00 -08002571 setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002572 }
2573
2574 /**
2575 * Sets the view for which the view represented by this info serves as a
2576 * label for accessibility purposes. If <code>virtualDescendantId</code>
2577 * is {@link View#NO_ID} the root is set as the labeled.
2578 * <p>
2579 * A virtual descendant is an imaginary View that is reported as a part of the view
2580 * hierarchy for accessibility purposes. This enables custom views that draw complex
2581 * content to report themselves as a tree of virtual views, thus conveying their
2582 * logical structure.
2583 * </p>
2584 * <p>
2585 * <strong>Note:</strong> Cannot be called from an
2586 * {@link android.accessibilityservice.AccessibilityService}.
2587 * This class is made immutable before being delivered to an AccessibilityService.
2588 * </p>
2589 *
2590 * @param root The root whose virtual descendant serves as a label.
2591 * @param virtualDescendantId The id of the virtual descendant.
2592 */
2593 public void setLabelFor(View root, int virtualDescendantId) {
2594 enforceNotSealed();
2595 final int rootAccessibilityViewId = (root != null)
Svetoslav8e3feb12014-02-24 13:46:47 -08002596 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002597 mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2598 }
2599
2600 /**
2601 * Gets the node info for which the view represented by this info serves as
2602 * a label for accessibility purposes.
2603 * <p>
2604 * <strong>Note:</strong> It is a client responsibility to recycle the
2605 * received info by calling {@link AccessibilityNodeInfo#recycle()}
2606 * to avoid creating of multiple instances.
2607 * </p>
2608 *
2609 * @return The labeled info.
2610 */
2611 public AccessibilityNodeInfo getLabelFor() {
2612 enforceSealed();
Svetoslav6c702902014-10-09 18:40:56 -07002613 return getNodeForAccessibilityId(mLabelForId);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002614 }
2615
2616 /**
2617 * Sets the view which serves as the label of the view represented by
2618 * this info for accessibility purposes.
2619 *
2620 * @param label The view that labels this node's source.
2621 */
2622 public void setLabeledBy(View label) {
Phil Weaverf00cd142017-03-03 13:44:00 -08002623 setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002624 }
2625
2626 /**
2627 * Sets the view which serves as the label of the view represented by
2628 * this info for accessibility purposes. If <code>virtualDescendantId</code>
2629 * is {@link View#NO_ID} the root is set as the label.
2630 * <p>
2631 * A virtual descendant is an imaginary View that is reported as a part of the view
2632 * hierarchy for accessibility purposes. This enables custom views that draw complex
2633 * content to report themselves as a tree of virtual views, thus conveying their
2634 * logical structure.
2635 * </p>
2636 * <p>
2637 * <strong>Note:</strong> Cannot be called from an
2638 * {@link android.accessibilityservice.AccessibilityService}.
2639 * This class is made immutable before being delivered to an AccessibilityService.
2640 * </p>
2641 *
2642 * @param root The root whose virtual descendant labels this node's source.
2643 * @param virtualDescendantId The id of the virtual descendant.
2644 */
2645 public void setLabeledBy(View root, int virtualDescendantId) {
2646 enforceNotSealed();
2647 final int rootAccessibilityViewId = (root != null)
Svetoslav8e3feb12014-02-24 13:46:47 -08002648 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002649 mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2650 }
2651
2652 /**
2653 * Gets the node info which serves as the label of the view represented by
2654 * this info for accessibility purposes.
2655 * <p>
2656 * <strong>Note:</strong> It is a client responsibility to recycle the
2657 * received info by calling {@link AccessibilityNodeInfo#recycle()}
2658 * to avoid creating of multiple instances.
2659 * </p>
2660 *
2661 * @return The label.
2662 */
2663 public AccessibilityNodeInfo getLabeledBy() {
2664 enforceSealed();
Svetoslav6c702902014-10-09 18:40:56 -07002665 return getNodeForAccessibilityId(mLabeledById);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002666 }
2667
2668 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002669 * Sets the fully qualified resource name of the source view's id.
2670 *
2671 * <p>
2672 * <strong>Note:</strong> Cannot be called from an
2673 * {@link android.accessibilityservice.AccessibilityService}.
2674 * This class is made immutable before being delivered to an AccessibilityService.
2675 * </p>
2676 *
Svetoslav92826452013-02-05 14:57:42 -08002677 * @param viewIdResName The id resource name.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002678 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07002679 public void setViewIdResourceName(String viewIdResName) {
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002680 enforceNotSealed();
Svetoslav22431a32013-02-05 14:30:19 -08002681 mViewIdResourceName = viewIdResName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002682 }
2683
2684 /**
2685 * Gets the fully qualified resource name of the source view's id.
2686 *
2687 * <p>
2688 * <strong>Note:</strong> The primary usage of this API is for UI test automation
2689 * and in order to report the source view id of an {@link AccessibilityNodeInfo} the
2690 * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08002691 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002692 * </p>
2693
2694 * @return The id resource name.
2695 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07002696 public String getViewIdResourceName() {
Svetoslav22431a32013-02-05 14:30:19 -08002697 return mViewIdResourceName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002698 }
2699
2700 /**
Phil Weaver40ded282016-01-25 15:49:02 -08002701 * Gets the text selection start or the cursor position.
2702 * <p>
2703 * If no text is selected, both this method and
2704 * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
2705 * the current location of the cursor.
2706 * </p>
Svetoslavbcc46a02013-02-06 11:56:00 -08002707 *
Phil Weaver40ded282016-01-25 15:49:02 -08002708 * @return The text selection start, the cursor location if there is no selection, or -1 if
2709 * there is no text selection and no cursor.
Svetoslavbcc46a02013-02-06 11:56:00 -08002710 */
2711 public int getTextSelectionStart() {
2712 return mTextSelectionStart;
2713 }
2714
2715 /**
Phil Weaver40ded282016-01-25 15:49:02 -08002716 * Gets the text selection end if text is selected.
2717 * <p>
2718 * If no text is selected, both this method and
2719 * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
2720 * the current location of the cursor.
2721 * </p>
Svetoslavbcc46a02013-02-06 11:56:00 -08002722 *
Phil Weaver40ded282016-01-25 15:49:02 -08002723 * @return The text selection end, the cursor location if there is no selection, or -1 if
2724 * there is no text selection and no cursor.
Svetoslavbcc46a02013-02-06 11:56:00 -08002725 */
2726 public int getTextSelectionEnd() {
2727 return mTextSelectionEnd;
2728 }
2729
2730 /**
2731 * Sets the text selection start and end.
2732 * <p>
2733 * <strong>Note:</strong> Cannot be called from an
2734 * {@link android.accessibilityservice.AccessibilityService}.
2735 * This class is made immutable before being delivered to an AccessibilityService.
2736 * </p>
2737 *
2738 * @param start The text selection start.
2739 * @param end The text selection end.
2740 *
2741 * @throws IllegalStateException If called from an AccessibilityService.
2742 */
2743 public void setTextSelection(int start, int end) {
2744 enforceNotSealed();
2745 mTextSelectionStart = start;
2746 mTextSelectionEnd = end;
2747 }
2748
2749 /**
Svetoslav6254f482013-06-04 17:22:14 -07002750 * Gets the input type of the source as defined by {@link InputType}.
2751 *
2752 * @return The input type.
2753 */
2754 public int getInputType() {
2755 return mInputType;
2756 }
2757
2758 /**
2759 * Sets the input type of the source as defined by {@link InputType}.
2760 * <p>
2761 * <strong>Note:</strong> Cannot be called from an
2762 * {@link android.accessibilityservice.AccessibilityService}.
2763 * This class is made immutable before being delivered to an
2764 * AccessibilityService.
2765 * </p>
2766 *
2767 * @param inputType The input type.
2768 *
2769 * @throws IllegalStateException If called from an AccessibilityService.
2770 */
2771 public void setInputType(int inputType) {
Alan Viverettedf39cb92013-08-19 12:28:04 -07002772 enforceNotSealed();
Svetoslav6254f482013-06-04 17:22:14 -07002773 mInputType = inputType;
2774 }
2775
2776 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002777 * Gets an optional bundle with extra data. The bundle
Svetoslav6254f482013-06-04 17:22:14 -07002778 * is lazily created and never <code>null</code>.
2779 * <p>
2780 * <strong>Note:</strong> It is recommended to use the package
2781 * name of your application as a prefix for the keys to avoid
2782 * collisions which may confuse an accessibility service if the
2783 * same key has different meaning when emitted from different
2784 * applications.
2785 * </p>
2786 *
2787 * @return The bundle.
2788 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002789 public Bundle getExtras() {
2790 if (mExtras == null) {
2791 mExtras = new Bundle();
Svetoslav6254f482013-06-04 17:22:14 -07002792 }
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002793 return mExtras;
Svetoslav6254f482013-06-04 17:22:14 -07002794 }
2795
2796 /**
Phil Weaverc2e28932016-12-08 12:29:25 -08002797 * Check if a node has an extras bundle
2798 * @hide
2799 */
2800 public boolean hasExtras() {
2801 return mExtras != null;
2802 }
2803
2804 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002805 * Gets the value of a boolean property.
2806 *
2807 * @param property The property.
2808 * @return The value.
2809 */
2810 private boolean getBooleanProperty(int property) {
2811 return (mBooleanProperties & property) != 0;
2812 }
2813
2814 /**
2815 * Sets a boolean property.
2816 *
2817 * @param property The property.
2818 * @param value The value.
2819 *
2820 * @throws IllegalStateException If called from an AccessibilityService.
2821 */
2822 private void setBooleanProperty(int property, boolean value) {
2823 enforceNotSealed();
2824 if (value) {
2825 mBooleanProperties |= property;
2826 } else {
2827 mBooleanProperties &= ~property;
2828 }
2829 }
2830
2831 /**
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002832 * Sets the unique id of the IAccessibilityServiceConnection over which
2833 * this instance can send requests to the system.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002834 *
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002835 * @param connectionId The connection id.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002836 *
2837 * @hide
2838 */
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002839 public void setConnectionId(int connectionId) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07002840 enforceNotSealed();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08002841 mConnectionId = connectionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002842 }
2843
2844 /**
Phil Weaver23161e72017-04-19 12:16:36 -07002845 * Get the connection ID.
2846 *
2847 * @return The connection id
2848 *
2849 * @hide
2850 */
2851 public int getConnectionId() {
2852 return mConnectionId;
2853 }
2854
2855 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002856 * {@inheritDoc}
2857 */
Alan Viverettef0aed092013-11-06 15:33:03 -08002858 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002859 public int describeContents() {
2860 return 0;
2861 }
2862
2863 /**
Phil Weaverf00cd142017-03-03 13:44:00 -08002864 * Sets the id of the source node.
2865 *
2866 * @param sourceId The id.
2867 * @param windowId The window id.
2868 *
2869 * @hide
2870 */
2871 public void setSourceNodeId(long sourceId, int windowId) {
2872 enforceNotSealed();
2873 mSourceNodeId = sourceId;
2874 mWindowId = windowId;
2875 }
2876
2877 /**
Svetoslav Ganov79311c42012-01-17 20:24:26 -08002878 * Gets the id of the source node.
2879 *
2880 * @return The id.
2881 *
2882 * @hide
2883 */
2884 public long getSourceNodeId() {
2885 return mSourceNodeId;
2886 }
2887
2888 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002889 * Sets if this instance is sealed.
2890 *
2891 * @param sealed Whether is sealed.
2892 *
2893 * @hide
2894 */
2895 public void setSealed(boolean sealed) {
2896 mSealed = sealed;
2897 }
2898
2899 /**
2900 * Gets if this instance is sealed.
2901 *
2902 * @return Whether is sealed.
2903 *
2904 * @hide
2905 */
2906 public boolean isSealed() {
2907 return mSealed;
2908 }
2909
2910 /**
2911 * Enforces that this instance is sealed.
2912 *
2913 * @throws IllegalStateException If this instance is not sealed.
2914 *
2915 * @hide
2916 */
2917 protected void enforceSealed() {
2918 if (!isSealed()) {
2919 throw new IllegalStateException("Cannot perform this "
2920 + "action on a not sealed instance.");
2921 }
2922 }
2923
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07002924 private void enforceValidFocusDirection(int direction) {
2925 switch (direction) {
2926 case View.FOCUS_DOWN:
2927 case View.FOCUS_UP:
2928 case View.FOCUS_LEFT:
2929 case View.FOCUS_RIGHT:
2930 case View.FOCUS_FORWARD:
2931 case View.FOCUS_BACKWARD:
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07002932 return;
2933 default:
2934 throw new IllegalArgumentException("Unknown direction: " + direction);
2935 }
2936 }
2937
2938 private void enforceValidFocusType(int focusType) {
2939 switch (focusType) {
2940 case FOCUS_INPUT:
2941 case FOCUS_ACCESSIBILITY:
2942 return;
2943 default:
2944 throw new IllegalArgumentException("Unknown focus type: " + focusType);
2945 }
2946 }
2947
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002948 /**
2949 * Enforces that this instance is not sealed.
2950 *
2951 * @throws IllegalStateException If this instance is sealed.
2952 *
2953 * @hide
2954 */
2955 protected void enforceNotSealed() {
2956 if (isSealed()) {
2957 throw new IllegalStateException("Cannot perform this "
Ken Wakasaf76a50c2012-03-09 19:56:35 +09002958 + "action on a sealed instance.");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002959 }
2960 }
2961
2962 /**
2963 * Returns a cached instance if such is available otherwise a new one
2964 * and sets the source.
2965 *
Svetoslav Ganov02107852011-10-03 17:06:56 -07002966 * @param source The source view.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002967 * @return An instance.
2968 *
2969 * @see #setSource(View)
2970 */
2971 public static AccessibilityNodeInfo obtain(View source) {
2972 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2973 info.setSource(source);
2974 return info;
2975 }
2976
2977 /**
Svetoslav Ganov02107852011-10-03 17:06:56 -07002978 * Returns a cached instance if such is available otherwise a new one
2979 * and sets the source.
2980 *
2981 * @param root The root of the virtual subtree.
2982 * @param virtualDescendantId The id of the virtual descendant.
2983 * @return An instance.
2984 *
2985 * @see #setSource(View, int)
2986 */
2987 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
2988 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
2989 info.setSource(root, virtualDescendantId);
2990 return info;
2991 }
2992
2993 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002994 * Returns a cached instance if such is available otherwise a new one.
2995 *
2996 * @return An instance.
2997 */
2998 public static AccessibilityNodeInfo obtain() {
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08002999 AccessibilityNodeInfo info = sPool.acquire();
Phil Weaver62d20fa2016-09-15 11:05:55 -07003000 if (sNumInstancesInUse != null) {
3001 sNumInstancesInUse.incrementAndGet();
3002 }
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08003003 return (info != null) ? info : new AccessibilityNodeInfo();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003004 }
3005
3006 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003007 * Returns a cached instance if such is available or a new one is
3008 * create. The returned instance is initialized from the given
3009 * <code>info</code>.
3010 *
3011 * @param info The other info.
3012 * @return An instance.
3013 */
3014 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
3015 AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
3016 infoClone.init(info);
3017 return infoClone;
3018 }
3019
3020 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003021 * Return an instance back to be reused.
3022 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003023 * <strong>Note:</strong> You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003024 *
3025 * @throws IllegalStateException If the info is already recycled.
3026 */
3027 public void recycle() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003028 clear();
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08003029 sPool.release(this);
Phil Weaver62d20fa2016-09-15 11:05:55 -07003030 if (sNumInstancesInUse != null) {
3031 sNumInstancesInUse.decrementAndGet();
3032 }
Phil Weaverb010b122016-08-17 17:47:48 -07003033 }
3034
3035 /**
Phil Weaver62d20fa2016-09-15 11:05:55 -07003036 * Specify a counter that will be incremented on obtain() and decremented on recycle()
Phil Weaverb010b122016-08-17 17:47:48 -07003037 *
3038 * @hide
3039 */
Phil Weaver62d20fa2016-09-15 11:05:55 -07003040 @TestApi
3041 public static void setNumInstancesInUseCounter(AtomicInteger counter) {
3042 sNumInstancesInUse = counter;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003043 }
3044
3045 /**
3046 * {@inheritDoc}
3047 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003048 * <strong>Note:</strong> After the instance is written to a parcel it
3049 * is recycled. You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003050 * </p>
3051 */
Alan Viverettef0aed092013-11-06 15:33:03 -08003052 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003053 public void writeToParcel(Parcel parcel, int flags) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003054 // Write bit set of indices of fields with values differing from default
3055 long nonDefaultFields = 0;
3056 int fieldIndex = 0; // index of the current field
3057 if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex);
3058 fieldIndex++;
3059 if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex);
3060 fieldIndex++;
3061 if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex);
3062 fieldIndex++;
3063 if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex);
3064 fieldIndex++;
3065 if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex);
3066 fieldIndex++;
3067 if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex);
3068 fieldIndex++;
3069 if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex);
3070 fieldIndex++;
3071 if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex);
3072 fieldIndex++;
3073 if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex);
3074 fieldIndex++;
3075 if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) {
3076 nonDefaultFields |= bitAt(fieldIndex);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003077 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003078 fieldIndex++;
3079 if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) {
3080 nonDefaultFields |= bitAt(fieldIndex);
3081 }
3082 fieldIndex++;
3083 if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) {
3084 nonDefaultFields |= bitAt(fieldIndex);
3085 }
3086 fieldIndex++;
3087 if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex);
3088 fieldIndex++;
3089 if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex);
3090 fieldIndex++;
3091 if (mMovementGranularities != DEFAULT.mMovementGranularities) {
3092 nonDefaultFields |= bitAt(fieldIndex);
3093 }
3094 fieldIndex++;
3095 if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex);
3096 fieldIndex++;
3097 if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) {
3098 nonDefaultFields |= bitAt(fieldIndex);
3099 }
3100 fieldIndex++;
3101 if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex);
3102 fieldIndex++;
3103 if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex);
3104 fieldIndex++;
3105 if (!Objects.equals(mHintText, DEFAULT.mHintText)) {
3106 nonDefaultFields |= bitAt(fieldIndex);
3107 }
3108 fieldIndex++;
3109 if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex);
3110 fieldIndex++;
3111 if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) {
3112 nonDefaultFields |= bitAt(fieldIndex);
3113 }
3114 fieldIndex++;
3115 if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) {
3116 nonDefaultFields |= bitAt(fieldIndex);
3117 }
3118 fieldIndex++;
3119 if (mTextSelectionStart != DEFAULT.mTextSelectionStart) {
3120 nonDefaultFields |= bitAt(fieldIndex);
3121 }
3122 fieldIndex++;
3123 if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) {
3124 nonDefaultFields |= bitAt(fieldIndex);
3125 }
3126 fieldIndex++;
3127 if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex);
3128 fieldIndex++;
3129 if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex);
3130 fieldIndex++;
3131 if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) {
3132 nonDefaultFields |= bitAt(fieldIndex);
3133 }
3134 fieldIndex++;
3135 if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) {
3136 nonDefaultFields |= bitAt(fieldIndex);
3137 }
3138 fieldIndex++;
3139 if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex);
3140 fieldIndex++;
3141 if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex);
3142 fieldIndex++;
3143 if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) {
3144 nonDefaultFields |= bitAt(fieldIndex);
3145 }
3146 fieldIndex++;
3147 if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
3148 nonDefaultFields |= bitAt(fieldIndex);
3149 }
3150 int totalFields = fieldIndex;
3151 parcel.writeLong(nonDefaultFields);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003152
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003153 fieldIndex = 0;
3154 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0);
3155 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId);
3156 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId);
3157 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId);
3158 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId);
3159 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById);
3160 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore);
3161 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003162
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003163 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003164
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003165 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3166 final LongArray childIds = mChildNodeIds;
3167 if (childIds == null) {
3168 parcel.writeInt(0);
3169 } else {
3170 final int childIdsSize = childIds.size();
3171 parcel.writeInt(childIdsSize);
3172 for (int i = 0; i < childIdsSize; i++) {
3173 parcel.writeLong(childIds.get(i));
Kristian Monsen74bc1942014-04-29 11:00:17 -07003174 }
3175 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003176 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003177
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003178 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3179 parcel.writeInt(mBoundsInParent.top);
3180 parcel.writeInt(mBoundsInParent.bottom);
3181 parcel.writeInt(mBoundsInParent.left);
3182 parcel.writeInt(mBoundsInParent.right);
3183 }
3184
3185 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3186 parcel.writeInt(mBoundsInScreen.top);
3187 parcel.writeInt(mBoundsInScreen.bottom);
3188 parcel.writeInt(mBoundsInScreen.left);
3189 parcel.writeInt(mBoundsInScreen.right);
3190 }
3191
3192 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3193 if (mActions != null && !mActions.isEmpty()) {
3194 final int actionCount = mActions.size();
3195
3196 int nonLegacyActionCount = 0;
3197 int defaultLegacyStandardActions = 0;
3198 for (int i = 0; i < actionCount; i++) {
3199 AccessibilityAction action = mActions.get(i);
3200 if (isDefaultLegacyStandardAction(action)) {
3201 defaultLegacyStandardActions |= action.getId();
3202 } else {
3203 nonLegacyActionCount++;
3204 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003205 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003206 parcel.writeInt(defaultLegacyStandardActions);
3207 parcel.writeInt(nonLegacyActionCount);
3208
3209 for (int i = 0; i < actionCount; i++) {
3210 AccessibilityAction action = mActions.get(i);
3211 if (!isDefaultLegacyStandardAction(action)) {
3212 parcel.writeInt(action.getId());
3213 parcel.writeCharSequence(action.getLabel());
3214 }
3215 }
3216 } else {
3217 parcel.writeInt(0);
3218 parcel.writeInt(0);
Kristian Monsen74bc1942014-04-29 11:00:17 -07003219 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003220 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003221
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003222 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength);
3223 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities);
3224 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003225
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003226 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName);
3227 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName);
3228 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText);
3229 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText);
3230 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError);
3231 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3232 parcel.writeCharSequence(mContentDescription);
Phil Weaverc2e28932016-12-08 12:29:25 -08003233 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003234 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName);
Svetoslav6254f482013-06-04 17:22:14 -07003235
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003236 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart);
3237 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd);
3238 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType);
3239 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion);
3240 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent);
Svetoslavbcc46a02013-02-06 11:56:00 -08003241
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003242 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys);
3243
3244 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras);
3245
3246 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav3577a282013-06-06 14:09:10 -07003247 parcel.writeInt(mRangeInfo.getType());
3248 parcel.writeFloat(mRangeInfo.getMin());
3249 parcel.writeFloat(mRangeInfo.getMax());
3250 parcel.writeFloat(mRangeInfo.getCurrent());
Svetoslav3577a282013-06-06 14:09:10 -07003251 }
3252
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003253 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07003254 parcel.writeInt(mCollectionInfo.getRowCount());
3255 parcel.writeInt(mCollectionInfo.getColumnCount());
Svetoslav3577a282013-06-06 14:09:10 -07003256 parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
Alan Viverette76769ae2014-02-12 16:38:10 -08003257 parcel.writeInt(mCollectionInfo.getSelectionMode());
Svetoslav3577a282013-06-06 14:09:10 -07003258 }
3259
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003260 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07003261 parcel.writeInt(mCollectionItemInfo.getRowIndex());
3262 parcel.writeInt(mCollectionItemInfo.getRowSpan());
Alan Viverettefaeac962015-06-01 09:03:27 -07003263 parcel.writeInt(mCollectionItemInfo.getColumnIndex());
3264 parcel.writeInt(mCollectionItemInfo.getColumnSpan());
Svetoslav3577a282013-06-06 14:09:10 -07003265 parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
Alan Viverette76769ae2014-02-12 16:38:10 -08003266 parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003267 }
3268
3269 if (DEBUG) {
3270 fieldIndex--;
3271 if (totalFields != fieldIndex) {
3272 throw new IllegalStateException("Number of fields mismatch: " + totalFields
3273 + " vs " + fieldIndex);
3274 }
Svetoslav3577a282013-06-06 14:09:10 -07003275 }
3276
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003277 // Since instances of this class are fetched via synchronous i.e. blocking
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003278 // calls in IPCs we always recycle as soon as the instance is marshaled.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003279 recycle();
3280 }
3281
3282 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003283 * Initializes this instance from another one.
3284 *
3285 * @param other The other instance.
3286 */
3287 private void init(AccessibilityNodeInfo other) {
3288 mSealed = other.mSealed;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003289 mSourceNodeId = other.mSourceNodeId;
3290 mParentNodeId = other.mParentNodeId;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07003291 mLabelForId = other.mLabelForId;
3292 mLabeledById = other.mLabeledById;
Svetoslav6c702902014-10-09 18:40:56 -07003293 mTraversalBefore = other.mTraversalBefore;
3294 mTraversalAfter = other.mTraversalAfter;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003295 mWindowId = other.mWindowId;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003296 mConnectionId = other.mConnectionId;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003297 mBoundsInParent.set(other.mBoundsInParent);
3298 mBoundsInScreen.set(other.mBoundsInScreen);
3299 mPackageName = other.mPackageName;
3300 mClassName = other.mClassName;
3301 mText = other.mText;
Phil Weaver776afc22016-12-21 10:55:13 -08003302 mHintText = other.mHintText;
Alan Viverettefccbff52014-07-07 15:06:14 -07003303 mError = other.mError;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003304 mContentDescription = other.mContentDescription;
Svetoslav22431a32013-02-05 14:30:19 -08003305 mViewIdResourceName = other.mViewIdResourceName;
Kristian Monsen74bc1942014-04-29 11:00:17 -07003306
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003307 if (mActions != null) mActions.clear();
Kristian Monsen74bc1942014-04-29 11:00:17 -07003308 final ArrayList<AccessibilityAction> otherActions = other.mActions;
3309 if (otherActions != null && otherActions.size() > 0) {
3310 if (mActions == null) {
3311 mActions = new ArrayList(otherActions);
3312 } else {
Kristian Monsen74bc1942014-04-29 11:00:17 -07003313 mActions.addAll(other.mActions);
3314 }
3315 }
3316
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003317 mBooleanProperties = other.mBooleanProperties;
Alan Viverette029942f2014-08-12 14:55:56 -07003318 mMaxTextLength = other.mMaxTextLength;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003319 mMovementGranularities = other.mMovementGranularities;
Alan Viverettef0aed092013-11-06 15:33:03 -08003320
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003321
3322 if (mChildNodeIds != null) mChildNodeIds.clear();
Alan Viverettef0aed092013-11-06 15:33:03 -08003323 final LongArray otherChildNodeIds = other.mChildNodeIds;
3324 if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
3325 if (mChildNodeIds == null) {
3326 mChildNodeIds = otherChildNodeIds.clone();
3327 } else {
3328 mChildNodeIds.addAll(otherChildNodeIds);
3329 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003330 }
Alan Viverettef0aed092013-11-06 15:33:03 -08003331
Svetoslavbcc46a02013-02-06 11:56:00 -08003332 mTextSelectionStart = other.mTextSelectionStart;
3333 mTextSelectionEnd = other.mTextSelectionEnd;
Svetoslav6254f482013-06-04 17:22:14 -07003334 mInputType = other.mInputType;
Alan Viverette77e9a282013-09-12 17:16:09 -07003335 mLiveRegion = other.mLiveRegion;
Phil Weaver1f222542016-01-08 11:49:32 -08003336 mDrawingOrderInParent = other.mDrawingOrderInParent;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003337
Phil Weaverc2e28932016-12-08 12:29:25 -08003338 mExtraDataKeys = other.mExtraDataKeys;
3339
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003340 mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
3341
3342 if (mRangeInfo != null) mRangeInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003343 mRangeInfo = (other.mRangeInfo != null)
3344 ? RangeInfo.obtain(other.mRangeInfo) : null;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003345 if (mCollectionInfo != null) mCollectionInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003346 mCollectionInfo = (other.mCollectionInfo != null)
3347 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003348 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003349 mCollectionItemInfo = (other.mCollectionItemInfo != null)
3350 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003351 }
3352
3353 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003354 * Creates a new instance from a {@link Parcel}.
3355 *
3356 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
3357 */
3358 private void initFromParcel(Parcel parcel) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003359 // Bit mask of non-default-valued field indices
3360 long nonDefaultFields = parcel.readLong();
3361 int fieldIndex = 0;
3362 final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++)
3363 ? (parcel.readInt() == 1)
3364 : DEFAULT.mSealed;
3365 if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong();
3366 if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt();
3367 if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong();
3368 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong();
3369 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong();
3370 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong();
3371 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong();
Svetoslav6c702902014-10-09 18:40:56 -07003372
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003373 if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003374
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003375 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3376 final int childrenSize = parcel.readInt();
3377 if (childrenSize <= 0) {
3378 mChildNodeIds = null;
3379 } else {
3380 mChildNodeIds = new LongArray(childrenSize);
3381 for (int i = 0; i < childrenSize; i++) {
3382 final long childId = parcel.readLong();
3383 mChildNodeIds.add(childId);
3384 }
Alan Viverettef0aed092013-11-06 15:33:03 -08003385 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003386 }
3387
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003388 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3389 mBoundsInParent.top = parcel.readInt();
3390 mBoundsInParent.bottom = parcel.readInt();
3391 mBoundsInParent.left = parcel.readInt();
3392 mBoundsInParent.right = parcel.readInt();
Kristian Monsen74bc1942014-04-29 11:00:17 -07003393 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003394
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003395 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3396 mBoundsInScreen.top = parcel.readInt();
3397 mBoundsInScreen.bottom = parcel.readInt();
3398 mBoundsInScreen.left = parcel.readInt();
3399 mBoundsInScreen.right = parcel.readInt();
Phil Weaverc2e28932016-12-08 12:29:25 -08003400 }
3401
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003402 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3403 final int legacyStandardActions = parcel.readInt();
3404 addLegacyStandardActions(legacyStandardActions);
3405 final int nonLegacyActionCount = parcel.readInt();
3406 for (int i = 0; i < nonLegacyActionCount; i++) {
3407 final AccessibilityAction action = new AccessibilityAction(
3408 parcel.readInt(), parcel.readCharSequence());
3409 addActionUnchecked(action);
3410 }
Svetoslav6254f482013-06-04 17:22:14 -07003411 }
Svetoslav3577a282013-06-06 14:09:10 -07003412
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003413 if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt();
3414 if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt();
3415 if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt();
Svetoslav3577a282013-06-06 14:09:10 -07003416
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003417 if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence();
3418 if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence();
3419 if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence();
3420 if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence();
3421 if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence();
3422 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3423 mContentDescription = parcel.readCharSequence();
Svetoslav3577a282013-06-06 14:09:10 -07003424 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003425 if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
Svetoslav3577a282013-06-06 14:09:10 -07003426
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003427 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt();
3428 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt();
3429
3430 if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt();
3431 if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt();
3432 if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt();
3433
3434 mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++)
3435 ? parcel.createStringArrayList()
3436 : null;
3437
3438 mExtras = isBitSet(nonDefaultFields, fieldIndex++)
3439 ? parcel.readBundle()
3440 : null;
3441
3442 if (mRangeInfo != null) mRangeInfo.recycle();
3443 mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++)
3444 ? RangeInfo.obtain(
3445 parcel.readInt(),
3446 parcel.readFloat(),
3447 parcel.readFloat(),
3448 parcel.readFloat())
3449 : null;
3450
3451 if (mCollectionInfo != null) mCollectionInfo.recycle();
3452 mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++)
3453 ? CollectionInfo.obtain(
3454 parcel.readInt(),
3455 parcel.readInt(),
3456 parcel.readInt() == 1,
3457 parcel.readInt())
3458 : null;
3459
3460 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
3461 mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
3462 ? CollectionItemInfo.obtain(
3463 parcel.readInt(),
3464 parcel.readInt(),
3465 parcel.readInt(),
3466 parcel.readInt(),
3467 parcel.readInt() == 1,
3468 parcel.readInt() == 1)
3469 : null;
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -07003470
3471 mSealed = sealed;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003472 }
3473
3474 /**
3475 * Clears the state of this instance.
3476 */
3477 private void clear() {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003478 init(DEFAULT);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003479 }
3480
Kristian Monsen74bc1942014-04-29 11:00:17 -07003481 private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
3482 return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
3483 && TextUtils.isEmpty(action.getLabel()));
3484 }
3485
3486 private static AccessibilityAction getActionSingleton(int actionId) {
3487 final int actions = AccessibilityAction.sStandardActions.size();
3488 for (int i = 0; i < actions; i++) {
3489 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
3490 if (actionId == currentAction.getId()) {
3491 return currentAction;
3492 }
3493 }
3494
3495 return null;
3496 }
3497
3498 private void addLegacyStandardActions(int actionMask) {
3499 int remainingIds = actionMask;
3500 while (remainingIds > 0) {
3501 final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
3502 remainingIds &= ~id;
3503 AccessibilityAction action = getActionSingleton(id);
3504 addAction(action);
3505 }
3506 }
3507
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003508 /**
3509 * Gets the human readable action symbolic name.
3510 *
3511 * @param action The action.
3512 * @return The symbolic name.
3513 */
3514 private static String getActionSymbolicName(int action) {
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003515 switch (action) {
3516 case ACTION_FOCUS:
3517 return "ACTION_FOCUS";
3518 case ACTION_CLEAR_FOCUS:
3519 return "ACTION_CLEAR_FOCUS";
3520 case ACTION_SELECT:
3521 return "ACTION_SELECT";
3522 case ACTION_CLEAR_SELECTION:
3523 return "ACTION_CLEAR_SELECTION";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07003524 case ACTION_CLICK:
3525 return "ACTION_CLICK";
3526 case ACTION_LONG_CLICK:
3527 return "ACTION_LONG_CLICK";
3528 case ACTION_ACCESSIBILITY_FOCUS:
3529 return "ACTION_ACCESSIBILITY_FOCUS";
3530 case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
3531 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003532 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
3533 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
3534 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
3535 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07003536 case ACTION_NEXT_HTML_ELEMENT:
3537 return "ACTION_NEXT_HTML_ELEMENT";
3538 case ACTION_PREVIOUS_HTML_ELEMENT:
3539 return "ACTION_PREVIOUS_HTML_ELEMENT";
Svetoslav Ganova1dc7612012-05-10 04:14:53 -07003540 case ACTION_SCROLL_FORWARD:
3541 return "ACTION_SCROLL_FORWARD";
3542 case ACTION_SCROLL_BACKWARD:
3543 return "ACTION_SCROLL_BACKWARD";
Svetoslav Ganov242724e2013-02-01 14:42:18 -08003544 case ACTION_CUT:
3545 return "ACTION_CUT";
3546 case ACTION_COPY:
3547 return "ACTION_COPY";
3548 case ACTION_PASTE:
3549 return "ACTION_PASTE";
3550 case ACTION_SET_SELECTION:
3551 return "ACTION_SET_SELECTION";
Steven Dao103a577c2015-10-12 17:35:59 -07003552 case ACTION_EXPAND:
3553 return "ACTION_EXPAND";
3554 case ACTION_COLLAPSE:
3555 return "ACTION_COLLAPSE";
3556 case ACTION_DISMISS:
3557 return "ACTION_DISMISS";
3558 case ACTION_SET_TEXT:
3559 return "ACTION_SET_TEXT";
3560 case R.id.accessibilityActionShowOnScreen:
3561 return "ACTION_SHOW_ON_SCREEN";
3562 case R.id.accessibilityActionScrollToPosition:
3563 return "ACTION_SCROLL_TO_POSITION";
3564 case R.id.accessibilityActionScrollUp:
3565 return "ACTION_SCROLL_UP";
3566 case R.id.accessibilityActionScrollLeft:
3567 return "ACTION_SCROLL_LEFT";
3568 case R.id.accessibilityActionScrollDown:
3569 return "ACTION_SCROLL_DOWN";
3570 case R.id.accessibilityActionScrollRight:
3571 return "ACTION_SCROLL_RIGHT";
3572 case R.id.accessibilityActionSetProgress:
3573 return "ACTION_SET_PROGRESS";
3574 case R.id.accessibilityActionContextClick:
3575 return "ACTION_CONTEXT_CLICK";
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003576 default:
Steven Dao103a577c2015-10-12 17:35:59 -07003577 return "ACTION_UNKNOWN";
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003578 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003579 }
3580
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003581 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003582 * Gets the human readable movement granularity symbolic name.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003583 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003584 * @param granularity The granularity.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003585 * @return The symbolic name.
3586 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003587 private static String getMovementGranularitySymbolicName(int granularity) {
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003588 switch (granularity) {
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003589 case MOVEMENT_GRANULARITY_CHARACTER:
3590 return "MOVEMENT_GRANULARITY_CHARACTER";
3591 case MOVEMENT_GRANULARITY_WORD:
3592 return "MOVEMENT_GRANULARITY_WORD";
3593 case MOVEMENT_GRANULARITY_LINE:
3594 return "MOVEMENT_GRANULARITY_LINE";
3595 case MOVEMENT_GRANULARITY_PARAGRAPH:
3596 return "MOVEMENT_GRANULARITY_PARAGRAPH";
3597 case MOVEMENT_GRANULARITY_PAGE:
3598 return "MOVEMENT_GRANULARITY_PAGE";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003599 default:
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003600 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003601 }
3602 }
3603
Svetoslav Ganov02107852011-10-03 17:06:56 -07003604 private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
Phil Weaver23161e72017-04-19 12:16:36 -07003605 return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
3606 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
3607 && (mConnectionId != UNDEFINED_CONNECTION_ID));
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003608 }
3609
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003610 @Override
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003611 public boolean equals(Object object) {
3612 if (this == object) {
3613 return true;
3614 }
3615 if (object == null) {
3616 return false;
3617 }
3618 if (getClass() != object.getClass()) {
3619 return false;
3620 }
3621 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003622 if (mSourceNodeId != other.mSourceNodeId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003623 return false;
3624 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07003625 if (mWindowId != other.mWindowId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003626 return false;
3627 }
3628 return true;
3629 }
3630
3631 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003632 public int hashCode() {
3633 final int prime = 31;
3634 int result = 1;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003635 result = prime * result + getAccessibilityViewId(mSourceNodeId);
3636 result = prime * result + getVirtualDescendantId(mSourceNodeId);
3637 result = prime * result + mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003638 return result;
3639 }
3640
3641 @Override
3642 public String toString() {
3643 StringBuilder builder = new StringBuilder();
3644 builder.append(super.toString());
3645
3646 if (DEBUG) {
Svetoslav8e3feb12014-02-24 13:46:47 -08003647 builder.append("; sourceNodeId: " + mSourceNodeId);
Svetoslav Ganov02107852011-10-03 17:06:56 -07003648 builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
3649 builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
3650 builder.append("; mParentNodeId: " + mParentNodeId);
Svetoslav6c702902014-10-09 18:40:56 -07003651 builder.append("; traversalBefore: ").append(mTraversalBefore);
3652 builder.append("; traversalAfter: ").append(mTraversalAfter);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003653
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003654 int granularities = mMovementGranularities;
3655 builder.append("; MovementGranularities: [");
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003656 while (granularities != 0) {
3657 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
3658 granularities &= ~granularity;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003659 builder.append(getMovementGranularitySymbolicName(granularity));
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003660 if (granularities != 0) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003661 builder.append(", ");
3662 }
3663 }
3664 builder.append("]");
3665
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003666 builder.append("; childAccessibilityIds: [");
Alan Viverettef0aed092013-11-06 15:33:03 -08003667 final LongArray childIds = mChildNodeIds;
3668 if (childIds != null) {
3669 for (int i = 0, count = childIds.size(); i < count; i++) {
3670 builder.append(childIds.get(i));
3671 if (i < count - 1) {
3672 builder.append(", ");
3673 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003674 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003675 }
3676 builder.append("]");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003677 }
3678
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003679 builder.append("; boundsInParent: " + mBoundsInParent);
3680 builder.append("; boundsInScreen: " + mBoundsInScreen);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003681
3682 builder.append("; packageName: ").append(mPackageName);
3683 builder.append("; className: ").append(mClassName);
3684 builder.append("; text: ").append(mText);
Alan Viverettefccbff52014-07-07 15:06:14 -07003685 builder.append("; error: ").append(mError);
Alan Viverette029942f2014-08-12 14:55:56 -07003686 builder.append("; maxTextLength: ").append(mMaxTextLength);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003687 builder.append("; contentDescription: ").append(mContentDescription);
Svetoslav22431a32013-02-05 14:30:19 -08003688 builder.append("; viewIdResName: ").append(mViewIdResourceName);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003689
3690 builder.append("; checkable: ").append(isCheckable());
3691 builder.append("; checked: ").append(isChecked());
3692 builder.append("; focusable: ").append(isFocusable());
3693 builder.append("; focused: ").append(isFocused());
3694 builder.append("; selected: ").append(isSelected());
3695 builder.append("; clickable: ").append(isClickable());
3696 builder.append("; longClickable: ").append(isLongClickable());
Mady Mellore8608912015-06-05 09:02:55 -07003697 builder.append("; contextClickable: ").append(isContextClickable());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003698 builder.append("; enabled: ").append(isEnabled());
3699 builder.append("; password: ").append(isPassword());
Kristian Monsen74bc1942014-04-29 11:00:17 -07003700 builder.append("; scrollable: ").append(isScrollable());
Phil Weaver4d3eec412016-09-01 16:28:34 -07003701 builder.append("; importantForAccessibility: ").append(isImportantForAccessibility());
Kristian Monsen74bc1942014-04-29 11:00:17 -07003702 builder.append("; actions: ").append(mActions);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003703
3704 return builder.toString();
3705 }
3706
Svetoslav6c702902014-10-09 18:40:56 -07003707 private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
3708 if (!canPerformRequestOverConnection(accessibilityId)) {
3709 return null;
3710 }
3711 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
3712 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
3713 mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
Phil Weaverc2e28932016-12-08 12:29:25 -08003714 | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
Svetoslav6c702902014-10-09 18:40:56 -07003715 }
3716
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003717 /**
Kristian Monsen74bc1942014-04-29 11:00:17 -07003718 * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
3719 * Each action has a unique id that is mandatory and optional data.
3720 * <p>
3721 * There are three categories of actions:
3722 * <ul>
3723 * <li><strong>Standard actions</strong> - These are actions that are reported and
3724 * handled by the standard UI widgets in the platform. For each standard action
3725 * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
Phil Weaver426361c2017-02-22 13:06:25 -08003726 * These actions will have {@code null} labels.
Kristian Monsen74bc1942014-04-29 11:00:17 -07003727 * </li>
3728 * <li><strong>Custom actions action</strong> - These are actions that are reported
3729 * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
3730 * example, an application may define a custom action for clearing the user history.
3731 * </li>
3732 * <li><strong>Overriden standard actions</strong> - These are actions that override
3733 * standard actions to customize them. For example, an app may add a label to the
Casey Burkhardt7ef48be2016-01-31 11:51:09 -08003734 * standard {@link #ACTION_CLICK} action to announce that this action clears browsing history.
Kristian Monsen74bc1942014-04-29 11:00:17 -07003735 * </ul>
3736 * </p>
Casey Burkhardt7ef48be2016-01-31 11:51:09 -08003737 * <p>
3738 * Actions are typically added to an {@link AccessibilityNodeInfo} by using
3739 * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within
3740 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed
3741 * within {@link View#performAccessibilityAction(int, Bundle)}.
3742 * </p>
3743 * <p class="note">
3744 * <strong>Note:</strong> Views which support these actions should invoke
3745 * {@link View#setImportantForAccessibility(int)} with
3746 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService}
3747 * can discover the set of supported actions.
3748 * </p>
Kristian Monsen74bc1942014-04-29 11:00:17 -07003749 */
3750 public static final class AccessibilityAction {
3751
3752 /**
3753 * Action that gives input focus to the node.
3754 */
3755 public static final AccessibilityAction ACTION_FOCUS =
3756 new AccessibilityAction(
3757 AccessibilityNodeInfo.ACTION_FOCUS, null);
3758
3759 /**
3760 * Action that clears input focus of the node.
3761 */
3762 public static final AccessibilityAction ACTION_CLEAR_FOCUS =
3763 new AccessibilityAction(
3764 AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
3765
3766 /**
3767 * Action that selects the node.
3768 */
3769 public static final AccessibilityAction ACTION_SELECT =
3770 new AccessibilityAction(
3771 AccessibilityNodeInfo.ACTION_SELECT, null);
3772
3773 /**
3774 * Action that deselects the node.
3775 */
3776 public static final AccessibilityAction ACTION_CLEAR_SELECTION =
3777 new AccessibilityAction(
3778 AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
3779
3780 /**
3781 * Action that clicks on the node info.
3782 */
3783 public static final AccessibilityAction ACTION_CLICK =
3784 new AccessibilityAction(
3785 AccessibilityNodeInfo.ACTION_CLICK, null);
3786
3787 /**
3788 * Action that long clicks on the node.
3789 */
3790 public static final AccessibilityAction ACTION_LONG_CLICK =
3791 new AccessibilityAction(
3792 AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
3793
3794 /**
3795 * Action that gives accessibility focus to the node.
3796 */
3797 public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
3798 new AccessibilityAction(
3799 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
3800
3801 /**
3802 * Action that clears accessibility focus of the node.
3803 */
3804 public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
3805 new AccessibilityAction(
3806 AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
3807
3808 /**
3809 * Action that requests to go to the next entity in this node's text
3810 * at a given movement granularity. For example, move to the next character,
3811 * word, etc.
3812 * <p>
3813 * <strong>Arguments:</strong>
3814 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3815 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3816 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3817 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3818 * <strong>Example:</strong> Move to the previous character and do not extend selection.
3819 * <code><pre><p>
3820 * Bundle arguments = new Bundle();
3821 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3822 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3823 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3824 * false);
3825 * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
3826 * arguments);
3827 * </code></pre></p>
3828 * </p>
3829 *
3830 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3831 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3832 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3833 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3834 *
3835 * @see AccessibilityNodeInfo#setMovementGranularities(int)
3836 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3837 * @see AccessibilityNodeInfo#getMovementGranularities()
3838 * AccessibilityNodeInfo.getMovementGranularities()
3839 *
3840 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3841 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3842 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3843 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3844 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3845 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3846 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3847 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3848 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3849 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3850 */
3851 public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
3852 new AccessibilityAction(
3853 AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
3854
3855 /**
3856 * Action that requests to go to the previous entity in this node's text
3857 * at a given movement granularity. For example, move to the next character,
3858 * word, etc.
3859 * <p>
3860 * <strong>Arguments:</strong>
3861 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3862 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
3863 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3864 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
3865 * <strong>Example:</strong> Move to the next character and do not extend selection.
3866 * <code><pre><p>
3867 * Bundle arguments = new Bundle();
3868 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
3869 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
3870 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
3871 * false);
3872 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
3873 * arguments);
3874 * </code></pre></p>
3875 * </p>
3876 *
3877 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3878 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
3879 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3880 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
3881 *
3882 * @see AccessibilityNodeInfo#setMovementGranularities(int)
3883 * AccessibilityNodeInfo.setMovementGranularities(int)
3884 * @see AccessibilityNodeInfo#getMovementGranularities()
3885 * AccessibilityNodeInfo.getMovementGranularities()
3886 *
3887 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
3888 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
3889 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
3890 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
3891 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
3892 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
3893 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
3894 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
3895 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
3896 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
3897 */
3898 public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
3899 new AccessibilityAction(
3900 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
3901
3902 /**
3903 * Action to move to the next HTML element of a given type. For example, move
3904 * to the BUTTON, INPUT, TABLE, etc.
3905 * <p>
3906 * <strong>Arguments:</strong>
3907 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3908 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3909 * <strong>Example:</strong>
3910 * <code><pre><p>
3911 * Bundle arguments = new Bundle();
3912 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3913 * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
3914 * </code></pre></p>
3915 * </p>
3916 */
3917 public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
3918 new AccessibilityAction(
3919 AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
3920
3921 /**
3922 * Action to move to the previous HTML element of a given type. For example, move
3923 * to the BUTTON, INPUT, TABLE, etc.
3924 * <p>
3925 * <strong>Arguments:</strong>
3926 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
3927 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
3928 * <strong>Example:</strong>
3929 * <code><pre><p>
3930 * Bundle arguments = new Bundle();
3931 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
3932 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
3933 * </code></pre></p>
3934 * </p>
3935 */
3936 public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
3937 new AccessibilityAction(
3938 AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
3939
3940 /**
3941 * Action to scroll the node content forward.
3942 */
3943 public static final AccessibilityAction ACTION_SCROLL_FORWARD =
3944 new AccessibilityAction(
3945 AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
3946
3947 /**
3948 * Action to scroll the node content backward.
3949 */
3950 public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
3951 new AccessibilityAction(
3952 AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
3953
3954 /**
3955 * Action to copy the current selection to the clipboard.
3956 */
3957 public static final AccessibilityAction ACTION_COPY =
3958 new AccessibilityAction(
3959 AccessibilityNodeInfo.ACTION_COPY, null);
3960
3961 /**
3962 * Action to paste the current clipboard content.
3963 */
3964 public static final AccessibilityAction ACTION_PASTE =
3965 new AccessibilityAction(
3966 AccessibilityNodeInfo.ACTION_PASTE, null);
3967
3968 /**
3969 * Action to cut the current selection and place it to the clipboard.
3970 */
3971 public static final AccessibilityAction ACTION_CUT =
3972 new AccessibilityAction(
3973 AccessibilityNodeInfo.ACTION_CUT, null);
3974
3975 /**
3976 * Action to set the selection. Performing this action with no arguments
3977 * clears the selection.
3978 * <p>
3979 * <strong>Arguments:</strong>
3980 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3981 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
3982 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3983 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
3984 * <strong>Example:</strong>
3985 * <code><pre><p>
3986 * Bundle arguments = new Bundle();
3987 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
3988 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
3989 * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
3990 * </code></pre></p>
3991 * </p>
3992 *
3993 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
3994 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
3995 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
3996 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
3997 */
3998 public static final AccessibilityAction ACTION_SET_SELECTION =
3999 new AccessibilityAction(
4000 AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
4001
4002 /**
4003 * Action to expand an expandable node.
4004 */
4005 public static final AccessibilityAction ACTION_EXPAND =
4006 new AccessibilityAction(
4007 AccessibilityNodeInfo.ACTION_EXPAND, null);
4008
4009 /**
4010 * Action to collapse an expandable node.
4011 */
4012 public static final AccessibilityAction ACTION_COLLAPSE =
4013 new AccessibilityAction(
4014 AccessibilityNodeInfo.ACTION_COLLAPSE, null);
4015
4016 /**
4017 * Action to dismiss a dismissable node.
4018 */
4019 public static final AccessibilityAction ACTION_DISMISS =
4020 new AccessibilityAction(
4021 AccessibilityNodeInfo.ACTION_DISMISS, null);
4022
4023 /**
4024 * Action that sets the text of the node. Performing the action without argument,
4025 * using <code> null</code> or empty {@link CharSequence} will clear the text. This
4026 * action will also put the cursor at the end of text.
4027 * <p>
4028 * <strong>Arguments:</strong>
4029 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
4030 * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
4031 * <strong>Example:</strong>
4032 * <code><pre><p>
4033 * Bundle arguments = new Bundle();
4034 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
4035 * "android");
4036 * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
4037 * </code></pre></p>
4038 */
4039 public static final AccessibilityAction ACTION_SET_TEXT =
4040 new AccessibilityAction(
4041 AccessibilityNodeInfo.ACTION_SET_TEXT, null);
4042
Alan Viverette26c44ee2015-03-25 14:54:13 -07004043 /**
4044 * Action that requests the node make its bounding rectangle visible
4045 * on the screen, scrolling if necessary just enough.
4046 *
4047 * @see View#requestRectangleOnScreen(Rect)
4048 */
4049 public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
Alan Viverette23f44322015-04-06 16:04:56 -07004050 new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
Alan Viverette26c44ee2015-03-25 14:54:13 -07004051
Alan Viverette23f44322015-04-06 16:04:56 -07004052 /**
4053 * Action that scrolls the node to make the specified collection
4054 * position visible on screen.
4055 * <p>
4056 * <strong>Arguments:</strong>
4057 * <ul>
4058 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
4059 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
4060 * <ul>
4061 *
4062 * @see AccessibilityNodeInfo#getCollectionInfo()
4063 */
4064 public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
4065 new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
4066
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004067 /**
4068 * Action to scroll the node content up.
4069 */
4070 public static final AccessibilityAction ACTION_SCROLL_UP =
4071 new AccessibilityAction(R.id.accessibilityActionScrollUp, null);
4072
4073 /**
4074 * Action to scroll the node content left.
4075 */
4076 public static final AccessibilityAction ACTION_SCROLL_LEFT =
4077 new AccessibilityAction(R.id.accessibilityActionScrollLeft, null);
4078
4079 /**
4080 * Action to scroll the node content down.
4081 */
4082 public static final AccessibilityAction ACTION_SCROLL_DOWN =
4083 new AccessibilityAction(R.id.accessibilityActionScrollDown, null);
4084
4085 /**
4086 * Action to scroll the node content right.
4087 */
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004088 public static final AccessibilityAction ACTION_SCROLL_RIGHT =
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004089 new AccessibilityAction(R.id.accessibilityActionScrollRight, null);
4090
Mady Mellord2744002015-04-30 16:17:16 -07004091 /**
Mady Mellore8608912015-06-05 09:02:55 -07004092 * Action that context clicks the node.
Mady Mellore82067b2015-04-30 09:58:35 -07004093 */
Mady Mellore8608912015-06-05 09:02:55 -07004094 public static final AccessibilityAction ACTION_CONTEXT_CLICK =
4095 new AccessibilityAction(R.id.accessibilityActionContextClick, null);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004096
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004097 /**
4098 * Action that sets progress between {@link RangeInfo#getMin() RangeInfo.getMin()} and
4099 * {@link RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as
4100 * {@link RangeInfo#getType() RangeInfo.getType()}
4101 * <p>
4102 * <strong>Arguments:</strong>
4103 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE}
4104 *
4105 * @see RangeInfo
4106 */
4107 public static final AccessibilityAction ACTION_SET_PROGRESS =
4108 new AccessibilityAction(R.id.accessibilityActionSetProgress, null);
4109
Phil Weaverf00cd142017-03-03 13:44:00 -08004110 /**
4111 * Action to move a window to a new location.
4112 * <p>
4113 * <strong>Arguments:</strong>
4114 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X}
4115 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y}
4116 */
4117 public static final AccessibilityAction ACTION_MOVE_WINDOW =
4118 new AccessibilityAction(R.id.accessibilityActionMoveWindow, null);
4119
Alan Viverette23f44322015-04-06 16:04:56 -07004120 private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
Kristian Monsen74bc1942014-04-29 11:00:17 -07004121 static {
4122 sStandardActions.add(ACTION_FOCUS);
4123 sStandardActions.add(ACTION_CLEAR_FOCUS);
4124 sStandardActions.add(ACTION_SELECT);
4125 sStandardActions.add(ACTION_CLEAR_SELECTION);
4126 sStandardActions.add(ACTION_CLICK);
4127 sStandardActions.add(ACTION_LONG_CLICK);
4128 sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
4129 sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
4130 sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
4131 sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
4132 sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
4133 sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
4134 sStandardActions.add(ACTION_SCROLL_FORWARD);
4135 sStandardActions.add(ACTION_SCROLL_BACKWARD);
4136 sStandardActions.add(ACTION_COPY);
4137 sStandardActions.add(ACTION_PASTE);
4138 sStandardActions.add(ACTION_CUT);
4139 sStandardActions.add(ACTION_SET_SELECTION);
4140 sStandardActions.add(ACTION_EXPAND);
4141 sStandardActions.add(ACTION_COLLAPSE);
4142 sStandardActions.add(ACTION_DISMISS);
4143 sStandardActions.add(ACTION_SET_TEXT);
Alan Viverette26c44ee2015-03-25 14:54:13 -07004144 sStandardActions.add(ACTION_SHOW_ON_SCREEN);
Alan Viverette23f44322015-04-06 16:04:56 -07004145 sStandardActions.add(ACTION_SCROLL_TO_POSITION);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004146 sStandardActions.add(ACTION_SCROLL_UP);
4147 sStandardActions.add(ACTION_SCROLL_LEFT);
4148 sStandardActions.add(ACTION_SCROLL_DOWN);
4149 sStandardActions.add(ACTION_SCROLL_RIGHT);
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004150 sStandardActions.add(ACTION_SET_PROGRESS);
Mady Mellore8608912015-06-05 09:02:55 -07004151 sStandardActions.add(ACTION_CONTEXT_CLICK);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004152 }
4153
4154 private final int mActionId;
4155 private final CharSequence mLabel;
4156
4157 /**
4158 * Creates a new AccessibilityAction. For adding a standard action without a specific label,
4159 * use the static constants.
4160 *
4161 * You can also override the description for one the standard actions. Below is an example
4162 * how to override the standard click action by adding a custom label:
4163 * <pre>
4164 * AccessibilityAction action = new AccessibilityAction(
Phil Weaverc3791292016-09-12 11:06:49 -07004165 * AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel());
Kristian Monsen74bc1942014-04-29 11:00:17 -07004166 * node.addAction(action);
4167 * </pre>
4168 *
4169 * @param actionId The id for this action. This should either be one of the
4170 * standard actions or a specific action for your app. In that case it is
4171 * required to use a resource identifier.
4172 * @param label The label for the new AccessibilityAction.
4173 */
4174 public AccessibilityAction(int actionId, @Nullable CharSequence label) {
Svetoslav5c4cd182014-05-21 14:53:16 -07004175 if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
Kristian Monsen74bc1942014-04-29 11:00:17 -07004176 throw new IllegalArgumentException("Invalid standard action id");
4177 }
4178
Kristian Monsen74bc1942014-04-29 11:00:17 -07004179 mActionId = actionId;
4180 mLabel = label;
4181 }
4182
4183 /**
4184 * Gets the id for this action.
4185 *
4186 * @return The action id.
4187 */
4188 public int getId() {
4189 return mActionId;
4190 }
4191
4192 /**
4193 * Gets the label for this action. Its purpose is to describe the
4194 * action to user.
4195 *
4196 * @return The label.
4197 */
4198 public CharSequence getLabel() {
4199 return mLabel;
4200 }
4201
4202 @Override
4203 public int hashCode() {
4204 return mActionId;
4205 }
4206
4207 @Override
4208 public boolean equals(Object other) {
4209 if (other == null) {
4210 return false;
4211 }
4212
4213 if (other == this) {
4214 return true;
4215 }
4216
4217 if (getClass() != other.getClass()) {
4218 return false;
4219 }
4220
4221 return mActionId == ((AccessibilityAction)other).mActionId;
4222 }
4223
4224 @Override
4225 public String toString() {
4226 return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
4227 }
4228 }
4229
4230 /**
Svetoslav3577a282013-06-06 14:09:10 -07004231 * Class with information if a node is a range. Use
Phil Weaver764152b2016-07-19 11:32:27 -07004232 * {@link RangeInfo#obtain(int, float, float, float)} to get an instance. Recycling is
4233 * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
Svetoslav3577a282013-06-06 14:09:10 -07004234 */
4235 public static final class RangeInfo {
4236 private static final int MAX_POOL_SIZE = 10;
4237
4238 /** Range type: integer. */
4239 public static final int RANGE_TYPE_INT = 0;
4240 /** Range type: float. */
4241 public static final int RANGE_TYPE_FLOAT = 1;
4242 /** Range type: percent with values from zero to one.*/
4243 public static final int RANGE_TYPE_PERCENT = 2;
4244
4245 private static final SynchronizedPool<RangeInfo> sPool =
4246 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
4247
4248 private int mType;
4249 private float mMin;
4250 private float mMax;
4251 private float mCurrent;
4252
4253 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004254 * Obtains a pooled instance that is a clone of another one.
4255 *
4256 * @param other The instance to clone.
4257 *
4258 * @hide
4259 */
4260 public static RangeInfo obtain(RangeInfo other) {
4261 return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
4262 }
4263
4264 /**
Svetoslav3577a282013-06-06 14:09:10 -07004265 * Obtains a pooled instance.
4266 *
4267 * @param type The type of the range.
Phil Weaver79e44192016-12-19 14:24:49 -08004268 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
4269 * minimum.
4270 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
4271 * maximum.
Svetoslav3577a282013-06-06 14:09:10 -07004272 * @param current The current value.
4273 */
4274 public static RangeInfo obtain(int type, float min, float max, float current) {
4275 RangeInfo info = sPool.acquire();
Steven Dao24142812016-04-13 15:25:09 -07004276 if (info == null) {
4277 return new RangeInfo(type, min, max, current);
4278 }
4279
4280 info.mType = type;
4281 info.mMin = min;
4282 info.mMax = max;
4283 info.mCurrent = current;
4284 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004285 }
4286
4287 /**
4288 * Creates a new range.
4289 *
4290 * @param type The type of the range.
Phil Weaver79e44192016-12-19 14:24:49 -08004291 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
4292 * minimum.
4293 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
4294 * maximum.
Svetoslav3577a282013-06-06 14:09:10 -07004295 * @param current The current value.
4296 */
4297 private RangeInfo(int type, float min, float max, float current) {
4298 mType = type;
4299 mMin = min;
4300 mMax = max;
4301 mCurrent = current;
4302 }
4303
4304 /**
4305 * Gets the range type.
4306 *
4307 * @return The range type.
4308 *
4309 * @see #RANGE_TYPE_INT
4310 * @see #RANGE_TYPE_FLOAT
4311 * @see #RANGE_TYPE_PERCENT
4312 */
4313 public int getType() {
4314 return mType;
4315 }
4316
4317 /**
Phil Weaver79e44192016-12-19 14:24:49 -08004318 * Gets the minimum value.
Svetoslav3577a282013-06-06 14:09:10 -07004319 *
Phil Weaver79e44192016-12-19 14:24:49 -08004320 * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists.
Svetoslav3577a282013-06-06 14:09:10 -07004321 */
4322 public float getMin() {
4323 return mMin;
4324 }
4325
4326 /**
Phil Weaver79e44192016-12-19 14:24:49 -08004327 * Gets the maximum value.
Svetoslav3577a282013-06-06 14:09:10 -07004328 *
Phil Weaver79e44192016-12-19 14:24:49 -08004329 * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists.
Svetoslav3577a282013-06-06 14:09:10 -07004330 */
4331 public float getMax() {
4332 return mMax;
4333 }
4334
4335 /**
4336 * Gets the current value.
4337 *
4338 * @return The current value.
4339 */
4340 public float getCurrent() {
4341 return mCurrent;
4342 }
4343
4344 /**
4345 * Recycles this instance.
4346 */
4347 void recycle() {
4348 clear();
4349 sPool.release(this);
4350 }
4351
4352 private void clear() {
4353 mType = 0;
4354 mMin = 0;
4355 mMax = 0;
4356 mCurrent = 0;
4357 }
4358 }
4359
4360 /**
4361 * Class with information if a node is a collection. Use
Phil Weaver764152b2016-07-19 11:32:27 -07004362 * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance. Recycling is
4363 * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004364 * <p>
4365 * A collection of items has rows and columns and may be hierarchical.
4366 * For example, a horizontal list is a collection with one column, as
4367 * many rows as the list items, and is not hierarchical; A table is a
4368 * collection with several rows, several columns, and is not hierarchical;
4369 * A vertical tree is a hierarchical collection with one column and
4370 * as many rows as the first level children.
4371 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07004372 */
4373 public static final class CollectionInfo {
Alan Viverette76769ae2014-02-12 16:38:10 -08004374 /** Selection mode where items are not selectable. */
4375 public static final int SELECTION_MODE_NONE = 0;
4376
4377 /** Selection mode where a single item may be selected. */
4378 public static final int SELECTION_MODE_SINGLE = 1;
4379
4380 /** Selection mode where multiple items may be selected. */
4381 public static final int SELECTION_MODE_MULTIPLE = 2;
4382
Svetoslav3577a282013-06-06 14:09:10 -07004383 private static final int MAX_POOL_SIZE = 20;
4384
4385 private static final SynchronizedPool<CollectionInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -07004386 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav3577a282013-06-06 14:09:10 -07004387
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004388 private int mRowCount;
4389 private int mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004390 private boolean mHierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004391 private int mSelectionMode;
Svetoslav3577a282013-06-06 14:09:10 -07004392
4393 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004394 * Obtains a pooled instance that is a clone of another one.
4395 *
4396 * @param other The instance to clone.
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004397 * @hide
4398 */
4399 public static CollectionInfo obtain(CollectionInfo other) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004400 return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
4401 other.mSelectionMode);
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004402 }
4403
4404 /**
Svetoslav3577a282013-06-06 14:09:10 -07004405 * Obtains a pooled instance.
4406 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004407 * @param rowCount The number of rows.
4408 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004409 * @param hierarchical Whether the collection is hierarchical.
4410 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004411 public static CollectionInfo obtain(int rowCount, int columnCount,
4412 boolean hierarchical) {
4413 return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
4414 }
4415
4416 /**
4417 * Obtains a pooled instance.
4418 *
4419 * @param rowCount The number of rows.
4420 * @param columnCount The number of columns.
4421 * @param hierarchical Whether the collection is hierarchical.
4422 * @param selectionMode The collection's selection mode, one of:
4423 * <ul>
4424 * <li>{@link #SELECTION_MODE_NONE}
4425 * <li>{@link #SELECTION_MODE_SINGLE}
4426 * <li>{@link #SELECTION_MODE_MULTIPLE}
4427 * </ul>
4428 */
4429 public static CollectionInfo obtain(int rowCount, int columnCount,
4430 boolean hierarchical, int selectionMode) {
4431 final CollectionInfo info = sPool.acquire();
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004432 if (info == null) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004433 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004434 }
4435
4436 info.mRowCount = rowCount;
4437 info.mColumnCount = columnCount;
4438 info.mHierarchical = hierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004439 info.mSelectionMode = selectionMode;
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004440 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004441 }
4442
4443 /**
4444 * Creates a new instance.
4445 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004446 * @param rowCount The number of rows.
4447 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004448 * @param hierarchical Whether the collection is hierarchical.
Alan Viverette76769ae2014-02-12 16:38:10 -08004449 * @param selectionMode The collection's selection mode.
Svetoslav3577a282013-06-06 14:09:10 -07004450 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004451 private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
4452 int selectionMode) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004453 mRowCount = rowCount;
4454 mColumnCount = columnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004455 mHierarchical = hierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004456 mSelectionMode = selectionMode;
Svetoslav3577a282013-06-06 14:09:10 -07004457 }
4458
4459 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004460 * Gets the number of rows.
Svetoslav3577a282013-06-06 14:09:10 -07004461 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004462 * @return The row count.
Svetoslav3577a282013-06-06 14:09:10 -07004463 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004464 public int getRowCount() {
4465 return mRowCount;
Svetoslav3577a282013-06-06 14:09:10 -07004466 }
4467
4468 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004469 * Gets the number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004470 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004471 * @return The column count.
Svetoslav3577a282013-06-06 14:09:10 -07004472 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004473 public int getColumnCount() {
4474 return mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004475 }
4476
4477 /**
4478 * Gets if the collection is a hierarchically ordered.
4479 *
4480 * @return Whether the collection is hierarchical.
4481 */
4482 public boolean isHierarchical() {
4483 return mHierarchical;
4484 }
4485
4486 /**
Alan Viverette76769ae2014-02-12 16:38:10 -08004487 * Gets the collection's selection mode.
4488 *
4489 * @return The collection's selection mode, one of:
4490 * <ul>
4491 * <li>{@link #SELECTION_MODE_NONE}
4492 * <li>{@link #SELECTION_MODE_SINGLE}
4493 * <li>{@link #SELECTION_MODE_MULTIPLE}
4494 * </ul>
4495 */
4496 public int getSelectionMode() {
4497 return mSelectionMode;
4498 }
4499
4500 /**
Svetoslav3577a282013-06-06 14:09:10 -07004501 * Recycles this instance.
4502 */
4503 void recycle() {
4504 clear();
4505 sPool.release(this);
4506 }
4507
4508 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004509 mRowCount = 0;
4510 mColumnCount = 0;
Svetoslav3577a282013-06-06 14:09:10 -07004511 mHierarchical = false;
Alan Viverette76769ae2014-02-12 16:38:10 -08004512 mSelectionMode = SELECTION_MODE_NONE;
Svetoslav3577a282013-06-06 14:09:10 -07004513 }
4514 }
4515
4516 /**
4517 * Class with information if a node is a collection item. Use
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004518 * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
Phil Weaver764152b2016-07-19 11:32:27 -07004519 * to get an instance. Recycling is handled by the {@link AccessibilityNodeInfo} to which this
4520 * object is attached.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004521 * <p>
4522 * A collection item is contained in a collection, it starts at
4523 * a given row and column in the collection, and spans one or
4524 * more rows and columns. For example, a header of two related
4525 * table columns starts at the first row and the first column,
4526 * spans one row and two columns.
4527 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07004528 */
4529 public static final class CollectionItemInfo {
4530 private static final int MAX_POOL_SIZE = 20;
4531
4532 private static final SynchronizedPool<CollectionItemInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -07004533 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav3577a282013-06-06 14:09:10 -07004534
4535 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004536 * Obtains a pooled instance that is a clone of another one.
4537 *
4538 * @param other The instance to clone.
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004539 * @hide
4540 */
4541 public static CollectionItemInfo obtain(CollectionItemInfo other) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004542 return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
4543 other.mColumnSpan, other.mHeading, other.mSelected);
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004544 }
4545
4546 /**
Svetoslav3577a282013-06-06 14:09:10 -07004547 * Obtains a pooled instance.
4548 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004549 * @param rowIndex The row index at which the item is located.
4550 * @param rowSpan The number of rows the item spans.
4551 * @param columnIndex The column index at which the item is located.
4552 * @param columnSpan The number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004553 * @param heading Whether the item is a heading.
4554 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004555 public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4556 int columnIndex, int columnSpan, boolean heading) {
4557 return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
4558 }
4559
4560 /**
4561 * Obtains a pooled instance.
4562 *
4563 * @param rowIndex The row index at which the item is located.
4564 * @param rowSpan The number of rows the item spans.
4565 * @param columnIndex The column index at which the item is located.
4566 * @param columnSpan The number of columns the item spans.
4567 * @param heading Whether the item is a heading.
4568 * @param selected Whether the item is selected.
4569 */
4570 public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4571 int columnIndex, int columnSpan, boolean heading, boolean selected) {
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004572 final CollectionItemInfo info = sPool.acquire();
4573 if (info == null) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004574 return new CollectionItemInfo(
4575 rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004576 }
4577
4578 info.mRowIndex = rowIndex;
4579 info.mRowSpan = rowSpan;
4580 info.mColumnIndex = columnIndex;
4581 info.mColumnSpan = columnSpan;
4582 info.mHeading = heading;
Alan Viverette76769ae2014-02-12 16:38:10 -08004583 info.mSelected = selected;
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004584 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004585 }
4586
4587 private boolean mHeading;
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004588 private int mColumnIndex;
4589 private int mRowIndex;
4590 private int mColumnSpan;
4591 private int mRowSpan;
Alan Viverette76769ae2014-02-12 16:38:10 -08004592 private boolean mSelected;
Svetoslav3577a282013-06-06 14:09:10 -07004593
4594 /**
4595 * Creates a new instance.
4596 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004597 * @param rowIndex The row index at which the item is located.
4598 * @param rowSpan The number of rows the item spans.
4599 * @param columnIndex The column index at which the item is located.
4600 * @param columnSpan The number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004601 * @param heading Whether the item is a heading.
4602 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004603 private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
4604 boolean heading, boolean selected) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004605 mRowIndex = rowIndex;
4606 mRowSpan = rowSpan;
4607 mColumnIndex = columnIndex;
4608 mColumnSpan = columnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004609 mHeading = heading;
Alan Viverette76769ae2014-02-12 16:38:10 -08004610 mSelected = selected;
Svetoslav3577a282013-06-06 14:09:10 -07004611 }
4612
4613 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004614 * Gets the column index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07004615 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004616 * @return The column index.
Svetoslav3577a282013-06-06 14:09:10 -07004617 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004618 public int getColumnIndex() {
4619 return mColumnIndex;
Svetoslav3577a282013-06-06 14:09:10 -07004620 }
4621
4622 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004623 * Gets the row index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07004624 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004625 * @return The row index.
Svetoslav3577a282013-06-06 14:09:10 -07004626 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004627 public int getRowIndex() {
4628 return mRowIndex;
Svetoslav3577a282013-06-06 14:09:10 -07004629 }
4630
4631 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004632 * Gets the number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004633 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004634 * @return The column span.
Svetoslav3577a282013-06-06 14:09:10 -07004635 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004636 public int getColumnSpan() {
4637 return mColumnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004638 }
4639
4640 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004641 * Gets the number of rows the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004642 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004643 * @return The row span.
Svetoslav3577a282013-06-06 14:09:10 -07004644 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004645 public int getRowSpan() {
4646 return mRowSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004647 }
4648
4649 /**
4650 * Gets if the collection item is a heading. For example, section
4651 * heading, table header, etc.
4652 *
4653 * @return If the item is a heading.
4654 */
4655 public boolean isHeading() {
4656 return mHeading;
4657 }
4658
4659 /**
Alan Viverette76769ae2014-02-12 16:38:10 -08004660 * Gets if the collection item is selected.
4661 *
4662 * @return If the item is selected.
4663 */
4664 public boolean isSelected() {
4665 return mSelected;
4666 }
4667
4668 /**
Svetoslav3577a282013-06-06 14:09:10 -07004669 * Recycles this instance.
4670 */
4671 void recycle() {
4672 clear();
4673 sPool.release(this);
4674 }
4675
4676 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004677 mColumnIndex = 0;
4678 mColumnSpan = 0;
4679 mRowIndex = 0;
4680 mRowSpan = 0;
Svetoslav3577a282013-06-06 14:09:10 -07004681 mHeading = false;
Alan Viverette76769ae2014-02-12 16:38:10 -08004682 mSelected = false;
Svetoslav3577a282013-06-06 14:09:10 -07004683 }
4684 }
4685
4686 /**
Alan Viverettef0aed092013-11-06 15:33:03 -08004687 * @see android.os.Parcelable.Creator
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004688 */
4689 public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
4690 new Parcelable.Creator<AccessibilityNodeInfo>() {
Alan Viverettef0aed092013-11-06 15:33:03 -08004691 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004692 public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
4693 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
4694 info.initFromParcel(parcel);
4695 return info;
4696 }
4697
Alan Viverettef0aed092013-11-06 15:33:03 -08004698 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004699 public AccessibilityNodeInfo[] newArray(int size) {
4700 return new AccessibilityNodeInfo[size];
4701 }
4702 };
4703}