blob: a8a787edde04b2a47d934fbc72b5dec65e1d8fcb [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;
Rhed Jaoae638752018-09-18 19:40:13 +080026import android.annotation.NonNull;
Kristian Monsen74bc1942014-04-29 11:00:17 -070027import android.annotation.Nullable;
Phil Weaver62d20fa2016-09-15 11:05:55 -070028import android.annotation.TestApi;
Mathew Inwooda570dee2018-08-17 14:56:00 +010029import android.annotation.UnsupportedAppUsage;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070030import android.graphics.Rect;
Rhed Jaoae638752018-09-18 19:40:13 +080031import android.graphics.Region;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -070032import android.os.Bundle;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070033import android.os.Parcel;
34import android.os.Parcelable;
Svetoslav6254f482013-06-04 17:22:14 -070035import android.text.InputType;
Phil Weaver193520e2016-12-13 09:39:06 -080036import android.text.Spannable;
Phil Weaver0ebe6bd2017-02-21 16:24:31 -080037import android.text.SpannableStringBuilder;
Phil Weaver193520e2016-12-13 09:39:06 -080038import android.text.Spanned;
Kristian Monsen74bc1942014-04-29 11:00:17 -070039import android.text.TextUtils;
Phil Weaver193520e2016-12-13 09:39:06 -080040import android.text.style.AccessibilityClickableSpan;
41import android.text.style.AccessibilityURLSpan;
42import android.text.style.ClickableSpan;
43import android.text.style.URLSpan;
Rhed Jaoae638752018-09-18 19:40:13 +080044import android.util.ArrayMap;
Kristian Monsen74bc1942014-04-29 11:00:17 -070045import android.util.ArraySet;
qinyige0b5ca242018-12-27 19:56:54 +080046import android.util.Log;
Alan Viverettef0aed092013-11-06 15:33:03 -080047import android.util.LongArray;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -080048import android.util.Pools.SynchronizedPool;
Rhed Jaoae638752018-09-18 19:40:13 +080049import android.view.TouchDelegate;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070050import android.view.View;
51
Alan Viverette26c44ee2015-03-25 14:54:13 -070052import com.android.internal.R;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -070053import com.android.internal.util.CollectionUtils;
Rhed Jaoae638752018-09-18 19:40:13 +080054import com.android.internal.util.Preconditions;
Alan Viverette26c44ee2015-03-25 14:54:13 -070055
Kristian Monsen74bc1942014-04-29 11:00:17 -070056import java.util.ArrayList;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070057import java.util.Collections;
58import java.util.List;
Rhed Jaoae638752018-09-18 19:40:13 +080059import java.util.Map;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -070060import java.util.Objects;
Phil Weaverb010b122016-08-17 17:47:48 -070061import java.util.concurrent.atomic.AtomicInteger;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -070062
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070063/**
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070064 * This class represents a node of the window content as well as actions that
65 * can be requested from its source. From the point of view of an
Phil Weaver40ded282016-01-25 15:49:02 -080066 * {@link android.accessibilityservice.AccessibilityService} a window's content is
67 * presented as a tree of accessibility node infos, which may or may not map one-to-one
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070068 * to the view hierarchy. In other words, a custom view is free to report itself as
69 * a tree of accessibility node info.
70 * </p>
71 * <p>
72 * Once an accessibility node info is delivered to an accessibility service it is
73 * made immutable and calling a state mutation method generates an error.
74 * </p>
75 * <p>
76 * Please refer to {@link android.accessibilityservice.AccessibilityService} for
77 * details about how to obtain a handle to window content as a tree of accessibility
Phil Weaver40ded282016-01-25 15:49:02 -080078 * node info as well as details about the security model.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070079 * </p>
Joe Fernandeze1302ed2012-02-06 14:30:15 -080080 * <div class="special reference">
81 * <h3>Developer Guides</h3>
82 * <p>For more information about making applications accessible, read the
83 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
84 * developer guide.</p>
85 * </div>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070086 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -070087 * @see android.accessibilityservice.AccessibilityService
88 * @see AccessibilityEvent
89 * @see AccessibilityManager
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070090 */
91public class AccessibilityNodeInfo implements Parcelable {
92
93 private static final boolean DEBUG = false;
94
qinyige0b5ca242018-12-27 19:56:54 +080095 private static final String TAG = "AccessibilityNodeInfo";
96
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080097 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -080098 public static final int UNDEFINED_CONNECTION_ID = -1;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -080099
100 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -0800101 public static final int UNDEFINED_SELECTION_INDEX = -1;
Svetoslav Ganov0d04e242012-02-21 13:46:36 -0800102
103 /** @hide */
Svetoslav8e3feb12014-02-24 13:46:47 -0800104 public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE;
105
106 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -0800107 public static final int ROOT_ITEM_ID = Integer.MAX_VALUE - 1;
Svetoslav8e3feb12014-02-24 13:46:47 -0800108
109 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -0800110 public static final long UNDEFINED_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID);
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -0800111
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800112 /** @hide */
Phil Weaverf00cd142017-03-03 13:44:00 -0800113 public static final long ROOT_NODE_ID = makeNodeId(ROOT_ITEM_ID,
114 AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav1e0d4af2014-04-10 17:41:29 -0700115
116 /** @hide */
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800117 public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001;
118
119 /** @hide */
120 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002;
121
122 /** @hide */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700123 public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004;
124
125 /** @hide */
Svetoslav Ganov80943d82013-01-02 10:25:37 -0800126 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008;
127
128 /** @hide */
129 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800130
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700131 // Actions.
132
133 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700134 * Action that gives input focus to the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700135 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700136 public static final int ACTION_FOCUS = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700137
138 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700139 * Action that clears input focus of the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700140 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700141 public static final int ACTION_CLEAR_FOCUS = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700142
143 /**
144 * Action that selects the node.
145 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700146 public static final int ACTION_SELECT = 0x00000004;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700147
148 /**
Kristian Monsen74bc1942014-04-29 11:00:17 -0700149 * Action that deselects the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700150 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700151 public static final int ACTION_CLEAR_SELECTION = 0x00000008;
152
153 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700154 * Action that clicks on the node info.
Maxim Bogatov219b41d2015-05-01 14:00:24 -0700155 *
156 * See {@link AccessibilityAction#ACTION_CLICK}
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700157 */
158 public static final int ACTION_CLICK = 0x00000010;
159
160 /**
Svetoslav Ganov6d17a932012-04-27 19:30:38 -0700161 * Action that long clicks on the node.
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700162 */
163 public static final int ACTION_LONG_CLICK = 0x00000020;
164
165 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700166 * Action that gives accessibility focus to the node.
167 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700168 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700169
170 /**
171 * Action that clears accessibility focus of the node.
172 */
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700173 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700174
175 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700176 * Action that requests to go to the next entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700177 * at a given movement granularity. For example, move to the next character,
178 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700179 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800180 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
181 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
182 * <strong>Example:</strong> Move to the previous character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700183 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700184 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700185 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
186 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800187 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
188 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700189 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700190 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700191 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700192 *
Svetoslav7c512842013-01-30 23:02:08 -0800193 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
194 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
195 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700196 * @see #setMovementGranularities(int)
197 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700198 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700199 * @see #MOVEMENT_GRANULARITY_CHARACTER
200 * @see #MOVEMENT_GRANULARITY_WORD
201 * @see #MOVEMENT_GRANULARITY_LINE
202 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
203 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700204 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700205 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700206
207 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700208 * Action that requests to go to the previous entity in this node's text
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700209 * at a given movement granularity. For example, move to the next character,
210 * word, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700211 * <p>
Svetoslav7c512842013-01-30 23:02:08 -0800212 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
213 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
214 * <strong>Example:</strong> Move to the next character and do not extend selection.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700215 * <code><pre><p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700216 * Bundle arguments = new Bundle();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700217 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
218 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
Svetoslav7c512842013-01-30 23:02:08 -0800219 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
220 * false);
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700221 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
222 * arguments);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700223 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700224 * </p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700225 *
Svetoslav7c512842013-01-30 23:02:08 -0800226 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
227 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
228 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700229 * @see #setMovementGranularities(int)
230 * @see #getMovementGranularities()
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700231 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700232 * @see #MOVEMENT_GRANULARITY_CHARACTER
233 * @see #MOVEMENT_GRANULARITY_WORD
234 * @see #MOVEMENT_GRANULARITY_LINE
235 * @see #MOVEMENT_GRANULARITY_PARAGRAPH
236 * @see #MOVEMENT_GRANULARITY_PAGE
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700237 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700238 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700239
240 /**
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700241 * Action to move to the next HTML element of a given type. For example, move
242 * to the BUTTON, INPUT, TABLE, etc.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700243 * <p>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700244 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
245 * <strong>Example:</strong>
246 * <code><pre><p>
247 * Bundle arguments = new Bundle();
248 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
249 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
250 * </code></pre></p>
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700251 * </p>
252 */
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700253 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
254
255 /**
256 * Action to move to the previous HTML element of a given type. For example, move
257 * to the BUTTON, INPUT, TABLE, etc.
258 * <p>
259 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
260 * <strong>Example:</strong>
261 * <code><pre><p>
262 * Bundle arguments = new Bundle();
263 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
264 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
265 * </code></pre></p>
266 * </p>
267 */
268 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
269
270 /**
Svetoslav Ganova1dc7612012-05-10 04:14:53 -0700271 * Action to scroll the node content forward.
272 */
273 public static final int ACTION_SCROLL_FORWARD = 0x00001000;
274
275 /**
276 * Action to scroll the node content backward.
277 */
278 public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
279
280 /**
Svetoslav7c512842013-01-30 23:02:08 -0800281 * Action to copy the current selection to the clipboard.
282 */
283 public static final int ACTION_COPY = 0x00004000;
284
285 /**
286 * Action to paste the current clipboard content.
287 */
288 public static final int ACTION_PASTE = 0x00008000;
289
290 /**
291 * Action to cut the current selection and place it to the clipboard.
292 */
293 public static final int ACTION_CUT = 0x00010000;
294
295 /**
296 * Action to set the selection. Performing this action with no arguments
297 * clears the selection.
298 * <p>
Alan Viverette23f44322015-04-06 16:04:56 -0700299 * <strong>Arguments:</strong>
300 * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
Svetoslav7c512842013-01-30 23:02:08 -0800301 * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
302 * <strong>Example:</strong>
303 * <code><pre><p>
304 * Bundle arguments = new Bundle();
305 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
306 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
307 * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
308 * </code></pre></p>
309 * </p>
310 *
311 * @see #ACTION_ARGUMENT_SELECTION_START_INT
312 * @see #ACTION_ARGUMENT_SELECTION_END_INT
313 */
314 public static final int ACTION_SET_SELECTION = 0x00020000;
315
316 /**
Svetoslav3577a282013-06-06 14:09:10 -0700317 * Action to expand an expandable node.
318 */
319 public static final int ACTION_EXPAND = 0x00040000;
320
321 /**
322 * Action to collapse an expandable node.
323 */
324 public static final int ACTION_COLLAPSE = 0x00080000;
325
326 /**
327 * Action to dismiss a dismissable node.
328 */
329 public static final int ACTION_DISMISS = 0x00100000;
330
Guang Zhu4cd353c2014-02-12 19:54:30 -0800331 /**
332 * Action that sets the text of the node. Performing the action without argument, using <code>
333 * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
334 * cursor at the end of text.
335 * <p>
Alan Viverette23f44322015-04-06 16:04:56 -0700336 * <strong>Arguments:</strong>
337 * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
Guang Zhu4cd353c2014-02-12 19:54:30 -0800338 * <strong>Example:</strong>
339 * <code><pre><p>
340 * Bundle arguments = new Bundle();
341 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
342 * "android");
343 * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
344 * </code></pre></p>
345 */
346 public static final int ACTION_SET_TEXT = 0x00200000;
347
Eugene Susla554edd32017-05-24 16:49:59 -0700348 /** @hide */
349 public static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
Kristian Monsen74bc1942014-04-29 11:00:17 -0700350
351 /**
352 * Mask to see if the value is larger than the largest ACTION_ constant
353 */
354 private static final int ACTION_TYPE_MASK = 0xFF000000;
355
Svetoslav3577a282013-06-06 14:09:10 -0700356 // Action arguments
357
358 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700359 * Argument for which movement granularity to be used when traversing the node text.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700360 * <p>
361 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700362 * <strong>Actions:</strong>
363 * <ul>
364 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
365 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
366 * </ul>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700367 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800368 *
Alan Viverette23f44322015-04-06 16:04:56 -0700369 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
370 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700371 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700372 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
Svetoslav7c512842013-01-30 23:02:08 -0800373 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700374
375 /**
376 * Argument for which HTML element to get moving to the next/previous HTML element.
377 * <p>
378 * <strong>Type:</strong> String<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700379 * <strong>Actions:</strong>
380 * <ul>
381 * <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li>
382 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li>
383 * </ul>
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700384 * </p>
Svetoslav7c512842013-01-30 23:02:08 -0800385 *
Alan Viverette23f44322015-04-06 16:04:56 -0700386 * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT
387 * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700388 */
389 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
Svetoslav7c512842013-01-30 23:02:08 -0800390 "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
391
392 /**
393 * Argument for whether when moving at granularity to extend the selection
394 * or to move it otherwise.
395 * <p>
396 * <strong>Type:</strong> boolean<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700397 * <strong>Actions:</strong>
398 * <ul>
399 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
400 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
401 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800402 *
Alan Viverette23f44322015-04-06 16:04:56 -0700403 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
404 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
Svetoslav7c512842013-01-30 23:02:08 -0800405 */
406 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
407 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
408
409 /**
410 * Argument for specifying the selection start.
411 * <p>
412 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700413 * <strong>Actions:</strong>
414 * <ul>
415 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
416 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800417 *
Alan Viverette23f44322015-04-06 16:04:56 -0700418 * @see AccessibilityAction#ACTION_SET_SELECTION
Svetoslav7c512842013-01-30 23:02:08 -0800419 */
420 public static final String ACTION_ARGUMENT_SELECTION_START_INT =
421 "ACTION_ARGUMENT_SELECTION_START_INT";
422
423 /**
424 * Argument for specifying the selection end.
425 * <p>
426 * <strong>Type:</strong> int<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700427 * <strong>Actions:</strong>
428 * <ul>
429 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
430 * </ul>
Svetoslav7c512842013-01-30 23:02:08 -0800431 *
Alan Viverette23f44322015-04-06 16:04:56 -0700432 * @see AccessibilityAction#ACTION_SET_SELECTION
Svetoslav7c512842013-01-30 23:02:08 -0800433 */
434 public static final String ACTION_ARGUMENT_SELECTION_END_INT =
435 "ACTION_ARGUMENT_SELECTION_END_INT";
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700436
Guang Zhu4cd353c2014-02-12 19:54:30 -0800437 /**
Alan Viverette23f44322015-04-06 16:04:56 -0700438 * Argument for specifying the text content to set.
Guang Zhu4cd353c2014-02-12 19:54:30 -0800439 * <p>
440 * <strong>Type:</strong> CharSequence<br>
Alan Viverette23f44322015-04-06 16:04:56 -0700441 * <strong>Actions:</strong>
442 * <ul>
443 * <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li>
444 * </ul>
Guang Zhu4cd353c2014-02-12 19:54:30 -0800445 *
Alan Viverette23f44322015-04-06 16:04:56 -0700446 * @see AccessibilityAction#ACTION_SET_TEXT
Guang Zhu4cd353c2014-02-12 19:54:30 -0800447 */
448 public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
449 "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
450
Alan Viverette23f44322015-04-06 16:04:56 -0700451 /**
452 * Argument for specifying the collection row to make visible on screen.
453 * <p>
454 * <strong>Type:</strong> int<br>
455 * <strong>Actions:</strong>
456 * <ul>
457 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
458 * </ul>
459 *
460 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
461 */
462 public static final String ACTION_ARGUMENT_ROW_INT =
463 "android.view.accessibility.action.ARGUMENT_ROW_INT";
464
465 /**
466 * Argument for specifying the collection column to make visible on screen.
467 * <p>
468 * <strong>Type:</strong> int<br>
469 * <strong>Actions:</strong>
470 * <ul>
471 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
472 * </ul>
473 *
474 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
475 */
476 public static final String ACTION_ARGUMENT_COLUMN_INT =
477 "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
478
Maxim Bogatov32e59d52015-04-30 16:57:33 -0700479 /**
480 * Argument for specifying the progress value to set.
481 * <p>
482 * <strong>Type:</strong> float<br>
483 * <strong>Actions:</strong>
484 * <ul>
485 * <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li>
486 * </ul>
487 *
488 * @see AccessibilityAction#ACTION_SET_PROGRESS
489 */
490 public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
491 "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
492
Phil Weaver193520e2016-12-13 09:39:06 -0800493 /**
Phil Weaverf00cd142017-03-03 13:44:00 -0800494 * Argument for specifying the x coordinate to which to move a window.
495 * <p>
496 * <strong>Type:</strong> int<br>
497 * <strong>Actions:</strong>
498 * <ul>
499 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
500 * </ul>
501 *
502 * @see AccessibilityAction#ACTION_MOVE_WINDOW
503 */
504 public static final String ACTION_ARGUMENT_MOVE_WINDOW_X =
Phil Weaverbe2922f2017-04-28 14:58:35 -0700505 "ACTION_ARGUMENT_MOVE_WINDOW_X";
Phil Weaverf00cd142017-03-03 13:44:00 -0800506
507 /**
508 * Argument for specifying the y coordinate to which to move a window.
509 * <p>
510 * <strong>Type:</strong> int<br>
511 * <strong>Actions:</strong>
512 * <ul>
513 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li>
514 * </ul>
515 *
516 * @see AccessibilityAction#ACTION_MOVE_WINDOW
517 */
518 public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y =
Phil Weaverbe2922f2017-04-28 14:58:35 -0700519 "ACTION_ARGUMENT_MOVE_WINDOW_Y";
Phil Weaverf00cd142017-03-03 13:44:00 -0800520
521 /**
Phil Weaver193520e2016-12-13 09:39:06 -0800522 * Argument to pass the {@link AccessibilityClickableSpan}.
523 * For use with R.id.accessibilityActionClickOnClickableSpan
524 * @hide
525 */
526 public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
527 "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
528
Svetoslav3577a282013-06-06 14:09:10 -0700529 // Focus types
530
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700531 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -0700532 * The input focus.
533 */
534 public static final int FOCUS_INPUT = 1;
535
536 /**
537 * The accessibility focus.
538 */
539 public static final int FOCUS_ACCESSIBILITY = 2;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700540
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700541 // Movement granularities
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700542
543 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700544 * Movement granularity bit for traversing the text of a node by character.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700545 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700546 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700547
548 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700549 * Movement granularity bit for traversing the text of a node by word.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700550 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700551 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700552
553 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700554 * Movement granularity bit for traversing the text of a node by line.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700555 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700556 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700557
558 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700559 * Movement granularity bit for traversing the text of a node by paragraph.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700560 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700561 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700562
563 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700564 * Movement granularity bit for traversing the text of a node by page.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700565 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700566 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -0700567
Phil Weaverc2e28932016-12-08 12:29:25 -0800568 /**
569 * Key used to request and locate extra data for text character location. This key requests that
570 * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with
571 * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two
572 * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and
573 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid
574 * inside the CharSequence returned by {@link #getText()}, and the length must be positive.
575 * <p>
576 * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this
577 * string as a key for {@link Bundle#getParcelableArray(String)}. The
578 * {@link android.graphics.RectF} will be null for characters that either do not exist or are
579 * off the screen.
580 *
581 * {@see #refreshWithExtraData(String, Bundle)}
582 */
583 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY =
584 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY";
585
586 /**
587 * Integer argument specifying the start index of the requested text location data. Must be
588 * valid inside the CharSequence returned by {@link #getText()}.
589 *
Aurimas Liutikase701dc12018-06-01 16:04:37 -0700590 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
Phil Weaverc2e28932016-12-08 12:29:25 -0800591 */
592 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX =
593 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX";
594
595 /**
596 * Integer argument specifying the end index of the requested text location data. Must be
597 * positive.
598 *
Aurimas Liutikase701dc12018-06-01 16:04:37 -0700599 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
Phil Weaverc2e28932016-12-08 12:29:25 -0800600 */
601 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH =
602 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
603
604 /** @hide */
605 public static final String EXTRA_DATA_REQUESTED_KEY =
606 "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested";
607
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700608 // Boolean attributes.
609
Svetoslavbcc46a02013-02-06 11:56:00 -0800610 private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700611
Svetoslavbcc46a02013-02-06 11:56:00 -0800612 private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700613
Svetoslavbcc46a02013-02-06 11:56:00 -0800614 private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700615
Svetoslavbcc46a02013-02-06 11:56:00 -0800616 private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700617
Svetoslavbcc46a02013-02-06 11:56:00 -0800618 private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700619
Svetoslavbcc46a02013-02-06 11:56:00 -0800620 private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700621
Svetoslavbcc46a02013-02-06 11:56:00 -0800622 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400;
Svetoslav Ganov42138042012-03-20 11:51:39 -0700623
Svetoslavbcc46a02013-02-06 11:56:00 -0800624 private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800;
625
626 private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -0700627
Alan Viverette77e9a282013-09-12 17:16:09 -0700628 private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000;
Svetoslav3577a282013-06-06 14:09:10 -0700629
Alan Viverette77e9a282013-09-12 17:16:09 -0700630 private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000;
Svetoslav3577a282013-06-06 14:09:10 -0700631
Alan Viverette77e9a282013-09-12 17:16:09 -0700632 private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000;
Svetoslav3577a282013-06-06 14:09:10 -0700633
Alan Viverette77e9a282013-09-12 17:16:09 -0700634 private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000;
Svetoslav3577a282013-06-06 14:09:10 -0700635
Casey Burkhardt2d80ae42016-01-31 12:52:23 -0800636 private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
637
Phil Weaver1e6ecc62017-11-07 15:28:21 -0800638 private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x0080000;
639
Phil Weaver776afc22016-12-21 10:55:13 -0800640 private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
641
Phil Weaver6290fb592018-01-08 17:42:18 -0800642 private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x0200000;
643
Rhed Jaoa42495e2018-08-08 16:01:18 +0800644 private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x0400000;
645
Svetoslav Ganov02107852011-10-03 17:06:56 -0700646 /**
647 * Bits that provide the id of a virtual descendant of a view.
648 */
649 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700650 /**
651 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
652 * virtual descendant of a view. Such a descendant does not exist in the view
653 * hierarchy and is only reported via the accessibility APIs.
654 */
655 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32;
656
Phil Weaver62d20fa2016-09-15 11:05:55 -0700657 private static AtomicInteger sNumInstancesInUse;
Phil Weaverb010b122016-08-17 17:47:48 -0700658
Svetoslav Ganov02107852011-10-03 17:06:56 -0700659 /**
Phil Weavere1951292017-08-18 17:56:04 +0000660 * Gets the accessibility view id which identifies a View in the view three.
Svetoslav Ganov02107852011-10-03 17:06:56 -0700661 *
662 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
663 * @return The accessibility view id part of the node id.
664 *
665 * @hide
666 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100667 @UnsupportedAppUsage
Svetoslav Ganov02107852011-10-03 17:06:56 -0700668 public static int getAccessibilityViewId(long accessibilityNodeId) {
669 return (int) accessibilityNodeId;
670 }
671
672 /**
673 * Gets the virtual descendant id which identifies an imaginary view in a
674 * containing View.
675 *
676 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
677 * @return The virtual view id part of the node id.
678 *
679 * @hide
680 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100681 @UnsupportedAppUsage
Svetoslav Ganov02107852011-10-03 17:06:56 -0700682 public static int getVirtualDescendantId(long accessibilityNodeId) {
683 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK)
684 >> VIRTUAL_DESCENDANT_ID_SHIFT);
685 }
686
687 /**
688 * Makes a node id by shifting the <code>virtualDescendantId</code>
689 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking
690 * the bitwise or with the <code>accessibilityViewId</code>.
691 *
692 * @param accessibilityViewId A View accessibility id.
693 * @param virtualDescendantId A virtual descendant id.
694 * @return The node id.
695 *
696 * @hide
697 */
698 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) {
699 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId;
700 }
701
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700702 // Housekeeping.
703 private static final int MAX_POOL_SIZE = 50;
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -0800704 private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -0700705 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -0800706
Eugene Susla0eb2b6e2017-05-15 14:06:32 -0700707 private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo();
708
Mathew Inwooda570dee2018-08-17 14:56:00 +0100709 @UnsupportedAppUsage
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700710 private boolean mSealed;
711
712 // Data.
Phil Weaver23161e72017-04-19 12:16:36 -0700713 private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
Mathew Inwooda570dee2018-08-17 14:56:00 +0100714 @UnsupportedAppUsage
Phil Weaverf00cd142017-03-03 13:44:00 -0800715 private long mSourceNodeId = UNDEFINED_NODE_ID;
716 private long mParentNodeId = UNDEFINED_NODE_ID;
717 private long mLabelForId = UNDEFINED_NODE_ID;
718 private long mLabeledById = UNDEFINED_NODE_ID;
719 private long mTraversalBefore = UNDEFINED_NODE_ID;
720 private long mTraversalAfter = UNDEFINED_NODE_ID;
Svetoslav Ganovf3b4f312011-11-30 18:15:01 -0800721
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700722 private int mBooleanProperties;
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700723 private final Rect mBoundsInParent = new Rect();
724 private final Rect mBoundsInScreen = new Rect();
Phil Weaver1f222542016-01-08 11:49:32 -0800725 private int mDrawingOrderInParent;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700726
727 private CharSequence mPackageName;
728 private CharSequence mClassName;
Phil Weaver193520e2016-12-13 09:39:06 -0800729 // Hidden, unparceled value used to hold the original value passed to setText
730 private CharSequence mOriginalText;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700731 private CharSequence mText;
Phil Weaver776afc22016-12-21 10:55:13 -0800732 private CharSequence mHintText;
Alan Viverettefccbff52014-07-07 15:06:14 -0700733 private CharSequence mError;
Phil Weaver9f26b3d2018-01-04 10:04:37 -0800734 private CharSequence mPaneTitle;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700735 private CharSequence mContentDescription;
Phil Weaverd89905f2018-01-10 08:28:04 -0800736 private CharSequence mTooltipText;
Svetoslav9fa1ee52013-04-22 12:43:03 -0700737 private String mViewIdResourceName;
Phil Weaverc2e28932016-12-08 12:29:25 -0800738 private ArrayList<String> mExtraDataKeys;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700739
Mathew Inwooda570dee2018-08-17 14:56:00 +0100740 @UnsupportedAppUsage
Alan Viverettef0aed092013-11-06 15:33:03 -0800741 private LongArray mChildNodeIds;
Kristian Monsen74bc1942014-04-29 11:00:17 -0700742 private ArrayList<AccessibilityAction> mActions;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700743
Alan Viverette029942f2014-08-12 14:55:56 -0700744 private int mMaxTextLength = -1;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -0700745 private int mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -0700746
Svetoslav8e3feb12014-02-24 13:46:47 -0800747 private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
748 private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
Svetoslav6254f482013-06-04 17:22:14 -0700749 private int mInputType = InputType.TYPE_NULL;
Alan Viverette77e9a282013-09-12 17:16:09 -0700750 private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
Svetoslav6254f482013-06-04 17:22:14 -0700751
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -0700752 private Bundle mExtras;
Svetoslavbcc46a02013-02-06 11:56:00 -0800753
Svetoslav8e3feb12014-02-24 13:46:47 -0800754 private int mConnectionId = UNDEFINED_CONNECTION_ID;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700755
Svetoslav3577a282013-06-06 14:09:10 -0700756 private RangeInfo mRangeInfo;
757 private CollectionInfo mCollectionInfo;
758 private CollectionItemInfo mCollectionItemInfo;
759
Rhed Jaoae638752018-09-18 19:40:13 +0800760 private TouchDelegateInfo mTouchDelegateInfo;
761
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700762 /**
763 * Hide constructor from clients.
764 */
765 private AccessibilityNodeInfo() {
766 /* do nothing */
767 }
768
769 /**
770 * Sets the source.
Svetoslav Ganov02107852011-10-03 17:06:56 -0700771 * <p>
772 * <strong>Note:</strong> Cannot be called from an
773 * {@link android.accessibilityservice.AccessibilityService}.
774 * This class is made immutable before being delivered to an AccessibilityService.
775 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700776 *
777 * @param source The info source.
778 */
779 public void setSource(View source) {
Phil Weaverf00cd142017-03-03 13:44:00 -0800780 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -0700781 }
782
783 /**
784 * Sets the source to be a virtual descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700785 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -0700786 * is set as the source.
787 * <p>
788 * A virtual descendant is an imaginary View that is reported as a part of the view
789 * hierarchy for accessibility purposes. This enables custom views that draw complex
Svetoslav Ganov71b4e712011-10-25 11:31:31 -0700790 * content to report themselves as a tree of virtual views, thus conveying their
Svetoslav Ganov02107852011-10-03 17:06:56 -0700791 * logical structure.
792 * </p>
793 * <p>
794 * <strong>Note:</strong> Cannot be called from an
795 * {@link android.accessibilityservice.AccessibilityService}.
796 * This class is made immutable before being delivered to an AccessibilityService.
797 * </p>
798 *
799 * @param root The root of the virtual subtree.
800 * @param virtualDescendantId The id of the virtual descendant.
801 */
802 public void setSource(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700803 enforceNotSealed();
Svetoslav8e3feb12014-02-24 13:46:47 -0800804 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700805 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -0800806 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -0700807 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700808 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700809
Svetoslav Ganov42138042012-03-20 11:51:39 -0700810 /**
Svetoslav Ganov005b83b2012-04-16 18:17:17 -0700811 * Find the view that has the specified focus type. The search starts from
Svetoslav Ganov42138042012-03-20 11:51:39 -0700812 * the view represented by this node info.
813 *
814 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
815 * {@link #FOCUS_ACCESSIBILITY}.
816 * @return The node info of the focused view or null.
817 *
818 * @see #FOCUS_INPUT
819 * @see #FOCUS_ACCESSIBILITY
820 */
821 public AccessibilityNodeInfo findFocus(int focus) {
822 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700823 enforceValidFocusType(focus);
Rhed Jaoae638752018-09-18 19:40:13 +0800824 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700825 return null;
826 }
827 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
828 mSourceNodeId, focus);
829 }
830
831 /**
832 * Searches for the nearest view in the specified direction that can take
833 * the input focus.
834 *
835 * @param direction The direction. Can be one of:
836 * {@link View#FOCUS_DOWN},
837 * {@link View#FOCUS_UP},
838 * {@link View#FOCUS_LEFT},
839 * {@link View#FOCUS_RIGHT},
840 * {@link View#FOCUS_FORWARD},
Svetoslav Ganov8ffe8b32012-06-15 10:31:31 -0700841 * {@link View#FOCUS_BACKWARD}.
Svetoslav Ganov42138042012-03-20 11:51:39 -0700842 *
843 * @return The node info for the view that can take accessibility focus.
844 */
845 public AccessibilityNodeInfo focusSearch(int direction) {
846 enforceSealed();
Svetoslav Ganov2ef69052012-06-04 08:55:16 -0700847 enforceValidFocusDirection(direction);
Rhed Jaoae638752018-09-18 19:40:13 +0800848 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700849 return null;
850 }
851 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
852 mSourceNodeId, direction);
853 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700854
855 /**
856 * Gets the id of the window from which the info comes from.
857 *
858 * @return The window id.
859 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700860 public int getWindowId() {
Svetoslav Ganov02107852011-10-03 17:06:56 -0700861 return mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700862 }
863
864 /**
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800865 * Refreshes this info with the latest state of the view it represents.
866 * <p>
867 * <strong>Note:</strong> If this method returns false this info is obsolete
868 * since it represents a view that is no longer in the view tree and should
869 * be recycled.
870 * </p>
Svetoslav6254f482013-06-04 17:22:14 -0700871 *
872 * @param bypassCache Whether to bypass the cache.
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800873 * @return Whether the refresh succeeded.
Svetoslav6254f482013-06-04 17:22:14 -0700874 *
875 * @hide
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800876 */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100877 @UnsupportedAppUsage
Phil Weaverc2e28932016-12-08 12:29:25 -0800878 public boolean refresh(Bundle arguments, boolean bypassCache) {
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800879 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +0800880 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800881 return false;
882 }
883 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
884 AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId(
Phil Weaverc2e28932016-12-08 12:29:25 -0800885 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments);
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800886 if (refreshedInfo == null) {
887 return false;
888 }
Phil Weavercc797d52017-08-21 12:45:11 -0700889 // Hard-to-reproduce bugs seem to be due to some tools recycling a node on another
890 // thread. If that happens, the init will re-seal the node, which then is in a bad state
891 // when it is obtained. Enforce sealing again before we init to fail when a node has been
892 // recycled during a refresh to catch such errors earlier.
893 enforceSealed();
Svetoslav Ganov0b0afb42012-12-03 16:51:53 -0800894 init(refreshedInfo);
895 refreshedInfo.recycle();
896 return true;
897 }
898
899 /**
Svetoslav6254f482013-06-04 17:22:14 -0700900 * Refreshes this info with the latest state of the view it represents.
Phil Weaverc2e28932016-12-08 12:29:25 -0800901 *
902 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
903 * by this node is no longer in the view tree (and thus this node is obsolete and should be
904 * recycled).
Svetoslav6254f482013-06-04 17:22:14 -0700905 */
906 public boolean refresh() {
Phil Weaverc2e28932016-12-08 12:29:25 -0800907 return refresh(null, true);
908 }
909
910 /**
911 * Refreshes this info with the latest state of the view it represents, and request new
912 * data be added by the View.
913 *
Phil Weaver84994332018-05-01 09:26:01 -0700914 * @param extraDataKey The extra data requested. Data that must be requested
Phil Weaverc2e28932016-12-08 12:29:25 -0800915 * with this mechanism is generally expensive to retrieve, so should only be
916 * requested when needed. See
917 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
918 * {@link #getAvailableExtraData()}.
919 * @param args A bundle of arguments for the request. These depend on the particular request.
920 *
921 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
922 * by this node is no longer in the view tree (and thus this node is obsolete and should be
923 * recycled).
924 */
925 public boolean refreshWithExtraData(String extraDataKey, Bundle args) {
926 args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey);
927 return refresh(args, true);
Svetoslav6254f482013-06-04 17:22:14 -0700928 }
929
930 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800931 * Returns the array containing the IDs of this node's children.
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800932 *
933 * @hide
934 */
Alan Viverettef0aed092013-11-06 15:33:03 -0800935 public LongArray getChildNodeIds() {
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800936 return mChildNodeIds;
937 }
938
939 /**
Alan Viverettef0aed092013-11-06 15:33:03 -0800940 * Returns the id of the child at the specified index.
941 *
942 * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
943 * getChildCount()
944 * @hide
945 */
946 public long getChildId(int index) {
947 if (mChildNodeIds == null) {
948 throw new IndexOutOfBoundsException();
949 }
950 return mChildNodeIds.get(index);
951 }
952
953 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700954 * Gets the number of children.
955 *
956 * @return The child count.
957 */
958 public int getChildCount() {
Alan Viverettef0aed092013-11-06 15:33:03 -0800959 return mChildNodeIds == null ? 0 : mChildNodeIds.size();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700960 }
961
962 /**
963 * Get the child at given index.
964 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700965 * <strong>Note:</strong> It is a client responsibility to recycle the
966 * received info by calling {@link AccessibilityNodeInfo#recycle()}
967 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700968 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700969 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700970 * @param index The child index.
971 * @return The child node.
972 *
973 * @throws IllegalStateException If called outside of an AccessibilityService.
974 *
975 */
976 public AccessibilityNodeInfo getChild(int index) {
977 enforceSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -0800978 if (mChildNodeIds == null) {
979 return null;
980 }
Rhed Jaoae638752018-09-18 19:40:13 +0800981 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -0700982 return null;
983 }
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800984 final long childId = mChildNodeIds.get(index);
Svetoslav Ganov8bd69612011-08-23 13:40:30 -0700985 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -0800986 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId,
Phil Weaverc2e28932016-12-08 12:29:25 -0800987 childId, false, FLAG_PREFETCH_DESCENDANTS, null);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700988 }
989
990 /**
991 * Adds a child.
992 * <p>
Svetoslav Ganov02107852011-10-03 17:06:56 -0700993 * <strong>Note:</strong> Cannot be called from an
994 * {@link android.accessibilityservice.AccessibilityService}.
995 * This class is made immutable before being delivered to an AccessibilityService.
qinyige0b5ca242018-12-27 19:56:54 +0800996 * Note that a view cannot be made its own child.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700997 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -0700998 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700999 * @param child The child.
1000 *
1001 * @throws IllegalStateException If called from an AccessibilityService.
1002 */
1003 public void addChild(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001004 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, true);
Alan Viverettef0aed092013-11-06 15:33:03 -08001005 }
1006
1007 /**
1008 * Unchecked version of {@link #addChild(View)} that does not verify
1009 * uniqueness. For framework use only.
1010 *
1011 * @hide
1012 */
1013 public void addChildUnchecked(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001014 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, false);
Alan Viverettef0aed092013-11-06 15:33:03 -08001015 }
1016
1017 /**
1018 * Removes a child. If the child was not previously added to the node,
1019 * calling this method has no effect.
1020 * <p>
1021 * <strong>Note:</strong> Cannot be called from an
1022 * {@link android.accessibilityservice.AccessibilityService}.
1023 * This class is made immutable before being delivered to an AccessibilityService.
1024 * </p>
1025 *
1026 * @param child The child.
1027 * @return true if the child was present
1028 *
1029 * @throws IllegalStateException If called from an AccessibilityService.
1030 */
1031 public boolean removeChild(View child) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001032 return removeChild(child, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001033 }
1034
1035 /**
1036 * Adds a virtual child which is a descendant of the given <code>root</code>.
Svetoslav Ganov71b4e712011-10-25 11:31:31 -07001037 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
Svetoslav Ganov02107852011-10-03 17:06:56 -07001038 * is added as a child.
1039 * <p>
1040 * A virtual descendant is an imaginary View that is reported as a part of the view
1041 * hierarchy for accessibility purposes. This enables custom views that draw complex
1042 * content to report them selves as a tree of virtual views, thus conveying their
1043 * logical structure.
qinyige0b5ca242018-12-27 19:56:54 +08001044 * Note that a view cannot be made its own child.
Svetoslav Ganov02107852011-10-03 17:06:56 -07001045 * </p>
1046 *
1047 * @param root The root of the virtual subtree.
1048 * @param virtualDescendantId The id of the virtual child.
1049 */
1050 public void addChild(View root, int virtualDescendantId) {
Alan Viverettef0aed092013-11-06 15:33:03 -08001051 addChildInternal(root, virtualDescendantId, true);
1052 }
1053
1054 private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001055 enforceNotSealed();
Alan Viverettef0aed092013-11-06 15:33:03 -08001056 if (mChildNodeIds == null) {
1057 mChildNodeIds = new LongArray();
1058 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07001059 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001060 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001061 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
qinyige0b5ca242018-12-27 19:56:54 +08001062 if (childNodeId == mSourceNodeId) {
1063 Log.e(TAG, "Rejecting attempt to make a View its own child");
1064 return;
1065 }
1066
Alan Viverettef0aed092013-11-06 15:33:03 -08001067 // If we're checking uniqueness and the ID already exists, abort.
1068 if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
1069 return;
1070 }
1071 mChildNodeIds.add(childNodeId);
1072 }
1073
1074 /**
1075 * Removes a virtual child which is a descendant of the given
1076 * <code>root</code>. If the child was not previously added to the node,
1077 * calling this method has no effect.
1078 *
1079 * @param root The root of the virtual subtree.
1080 * @param virtualDescendantId The id of the virtual child.
1081 * @return true if the child was present
1082 * @see #addChild(View, int)
1083 */
1084 public boolean removeChild(View root, int virtualDescendantId) {
1085 enforceNotSealed();
1086 final LongArray childIds = mChildNodeIds;
1087 if (childIds == null) {
1088 return false;
1089 }
1090 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001091 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Alan Viverettef0aed092013-11-06 15:33:03 -08001092 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1093 final int index = childIds.indexOf(childNodeId);
1094 if (index < 0) {
1095 return false;
1096 }
1097 childIds.remove(index);
1098 return true;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001099 }
1100
1101 /**
1102 * Gets the actions that can be performed on the node.
Kristian Monsen74bc1942014-04-29 11:00:17 -07001103 */
1104 public List<AccessibilityAction> getActionList() {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07001105 return CollectionUtils.emptyIfNull(mActions);
Kristian Monsen74bc1942014-04-29 11:00:17 -07001106 }
1107
1108 /**
1109 * Gets the actions that can be performed on the node.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001110 *
1111 * @return The bit mask of with actions.
1112 *
1113 * @see AccessibilityNodeInfo#ACTION_FOCUS
1114 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
1115 * @see AccessibilityNodeInfo#ACTION_SELECT
1116 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
Svetoslav Ganova1dc7612012-05-10 04:14:53 -07001117 * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS
1118 * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS
1119 * @see AccessibilityNodeInfo#ACTION_CLICK
1120 * @see AccessibilityNodeInfo#ACTION_LONG_CLICK
1121 * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
1122 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
1123 * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT
1124 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT
1125 * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD
1126 * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD
Kristian Monsen74bc1942014-04-29 11:00:17 -07001127 *
1128 * @deprecated Use {@link #getActionList()}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001129 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001130 @Deprecated
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001131 public int getActions() {
Kristian Monsen74bc1942014-04-29 11:00:17 -07001132 int returnValue = 0;
1133
1134 if (mActions == null) {
1135 return returnValue;
1136 }
1137
1138 final int actionSize = mActions.size();
1139 for (int i = 0; i < actionSize; i++) {
1140 int actionId = mActions.get(i).getId();
1141 if (actionId <= LAST_LEGACY_STANDARD_ACTION) {
1142 returnValue |= actionId;
1143 }
1144 }
1145
1146 return returnValue;
1147 }
1148
1149 /**
1150 * Adds an action that can be performed on the node.
1151 * <p>
1152 * To add a standard action use the static constants on {@link AccessibilityAction}.
1153 * To add a custom action create a new {@link AccessibilityAction} by passing in a
1154 * resource id from your application as the action id and an optional label that
1155 * describes the action. To override one of the standard actions use as the action
1156 * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that
1157 * describes the action.
1158 * </p>
1159 * <p>
1160 * <strong>Note:</strong> Cannot be called from an
1161 * {@link android.accessibilityservice.AccessibilityService}.
1162 * This class is made immutable before being delivered to an AccessibilityService.
1163 * </p>
1164 *
1165 * @param action The action.
1166 *
1167 * @throws IllegalStateException If called from an AccessibilityService.
1168 */
1169 public void addAction(AccessibilityAction action) {
1170 enforceNotSealed();
1171
Alan Viverettec921f272015-05-14 12:26:49 -07001172 addActionUnchecked(action);
1173 }
1174
1175 private void addActionUnchecked(AccessibilityAction action) {
Kristian Monsen74bc1942014-04-29 11:00:17 -07001176 if (action == null) {
1177 return;
1178 }
1179
1180 if (mActions == null) {
Alan Viverette23f44322015-04-06 16:04:56 -07001181 mActions = new ArrayList<>();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001182 }
1183
1184 mActions.remove(action);
1185 mActions.add(action);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001186 }
1187
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001188 private boolean hasActionWithId(int actionId) {
Qasid Ahmad Sadiq2a53ad92018-08-15 15:31:28 -07001189 List<AccessibilityAction> actions = getActionList();
1190 for (int i = 0; i < actions.size(); i++) {
1191 if (actions.get(i).getId() == actionId) {
1192 return true;
1193 }
1194 }
1195 return false;
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001196 }
1197
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001198 /**
1199 * Adds an action that can be performed on the node.
1200 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001201 * <strong>Note:</strong> Cannot be called from an
1202 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001203 * This class is made immutable before being delivered to an AccessibilityService.
1204 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001205 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001206 * @param action The action.
1207 *
1208 * @throws IllegalStateException If called from an AccessibilityService.
Kristian Monsen74bc1942014-04-29 11:00:17 -07001209 * @throws IllegalArgumentException If the argument is not one of the standard actions.
1210 *
1211 * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)}
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001212 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001213 @Deprecated
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001214 public void addAction(int action) {
1215 enforceNotSealed();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001216
Kristian Monsen8d5f3fa2014-05-20 13:16:19 -07001217 if ((action & ACTION_TYPE_MASK) != 0) {
1218 throw new IllegalArgumentException("Action is not a combination of the standard " +
1219 "actions: " + action);
Kristian Monsen74bc1942014-04-29 11:00:17 -07001220 }
1221
Eugene Susla554edd32017-05-24 16:49:59 -07001222 addStandardActions(action);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001223 }
1224
1225 /**
Alan Viverettef0aed092013-11-06 15:33:03 -08001226 * Removes an action that can be performed on the node. If the action was
1227 * not already added to the node, calling this method has no effect.
1228 * <p>
1229 * <strong>Note:</strong> Cannot be called from an
1230 * {@link android.accessibilityservice.AccessibilityService}.
1231 * This class is made immutable before being delivered to an AccessibilityService.
1232 * </p>
1233 *
Kristian Monsen74bc1942014-04-29 11:00:17 -07001234 * @param action The action to be removed.
1235 *
1236 * @throws IllegalStateException If called from an AccessibilityService.
1237 * @deprecated Use {@link #removeAction(AccessibilityAction)}
1238 */
1239 @Deprecated
1240 public void removeAction(int action) {
1241 enforceNotSealed();
1242
1243 removeAction(getActionSingleton(action));
1244 }
1245
1246 /**
1247 * Removes an action that can be performed on the node. If the action was
1248 * not already added to the node, calling this method has no effect.
1249 * <p>
1250 * <strong>Note:</strong> Cannot be called from an
1251 * {@link android.accessibilityservice.AccessibilityService}.
1252 * This class is made immutable before being delivered to an AccessibilityService.
1253 * </p>
1254 *
1255 * @param action The action to be removed.
1256 * @return The action removed from the list of actions.
Alan Viverettef0aed092013-11-06 15:33:03 -08001257 *
1258 * @throws IllegalStateException If called from an AccessibilityService.
1259 */
Kristian Monsen74bc1942014-04-29 11:00:17 -07001260 public boolean removeAction(AccessibilityAction action) {
Alan Viverettef0aed092013-11-06 15:33:03 -08001261 enforceNotSealed();
Kristian Monsen74bc1942014-04-29 11:00:17 -07001262
1263 if (mActions == null || action == null) {
1264 return false;
1265 }
1266
1267 return mActions.remove(action);
Alan Viverettef0aed092013-11-06 15:33:03 -08001268 }
1269
1270 /**
Phil Weaverf00cd142017-03-03 13:44:00 -08001271 * Removes all actions.
1272 *
1273 * @hide
1274 */
1275 public void removeAllActions() {
1276 if (mActions != null) {
1277 mActions.clear();
1278 }
1279 }
1280
1281 /**
Svetoslav6c702902014-10-09 18:40:56 -07001282 * Gets the node before which this one is visited during traversal. A screen-reader
1283 * must visit the content of this node before the content of the one it precedes.
1284 *
1285 * @return The succeeding node if such or <code>null</code>.
1286 *
1287 * @see #setTraversalBefore(android.view.View)
1288 * @see #setTraversalBefore(android.view.View, int)
1289 */
1290 public AccessibilityNodeInfo getTraversalBefore() {
1291 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001292 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalBefore);
Svetoslav6c702902014-10-09 18:40:56 -07001293 }
1294
1295 /**
1296 * Sets the view before whose node this one should be visited during traversal. A
1297 * screen-reader must visit the content of this node before the content of the one
1298 * it precedes.
1299 * <p>
1300 * <strong>Note:</strong> Cannot be called from an
1301 * {@link android.accessibilityservice.AccessibilityService}.
1302 * This class is made immutable before being delivered to an AccessibilityService.
1303 * </p>
1304 *
1305 * @param view The view providing the preceding node.
1306 *
1307 * @see #getTraversalBefore()
1308 */
1309 public void setTraversalBefore(View view) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001310 setTraversalBefore(view, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav6c702902014-10-09 18:40:56 -07001311 }
1312
1313 /**
1314 * Sets the node before which this one is visited during traversal. A screen-reader
1315 * must visit the content of this node before the content of the one it precedes.
1316 * The successor is a virtual descendant of the given <code>root</code>. If
1317 * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
1318 * as the successor.
1319 * <p>
1320 * A virtual descendant is an imaginary View that is reported as a part of the view
1321 * hierarchy for accessibility purposes. This enables custom views that draw complex
1322 * content to report them selves as a tree of virtual views, thus conveying their
1323 * logical structure.
1324 * </p>
1325 * <p>
1326 * <strong>Note:</strong> Cannot be called from an
1327 * {@link android.accessibilityservice.AccessibilityService}.
1328 * This class is made immutable before being delivered to an AccessibilityService.
1329 * </p>
1330 *
1331 * @param root The root of the virtual subtree.
1332 * @param virtualDescendantId The id of the virtual descendant.
1333 */
1334 public void setTraversalBefore(View root, int virtualDescendantId) {
1335 enforceNotSealed();
1336 final int rootAccessibilityViewId = (root != null)
1337 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1338 mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1339 }
1340
1341 /**
1342 * Gets the node after which this one is visited in accessibility traversal.
1343 * A screen-reader must visit the content of the other node before the content
1344 * of this one.
1345 *
1346 * @return The succeeding node if such or <code>null</code>.
1347 *
1348 * @see #setTraversalAfter(android.view.View)
1349 * @see #setTraversalAfter(android.view.View, int)
1350 */
1351 public AccessibilityNodeInfo getTraversalAfter() {
1352 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001353 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalAfter);
Svetoslav6c702902014-10-09 18:40:56 -07001354 }
1355
1356 /**
1357 * Sets the view whose node is visited after this one in accessibility traversal.
1358 * A screen-reader must visit the content of the other node before the content
1359 * of this one.
1360 * <p>
1361 * <strong>Note:</strong> Cannot be called from an
1362 * {@link android.accessibilityservice.AccessibilityService}.
1363 * This class is made immutable before being delivered to an AccessibilityService.
1364 * </p>
1365 *
1366 * @param view The previous view.
1367 *
1368 * @see #getTraversalAfter()
1369 */
1370 public void setTraversalAfter(View view) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001371 setTraversalAfter(view, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav6c702902014-10-09 18:40:56 -07001372 }
1373
1374 /**
1375 * Sets the node after which this one is visited in accessibility traversal.
1376 * A screen-reader must visit the content of the other node before the content
1377 * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
1378 * the root is set as the predecessor.
1379 * <p>
1380 * A virtual descendant is an imaginary View that is reported as a part of the view
1381 * hierarchy for accessibility purposes. This enables custom views that draw complex
1382 * content to report them selves as a tree of virtual views, thus conveying their
1383 * logical structure.
1384 * </p>
1385 * <p>
1386 * <strong>Note:</strong> Cannot be called from an
1387 * {@link android.accessibilityservice.AccessibilityService}.
1388 * This class is made immutable before being delivered to an AccessibilityService.
1389 * </p>
1390 *
1391 * @param root The root of the virtual subtree.
1392 * @param virtualDescendantId The id of the virtual descendant.
1393 */
1394 public void setTraversalAfter(View root, int virtualDescendantId) {
1395 enforceNotSealed();
1396 final int rootAccessibilityViewId = (root != null)
1397 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
1398 mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
1399 }
1400
1401 /**
Phil Weaverc2e28932016-12-08 12:29:25 -08001402 * Get the extra data available for this node.
1403 * <p>
1404 * Some data that is useful for some accessibility services is expensive to compute, and would
1405 * place undue overhead on apps to compute all the time. That data can be requested with
1406 * {@link #refreshWithExtraData(String, Bundle)}.
1407 *
1408 * @return An unmodifiable list of keys corresponding to extra data that can be requested.
1409 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
1410 */
1411 public List<String> getAvailableExtraData() {
1412 if (mExtraDataKeys != null) {
1413 return Collections.unmodifiableList(mExtraDataKeys);
1414 } else {
1415 return EMPTY_LIST;
1416 }
1417 }
1418
1419 /**
1420 * Set the extra data available for this node.
1421 * <p>
1422 * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that
1423 * it will populate the node's extras with corresponding pieces of information in
1424 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}.
1425 * <p>
1426 * <strong>Note:</strong> Cannot be called from an
1427 * {@link android.accessibilityservice.AccessibilityService}.
1428 * This class is made immutable before being delivered to an AccessibilityService.
1429 *
1430 * @param extraDataKeys A list of types of extra data that are available.
1431 * @see #getAvailableExtraData()
1432 *
1433 * @throws IllegalStateException If called from an AccessibilityService.
1434 */
1435 public void setAvailableExtraData(List<String> extraDataKeys) {
1436 enforceNotSealed();
1437 mExtraDataKeys = new ArrayList<>(extraDataKeys);
1438 }
1439
1440 /**
Alan Viverette029942f2014-08-12 14:55:56 -07001441 * Sets the maximum text length, or -1 for no limit.
1442 * <p>
1443 * Typically used to indicate that an editable text field has a limit on
1444 * the number of characters entered.
1445 * <p>
1446 * <strong>Note:</strong> Cannot be called from an
1447 * {@link android.accessibilityservice.AccessibilityService}.
1448 * This class is made immutable before being delivered to an AccessibilityService.
1449 *
1450 * @param max The maximum text length.
1451 * @see #getMaxTextLength()
1452 *
1453 * @throws IllegalStateException If called from an AccessibilityService.
1454 */
1455 public void setMaxTextLength(int max) {
1456 enforceNotSealed();
1457 mMaxTextLength = max;
1458 }
1459
1460 /**
1461 * Returns the maximum text length for this node.
1462 *
1463 * @return The maximum text length, or -1 for no limit.
1464 * @see #setMaxTextLength(int)
1465 */
1466 public int getMaxTextLength() {
1467 return mMaxTextLength;
1468 }
1469
1470 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001471 * Sets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001472 * <p>
1473 * <strong>Note:</strong> Cannot be called from an
1474 * {@link android.accessibilityservice.AccessibilityService}.
1475 * This class is made immutable before being delivered to an AccessibilityService.
1476 * </p>
1477 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001478 * @param granularities The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001479 *
1480 * @throws IllegalStateException If called from an AccessibilityService.
1481 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001482 public void setMovementGranularities(int granularities) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001483 enforceNotSealed();
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001484 mMovementGranularities = granularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001485 }
1486
1487 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001488 * Gets the movement granularities for traversing the text of this node.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001489 *
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07001490 * @return The bit mask with granularities.
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001491 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07001492 public int getMovementGranularities() {
1493 return mMovementGranularities;
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001494 }
1495
1496 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001497 * Performs an action on the node.
1498 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001499 * <strong>Note:</strong> An action can be performed only if the request is made
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001500 * from an {@link android.accessibilityservice.AccessibilityService}.
1501 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001502 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001503 * @param action The action to perform.
1504 * @return True if the action was performed.
1505 *
1506 * @throws IllegalStateException If called outside of an AccessibilityService.
1507 */
1508 public boolean performAction(int action) {
1509 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001510 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001511 return false;
1512 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07001513 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001514 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1515 action, null);
1516 }
1517
1518 /**
1519 * Performs an action on the node.
1520 * <p>
1521 * <strong>Note:</strong> An action can be performed only if the request is made
1522 * from an {@link android.accessibilityservice.AccessibilityService}.
1523 * </p>
1524 *
1525 * @param action The action to perform.
1526 * @param arguments A bundle with additional arguments.
1527 * @return True if the action was performed.
1528 *
1529 * @throws IllegalStateException If called outside of an AccessibilityService.
1530 */
1531 public boolean performAction(int action, Bundle arguments) {
1532 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001533 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07001534 return false;
1535 }
1536 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1537 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
1538 action, arguments);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001539 }
1540
1541 /**
1542 * Finds {@link AccessibilityNodeInfo}s by text. The match is case
Svetoslav Ganov86398bd2011-06-21 17:38:43 -07001543 * insensitive containment. The search is relative to this info i.e.
1544 * this info is the root of the traversed tree.
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001545 *
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001546 * <p>
1547 * <strong>Note:</strong> It is a client responsibility to recycle the
1548 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1549 * to avoid creating of multiple instances.
1550 * </p>
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001551 *
1552 * @param text The searched text.
1553 * @return A list of node info.
1554 */
1555 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
1556 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001557 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganov86398bd2011-06-21 17:38:43 -07001558 return Collections.emptyList();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001559 }
Svetoslav Ganov8bd69612011-08-23 13:40:30 -07001560 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Svetoslav Ganov79311c42012-01-17 20:24:26 -08001561 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
1562 text);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001563 }
1564
1565 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001566 * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource
1567 * name where a fully qualified id is of the from "package:id/id_resource_name".
1568 * For example, if the target application's package is "foo.bar" and the id
1569 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
1570 *
1571 * <p>
1572 * <strong>Note:</strong> It is a client responsibility to recycle the
1573 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1574 * to avoid creating of multiple instances.
1575 * </p>
1576 * <p>
1577 * <strong>Note:</strong> The primary usage of this API is for UI test automation
1578 * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo}
1579 * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08001580 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001581 * </p>
1582 *
1583 * @param viewId The fully qualified resource name of the view id to find.
1584 * @return A list of node info.
1585 */
1586 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
1587 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001588 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001589 return Collections.emptyList();
1590 }
1591 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1592 return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId,
1593 viewId);
1594 }
1595
1596 /**
Svetoslav8e3feb12014-02-24 13:46:47 -08001597 * Gets the window to which this node belongs.
1598 *
1599 * @return The window.
1600 *
1601 * @see android.accessibilityservice.AccessibilityService#getWindows()
1602 */
1603 public AccessibilityWindowInfo getWindow() {
1604 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001605 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
Svetoslav8e3feb12014-02-24 13:46:47 -08001606 return null;
1607 }
1608 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
1609 return client.getWindow(mConnectionId, mWindowId);
1610 }
1611
1612 /**
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001613 * Gets the parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001614 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001615 * <strong>Note:</strong> It is a client responsibility to recycle the
1616 * received info by calling {@link AccessibilityNodeInfo#recycle()}
1617 * to avoid creating of multiple instances.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001618 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001619 *
Svetoslav Ganov00aabf72011-07-21 11:35:03 -07001620 * @return The parent.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001621 */
1622 public AccessibilityNodeInfo getParent() {
1623 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08001624 return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId);
Svetoslav Ganov57c7fd52012-02-23 18:31:39 -08001625 }
1626
1627 /**
1628 * @return The parent node id.
1629 *
1630 * @hide
1631 */
1632 public long getParentNodeId() {
1633 return mParentNodeId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001634 }
1635
1636 /**
1637 * Sets the parent.
1638 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001639 * <strong>Note:</strong> Cannot be called from an
1640 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001641 * This class is made immutable before being delivered to an AccessibilityService.
1642 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001643 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001644 * @param parent The parent.
1645 *
1646 * @throws IllegalStateException If called from an AccessibilityService.
1647 */
1648 public void setParent(View parent) {
Phil Weaverf00cd142017-03-03 13:44:00 -08001649 setParent(parent, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov02107852011-10-03 17:06:56 -07001650 }
1651
1652 /**
1653 * Sets the parent to be a virtual descendant of the given <code>root</code>.
1654 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
1655 * is set as the parent.
1656 * <p>
1657 * A virtual descendant is an imaginary View that is reported as a part of the view
1658 * hierarchy for accessibility purposes. This enables custom views that draw complex
1659 * content to report them selves as a tree of virtual views, thus conveying their
1660 * logical structure.
1661 * </p>
1662 * <p>
1663 * <strong>Note:</strong> Cannot be called from an
1664 * {@link android.accessibilityservice.AccessibilityService}.
1665 * This class is made immutable before being delivered to an AccessibilityService.
1666 * </p>
1667 *
1668 * @param root The root of the virtual subtree.
1669 * @param virtualDescendantId The id of the virtual descendant.
1670 */
1671 public void setParent(View root, int virtualDescendantId) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001672 enforceNotSealed();
Svetoslav Ganov02107852011-10-03 17:06:56 -07001673 final int rootAccessibilityViewId =
Svetoslav8e3feb12014-02-24 13:46:47 -08001674 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov02107852011-10-03 17:06:56 -07001675 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001676 }
1677
1678 /**
1679 * Gets the node bounds in parent coordinates.
1680 *
1681 * @param outBounds The output node bounds.
1682 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001683 public void getBoundsInParent(Rect outBounds) {
1684 outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
1685 mBoundsInParent.right, mBoundsInParent.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001686 }
1687
1688 /**
1689 * Sets the node bounds in parent coordinates.
1690 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001691 * <strong>Note:</strong> Cannot be called from an
1692 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001693 * This class is made immutable before being delivered to an AccessibilityService.
1694 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001695 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001696 * @param bounds The node bounds.
1697 *
1698 * @throws IllegalStateException If called from an AccessibilityService.
1699 */
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001700 public void setBoundsInParent(Rect bounds) {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001701 enforceNotSealed();
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001702 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
1703 }
1704
1705 /**
1706 * Gets the node bounds in screen coordinates.
1707 *
1708 * @param outBounds The output node bounds.
1709 */
1710 public void getBoundsInScreen(Rect outBounds) {
1711 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
1712 mBoundsInScreen.right, mBoundsInScreen.bottom);
1713 }
1714
1715 /**
Alan Viverettea7ea65e2015-05-15 11:30:21 -07001716 * Returns the actual rect containing the node bounds in screen coordinates.
1717 *
1718 * @hide Not safe to expose outside the framework.
1719 */
1720 public Rect getBoundsInScreen() {
1721 return mBoundsInScreen;
1722 }
1723
1724 /**
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001725 * Sets the node bounds in screen coordinates.
1726 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001727 * <strong>Note:</strong> Cannot be called from an
1728 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001729 * This class is made immutable before being delivered to an AccessibilityService.
1730 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001731 *
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07001732 * @param bounds The node bounds.
1733 *
1734 * @throws IllegalStateException If called from an AccessibilityService.
1735 */
1736 public void setBoundsInScreen(Rect bounds) {
1737 enforceNotSealed();
1738 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001739 }
1740
1741 /**
1742 * Gets whether this node is checkable.
1743 *
1744 * @return True if the node is checkable.
1745 */
1746 public boolean isCheckable() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001747 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001748 }
1749
1750 /**
1751 * Sets whether this node is checkable.
1752 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001753 * <strong>Note:</strong> Cannot be called from an
1754 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001755 * This class is made immutable before being delivered to an AccessibilityService.
1756 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001757 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001758 * @param checkable True if the node is checkable.
1759 *
1760 * @throws IllegalStateException If called from an AccessibilityService.
1761 */
1762 public void setCheckable(boolean checkable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001763 setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001764 }
1765
1766 /**
1767 * Gets whether this node is checked.
1768 *
1769 * @return True if the node is checked.
1770 */
1771 public boolean isChecked() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001772 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001773 }
1774
1775 /**
1776 * Sets whether this node is checked.
1777 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001778 * <strong>Note:</strong> Cannot be called from an
1779 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001780 * This class is made immutable before being delivered to an AccessibilityService.
1781 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001782 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001783 * @param checked True if the node is checked.
1784 *
1785 * @throws IllegalStateException If called from an AccessibilityService.
1786 */
1787 public void setChecked(boolean checked) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001788 setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001789 }
1790
1791 /**
1792 * Gets whether this node is focusable.
1793 *
1794 * @return True if the node is focusable.
1795 */
1796 public boolean isFocusable() {
Qasid Ahmad Sadiq2a53ad92018-08-15 15:31:28 -07001797 return hasActionWithId(ACTION_FOCUS) || hasActionWithId(ACTION_CLEAR_FOCUS);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001798 }
1799
1800 /**
1801 * Sets whether this node is focusable.
1802 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001803 * <strong>Note:</strong> Cannot be called from an
1804 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001805 * This class is made immutable before being delivered to an AccessibilityService.
1806 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001807 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001808 * @param focusable True if the node is focusable.
1809 *
1810 * @throws IllegalStateException If called from an AccessibilityService.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001811 * @deprecated Use {@link #addAction(AccessibilityAction)}
1812 * with {@link AccessibilityAction#ACTION_FOCUS}
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001813 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001814 @Deprecated
1815 public void setFocusable(boolean focusable) { }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001816
1817 /**
1818 * Gets whether this node is focused.
1819 *
1820 * @return True if the node is focused.
1821 */
1822 public boolean isFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001823 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001824 }
1825
1826 /**
1827 * Sets whether this node is focused.
1828 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001829 * <strong>Note:</strong> Cannot be called from an
1830 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001831 * This class is made immutable before being delivered to an AccessibilityService.
1832 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001833 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001834 * @param focused True if the node is focused.
1835 *
1836 * @throws IllegalStateException If called from an AccessibilityService.
1837 */
1838 public void setFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001839 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001840 }
1841
1842 /**
Alan Viverette1579edc2015-04-01 13:23:06 -07001843 * Gets whether this node is visible to the user.
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001844 *
1845 * @return Whether the node is visible to the user.
1846 */
1847 public boolean isVisibleToUser() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001848 return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001849 }
1850
1851 /**
1852 * Sets whether this node is visible to the user.
1853 * <p>
1854 * <strong>Note:</strong> Cannot be called from an
1855 * {@link android.accessibilityservice.AccessibilityService}.
1856 * This class is made immutable before being delivered to an AccessibilityService.
1857 * </p>
1858 *
1859 * @param visibleToUser Whether the node is visible to the user.
1860 *
1861 * @throws IllegalStateException If called from an AccessibilityService.
1862 */
1863 public void setVisibleToUser(boolean visibleToUser) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001864 setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser);
Svetoslav Ganov0a1bb6d2012-05-07 11:54:39 -07001865 }
1866
1867 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07001868 * Gets whether this node is accessibility focused.
1869 *
1870 * @return True if the node is accessibility focused.
1871 */
1872 public boolean isAccessibilityFocused() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001873 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001874 }
1875
1876 /**
1877 * Sets whether this node is accessibility focused.
1878 * <p>
1879 * <strong>Note:</strong> Cannot be called from an
1880 * {@link android.accessibilityservice.AccessibilityService}.
1881 * This class is made immutable before being delivered to an AccessibilityService.
1882 * </p>
1883 *
1884 * @param focused True if the node is accessibility focused.
1885 *
1886 * @throws IllegalStateException If called from an AccessibilityService.
1887 */
1888 public void setAccessibilityFocused(boolean focused) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001889 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
Svetoslav Ganov42138042012-03-20 11:51:39 -07001890 }
1891
1892 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001893 * Gets whether this node is selected.
1894 *
1895 * @return True if the node is selected.
1896 */
1897 public boolean isSelected() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001898 return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001899 }
1900
1901 /**
1902 * Sets whether this node is selected.
1903 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001904 * <strong>Note:</strong> Cannot be called from an
1905 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001906 * This class is made immutable before being delivered to an AccessibilityService.
1907 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001908 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001909 * @param selected True if the node is selected.
1910 *
1911 * @throws IllegalStateException If called from an AccessibilityService.
1912 */
1913 public void setSelected(boolean selected) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001914 setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001915 }
1916
1917 /**
1918 * Gets whether this node is clickable.
1919 *
1920 * @return True if the node is clickable.
1921 */
1922 public boolean isClickable() {
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001923 return hasActionWithId(ACTION_CLICK);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001924 }
1925
1926 /**
1927 * Sets whether this node is clickable.
1928 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001929 * <strong>Note:</strong> Cannot be called from an
1930 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001931 * This class is made immutable before being delivered to an AccessibilityService.
1932 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001933 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001934 * @param clickable True if the node is clickable.
1935 *
1936 * @throws IllegalStateException If called from an AccessibilityService.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001937 * @deprecated Use {@link #addAction(AccessibilityAction)}
1938 * with {@link AccessibilityAction#ACTION_CLICK}
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001939 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001940 @Deprecated
1941 public void setClickable(boolean clickable) { }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001942
1943 /**
1944 * Gets whether this node is long clickable.
1945 *
1946 * @return True if the node is long clickable.
1947 */
1948 public boolean isLongClickable() {
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001949 return hasActionWithId(ACTION_LONG_CLICK);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001950 }
1951
1952 /**
1953 * Sets whether this node is long clickable.
1954 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001955 * <strong>Note:</strong> Cannot be called from an
1956 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001957 * This class is made immutable before being delivered to an AccessibilityService.
1958 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001959 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001960 * @param longClickable True if the node is long clickable.
1961 *
1962 * @throws IllegalStateException If called from an AccessibilityService.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001963 * @deprecated Use {@link #addAction(AccessibilityAction)}
1964 * with {@link AccessibilityAction#ACTION_LONG_CLICK}
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001965 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07001966 @Deprecated
1967 public void setLongClickable(boolean longClickable) { }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001968
1969 /**
1970 * Gets whether this node is enabled.
1971 *
1972 * @return True if the node is enabled.
1973 */
1974 public boolean isEnabled() {
Svetoslavbcc46a02013-02-06 11:56:00 -08001975 return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001976 }
1977
1978 /**
1979 * Sets whether this node is enabled.
1980 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001981 * <strong>Note:</strong> Cannot be called from an
1982 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001983 * This class is made immutable before being delivered to an AccessibilityService.
1984 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07001985 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001986 * @param enabled True if the node is enabled.
1987 *
1988 * @throws IllegalStateException If called from an AccessibilityService.
1989 */
1990 public void setEnabled(boolean enabled) {
Svetoslavbcc46a02013-02-06 11:56:00 -08001991 setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001992 }
1993
1994 /**
1995 * Gets whether this node is a password.
1996 *
1997 * @return True if the node is a password.
1998 */
1999 public boolean isPassword() {
Svetoslavbcc46a02013-02-06 11:56:00 -08002000 return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002001 }
2002
2003 /**
2004 * Sets whether this node is a password.
2005 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002006 * <strong>Note:</strong> Cannot be called from an
2007 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002008 * This class is made immutable before being delivered to an AccessibilityService.
2009 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002010 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002011 * @param password True if the node is a password.
2012 *
2013 * @throws IllegalStateException If called from an AccessibilityService.
2014 */
2015 public void setPassword(boolean password) {
Svetoslavbcc46a02013-02-06 11:56:00 -08002016 setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002017 }
2018
2019 /**
Svetoslav Ganova0156172011-06-26 17:55:44 -07002020 * Gets if the node is scrollable.
2021 *
2022 * @return True if the node is scrollable, false otherwise.
2023 */
2024 public boolean isScrollable() {
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002025 return hasActionWithId(ACTION_SCROLL_BACKWARD)
2026 || hasActionWithId(ACTION_SCROLL_FORWARD)
2027 || hasActionWithId(R.id.accessibilityActionScrollToPosition)
2028 || hasActionWithId(R.id.accessibilityActionScrollUp)
2029 || hasActionWithId(R.id.accessibilityActionScrollDown)
2030 || hasActionWithId(R.id.accessibilityActionScrollLeft)
2031 || hasActionWithId(R.id.accessibilityActionScrollRight);
Svetoslav Ganova0156172011-06-26 17:55:44 -07002032 }
2033
2034 /**
2035 * Sets if the node is scrollable.
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002036 * <p>
2037 * <strong>Note:</strong> Cannot be called from an
2038 * {@link android.accessibilityservice.AccessibilityService}.
2039 * This class is made immutable before being delivered to an AccessibilityService.
2040 * </p>
Svetoslav Ganova0156172011-06-26 17:55:44 -07002041 *
2042 * @param scrollable True if the node is scrollable, false otherwise.
2043 *
2044 * @throws IllegalStateException If called from an AccessibilityService.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002045 * @deprecated Use {@link #addAction(AccessibilityAction)}
Svetoslav Ganova0156172011-06-26 17:55:44 -07002046 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002047 @Deprecated
2048
Svetoslav Ganova0156172011-06-26 17:55:44 -07002049 public void setScrollable(boolean scrollable) {
Svetoslavbcc46a02013-02-06 11:56:00 -08002050 }
2051
2052 /**
2053 * Gets if the node is editable.
2054 *
2055 * @return True if the node is editable, false otherwise.
2056 */
2057 public boolean isEditable() {
2058 return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE);
2059 }
2060
2061 /**
2062 * Sets whether this node is editable.
2063 * <p>
2064 * <strong>Note:</strong> Cannot be called from an
2065 * {@link android.accessibilityservice.AccessibilityService}.
2066 * This class is made immutable before being delivered to an AccessibilityService.
2067 * </p>
2068 *
2069 * @param editable True if the node is editable.
2070 *
2071 * @throws IllegalStateException If called from an AccessibilityService.
2072 */
2073 public void setEditable(boolean editable) {
2074 setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable);
Svetoslav Ganova0156172011-06-26 17:55:44 -07002075 }
2076
2077 /**
Phil Weaver9f26b3d2018-01-04 10:04:37 -08002078 * If this node represents a visually distinct region of the screen that may update separately
2079 * from the rest of the window, it is considered a pane. Set the pane title to indicate that
2080 * the node is a pane, and to provide a title for it.
2081 * <p>
2082 * <strong>Note:</strong> Cannot be called from an
2083 * {@link android.accessibilityservice.AccessibilityService}.
2084 * This class is made immutable before being delivered to an AccessibilityService.
2085 * </p>
2086 * @param paneTitle The title of the pane represented by this node.
2087 */
2088 public void setPaneTitle(@Nullable CharSequence paneTitle) {
2089 enforceNotSealed();
2090 mPaneTitle = (paneTitle == null)
2091 ? null : paneTitle.subSequence(0, paneTitle.length());
2092 }
2093
2094 /**
2095 * Get the title of the pane represented by this node.
2096 *
2097 * @return The title of the pane represented by this node, or {@code null} if this node does
2098 * not represent a pane.
2099 */
2100 public @Nullable CharSequence getPaneTitle() {
2101 return mPaneTitle;
2102 }
2103
2104 /**
Phil Weaver1f222542016-01-08 11:49:32 -08002105 * Get the drawing order of the view corresponding it this node.
2106 * <p>
2107 * Drawing order is determined only within the node's parent, so this index is only relative
2108 * to its siblings.
2109 * <p>
2110 * In some cases, the drawing order is essentially simultaneous, so it is possible for two
2111 * siblings to return the same value. It is also possible that values will be skipped.
2112 *
2113 * @return The drawing position of the view corresponding to this node relative to its siblings.
2114 */
2115 public int getDrawingOrder() {
2116 return mDrawingOrderInParent;
2117 }
2118
2119 /**
2120 * Set the drawing order of the view corresponding it this node.
2121 *
2122 * <p>
2123 * <strong>Note:</strong> Cannot be called from an
2124 * {@link android.accessibilityservice.AccessibilityService}.
2125 * This class is made immutable before being delivered to an AccessibilityService.
2126 * </p>
2127 * @param drawingOrderInParent
2128 * @throws IllegalStateException If called from an AccessibilityService.
2129 */
2130 public void setDrawingOrder(int drawingOrderInParent) {
2131 enforceNotSealed();
2132 mDrawingOrderInParent = drawingOrderInParent;
2133 }
2134
2135 /**
Svetoslav3577a282013-06-06 14:09:10 -07002136 * Gets the collection info if the node is a collection. A collection
2137 * child is always a collection item.
2138 *
2139 * @return The collection info.
2140 */
2141 public CollectionInfo getCollectionInfo() {
2142 return mCollectionInfo;
2143 }
2144
2145 /**
2146 * Sets the collection info if the node is a collection. A collection
2147 * child is always a collection item.
2148 * <p>
2149 * <strong>Note:</strong> Cannot be called from an
2150 * {@link android.accessibilityservice.AccessibilityService}.
2151 * This class is made immutable before being delivered to an AccessibilityService.
2152 * </p>
2153 *
2154 * @param collectionInfo The collection info.
2155 */
2156 public void setCollectionInfo(CollectionInfo collectionInfo) {
2157 enforceNotSealed();
2158 mCollectionInfo = collectionInfo;
2159 }
2160
2161 /**
2162 * Gets the collection item info if the node is a collection item. A collection
2163 * item is always a child of a collection.
2164 *
2165 * @return The collection item info.
2166 */
2167 public CollectionItemInfo getCollectionItemInfo() {
2168 return mCollectionItemInfo;
2169 }
2170
2171 /**
2172 * Sets the collection item info if the node is a collection item. A collection
2173 * item is always a child of a collection.
2174 * <p>
2175 * <strong>Note:</strong> Cannot be called from an
2176 * {@link android.accessibilityservice.AccessibilityService}.
2177 * This class is made immutable before being delivered to an AccessibilityService.
2178 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07002179 */
2180 public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
2181 enforceNotSealed();
2182 mCollectionItemInfo = collectionItemInfo;
2183 }
2184
2185 /**
2186 * Gets the range info if this node is a range.
2187 *
2188 * @return The range.
2189 */
2190 public RangeInfo getRangeInfo() {
2191 return mRangeInfo;
2192 }
2193
2194 /**
2195 * Sets the range info if this node is a range.
2196 * <p>
2197 * <strong>Note:</strong> Cannot be called from an
2198 * {@link android.accessibilityservice.AccessibilityService}.
2199 * This class is made immutable before being delivered to an AccessibilityService.
2200 * </p>
2201 *
2202 * @param rangeInfo The range info.
2203 */
2204 public void setRangeInfo(RangeInfo rangeInfo) {
2205 enforceNotSealed();
2206 mRangeInfo = rangeInfo;
2207 }
2208
2209 /**
2210 * Gets if the content of this node is invalid. For example,
2211 * a date is not well-formed.
2212 *
2213 * @return If the node content is invalid.
2214 */
2215 public boolean isContentInvalid() {
2216 return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
2217 }
2218
2219 /**
2220 * Sets if the content of this node is invalid. For example,
2221 * a date is not well-formed.
2222 * <p>
2223 * <strong>Note:</strong> Cannot be called from an
2224 * {@link android.accessibilityservice.AccessibilityService}.
2225 * This class is made immutable before being delivered to an AccessibilityService.
2226 * </p>
2227 *
2228 * @param contentInvalid If the node content is invalid.
2229 */
2230 public void setContentInvalid(boolean contentInvalid) {
2231 setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
2232 }
2233
2234 /**
Mady Mellore8608912015-06-05 09:02:55 -07002235 * Gets whether this node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002236 *
Mady Mellore8608912015-06-05 09:02:55 -07002237 * @return True if the node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002238 */
Mady Mellore8608912015-06-05 09:02:55 -07002239 public boolean isContextClickable() {
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002240 return hasActionWithId(R.id.accessibilityActionContextClick);
Mady Mellore82067b2015-04-30 09:58:35 -07002241 }
2242
2243 /**
Mady Mellore8608912015-06-05 09:02:55 -07002244 * Sets whether this node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002245 * <p>
2246 * <strong>Note:</strong> Cannot be called from an
2247 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
2248 * before being delivered to an AccessibilityService.
2249 * </p>
2250 *
Mady Mellore8608912015-06-05 09:02:55 -07002251 * @param contextClickable True if the node is context clickable.
Mady Mellore82067b2015-04-30 09:58:35 -07002252 * @throws IllegalStateException If called from an AccessibilityService.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002253 * @deprecated Use {@link #addAction(AccessibilityAction)}
2254 * with {@link AccessibilityAction#ACTION_CONTEXT_CLICK}
Mady Mellore82067b2015-04-30 09:58:35 -07002255 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002256 @Deprecated
2257 public void setContextClickable(boolean contextClickable) { }
Mady Mellore82067b2015-04-30 09:58:35 -07002258
2259 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07002260 * Gets the node's live region mode.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002261 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002262 * A live region is a node that contains information that is important for
2263 * the user and when it changes the user should be notified. For example,
2264 * in a login screen with a TextView that displays an "incorrect password"
2265 * notification, that view should be marked as a live region with mode
2266 * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002267 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002268 * It is the responsibility of the accessibility service to monitor
2269 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating
2270 * changes to live region nodes and their children.
Svetoslav3577a282013-06-06 14:09:10 -07002271 *
Alan Viverette77e9a282013-09-12 17:16:09 -07002272 * @return The live region mode, or
2273 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2274 * live region.
2275 * @see android.view.View#getAccessibilityLiveRegion()
Svetoslav3577a282013-06-06 14:09:10 -07002276 */
Alan Viverette77e9a282013-09-12 17:16:09 -07002277 public int getLiveRegion() {
2278 return mLiveRegion;
Svetoslav3577a282013-06-06 14:09:10 -07002279 }
2280
2281 /**
Alan Viverette77e9a282013-09-12 17:16:09 -07002282 * Sets the node's live region mode.
Svetoslav3577a282013-06-06 14:09:10 -07002283 * <p>
Alan Viverette77e9a282013-09-12 17:16:09 -07002284 * <strong>Note:</strong> Cannot be called from an
2285 * {@link android.accessibilityservice.AccessibilityService}. This class is
2286 * made immutable before being delivered to an AccessibilityService.
Svetoslav3577a282013-06-06 14:09:10 -07002287 *
Alan Viverette77e9a282013-09-12 17:16:09 -07002288 * @param mode The live region mode, or
2289 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a
2290 * live region.
2291 * @see android.view.View#setAccessibilityLiveRegion(int)
Svetoslav3577a282013-06-06 14:09:10 -07002292 */
Alan Viverette77e9a282013-09-12 17:16:09 -07002293 public void setLiveRegion(int mode) {
2294 enforceNotSealed();
2295 mLiveRegion = mode;
Svetoslav3577a282013-06-06 14:09:10 -07002296 }
2297
2298 /**
2299 * Gets if the node is a multi line editable text.
2300 *
2301 * @return True if the node is multi line.
2302 */
2303 public boolean isMultiLine() {
2304 return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
2305 }
2306
2307 /**
2308 * Sets if the node is a multi line editable text.
2309 * <p>
2310 * <strong>Note:</strong> Cannot be called from an
2311 * {@link android.accessibilityservice.AccessibilityService}.
2312 * This class is made immutable before being delivered to an AccessibilityService.
2313 * </p>
2314 *
2315 * @param multiLine True if the node is multi line.
2316 */
2317 public void setMultiLine(boolean multiLine) {
Svetoslav3577a282013-06-06 14:09:10 -07002318 setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
2319 }
2320
2321 /**
2322 * Gets if this node opens a popup or a dialog.
2323 *
2324 * @return If the the node opens a popup.
2325 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002326 public boolean canOpenPopup() {
Svetoslav3577a282013-06-06 14:09:10 -07002327 return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
2328 }
2329
2330 /**
2331 * Sets if this node opens a popup or a dialog.
2332 * <p>
2333 * <strong>Note:</strong> Cannot be called from an
2334 * {@link android.accessibilityservice.AccessibilityService}.
2335 * This class is made immutable before being delivered to an AccessibilityService.
2336 * </p>
2337 *
2338 * @param opensPopup If the the node opens a popup.
2339 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002340 public void setCanOpenPopup(boolean opensPopup) {
Phil Weavere1951292017-08-18 17:56:04 +00002341 enforceNotSealed();
Svetoslav3577a282013-06-06 14:09:10 -07002342 setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
2343 }
2344
2345 /**
Svetoslav3577a282013-06-06 14:09:10 -07002346 * Gets if the node can be dismissed.
2347 *
2348 * @return If the node can be dismissed.
2349 */
2350 public boolean isDismissable() {
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002351 return hasActionWithId(ACTION_DISMISS);
Svetoslav3577a282013-06-06 14:09:10 -07002352 }
2353
2354 /**
2355 * Sets if the node can be dismissed.
2356 * <p>
2357 * <strong>Note:</strong> Cannot be called from an
2358 * {@link android.accessibilityservice.AccessibilityService}.
2359 * This class is made immutable before being delivered to an AccessibilityService.
2360 * </p>
2361 *
2362 * @param dismissable If the node can be dismissed.
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002363 * @deprecated Use {@link #addAction(AccessibilityAction)}
2364 * with {@link AccessibilityAction#ACTION_DISMISS}
Svetoslav3577a282013-06-06 14:09:10 -07002365 */
Qasid Sadiq063eefa2018-06-11 17:52:51 -07002366 @Deprecated
2367 public void setDismissable(boolean dismissable) { }
Svetoslav3577a282013-06-06 14:09:10 -07002368
2369 /**
Casey Burkhardt2d80ae42016-01-31 12:52:23 -08002370 * Returns whether the node originates from a view considered important for accessibility.
2371 *
2372 * @return {@code true} if the node originates from a view considered important for
2373 * accessibility, {@code false} otherwise
2374 *
2375 * @see View#isImportantForAccessibility()
2376 */
2377 public boolean isImportantForAccessibility() {
2378 return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE);
2379 }
2380
2381 /**
2382 * Sets whether the node is considered important for accessibility.
2383 * <p>
2384 * <strong>Note:</strong> Cannot be called from an
2385 * {@link android.accessibilityservice.AccessibilityService}.
2386 * This class is made immutable before being delivered to an AccessibilityService.
2387 * </p>
2388 *
2389 * @param important {@code true} if the node is considered important for accessibility,
2390 * {@code false} otherwise
2391 */
2392 public void setImportantForAccessibility(boolean important) {
2393 setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important);
2394 }
2395
2396 /**
Phil Weaver1e6ecc62017-11-07 15:28:21 -08002397 * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note
2398 * that {@code false} indicates that it is not explicitly marked, not that the node is not
Phil Weaver75dce7c2017-12-15 17:48:33 -08002399 * a focusable unit. Screen readers should generally use other signals, such as
Phil Weaver1e6ecc62017-11-07 15:28:21 -08002400 * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive
2401 * focus.
2402 *
2403 * @return {@code true} if the node is specifically marked as a focusable unit for screen
2404 * readers, {@code false} otherwise.
2405 *
2406 * @see View#isScreenReaderFocusable()
2407 */
2408 public boolean isScreenReaderFocusable() {
2409 return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE);
2410 }
2411
2412 /**
2413 * Sets whether the node should be considered a focusable unit by a screen reader.
2414 * <p>
2415 * <strong>Note:</strong> Cannot be called from an
2416 * {@link android.accessibilityservice.AccessibilityService}.
2417 * This class is made immutable before being delivered to an AccessibilityService.
2418 * </p>
2419 *
2420 * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers,
2421 * {@code false} otherwise.
2422 */
2423 public void setScreenReaderFocusable(boolean screenReaderFocusable) {
2424 setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
2425 }
2426
2427 /**
Phil Weaver776afc22016-12-21 10:55:13 -08002428 * Returns whether the node's text represents a hint for the user to enter text. It should only
2429 * be {@code true} if the node has editable text.
2430 *
2431 * @return {@code true} if the text in the node represents a hint to the user, {@code false}
2432 * otherwise.
2433 */
2434 public boolean isShowingHintText() {
2435 return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
2436 }
2437
2438 /**
2439 * Sets whether the node's text represents a hint for the user to enter text. It should only
2440 * be {@code true} if the node has editable text.
2441 * <p>
2442 * <strong>Note:</strong> Cannot be called from an
2443 * {@link android.accessibilityservice.AccessibilityService}.
2444 * This class is made immutable before being delivered to an AccessibilityService.
2445 * </p>
2446 *
2447 * @param showingHintText {@code true} if the text in the node represents a hint to the user,
2448 * {@code false} otherwise.
2449 */
2450 public void setShowingHintText(boolean showingHintText) {
2451 setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
2452 }
2453
2454 /**
Phil Weaver6290fb592018-01-08 17:42:18 -08002455 * Returns whether node represents a heading.
Phil Weaver30601452018-04-16 14:23:04 -07002456 * <p><strong>Note:</strong> Returns {@code true} if either {@link #setHeading(boolean)}
2457 * marks this node as a heading or if the node has a {@link CollectionItemInfo} that marks
2458 * it as such, to accomodate apps that use the now-deprecated API.</p>
Phil Weaver6290fb592018-01-08 17:42:18 -08002459 *
2460 * @return {@code true} if the node is a heading, {@code false} otherwise.
2461 */
2462 public boolean isHeading() {
Phil Weaver30601452018-04-16 14:23:04 -07002463 if (getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING)) return true;
2464 CollectionItemInfo itemInfo = getCollectionItemInfo();
2465 return ((itemInfo != null) && itemInfo.mHeading);
Phil Weaver6290fb592018-01-08 17:42:18 -08002466 }
2467
2468 /**
2469 * Sets whether the node represents a heading.
2470 *
2471 * <p>
2472 * <strong>Note:</strong> Cannot be called from an
2473 * {@link android.accessibilityservice.AccessibilityService}.
2474 * This class is made immutable before being delivered to an AccessibilityService.
2475 * </p>
2476 *
2477 * @param isHeading {@code true} if the node is a heading, {@code false} otherwise.
2478 */
2479 public void setHeading(boolean isHeading) {
2480 setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading);
2481 }
2482
2483 /**
Rhed Jaoa42495e2018-08-08 16:01:18 +08002484 * Returns whether node represents a text entry key that is part of a keyboard or keypad.
2485 *
2486 * @return {@code true} if the node is a text entry key., {@code false} otherwise.
2487 */
2488 public boolean isTextEntryKey() {
2489 return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY);
2490 }
2491
2492 /**
2493 * Sets whether the node represents a text entry key that is part of a keyboard or keypad.
2494 *
2495 * <p>
2496 * <strong>Note:</strong> Cannot be called from an
2497 * {@link android.accessibilityservice.AccessibilityService}.
2498 * This class is made immutable before being delivered to an AccessibilityService.
2499 * </p>
2500 *
2501 * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise.
2502 */
2503 public void setTextEntryKey(boolean isTextEntryKey) {
2504 setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey);
2505 }
2506
2507 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002508 * Gets the package this node comes from.
2509 *
2510 * @return The package name.
2511 */
2512 public CharSequence getPackageName() {
2513 return mPackageName;
2514 }
2515
2516 /**
2517 * Sets the package this node comes from.
2518 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002519 * <strong>Note:</strong> Cannot be called from an
2520 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002521 * This class is made immutable before being delivered to an AccessibilityService.
2522 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002523 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002524 * @param packageName The package name.
2525 *
2526 * @throws IllegalStateException If called from an AccessibilityService.
2527 */
2528 public void setPackageName(CharSequence packageName) {
2529 enforceNotSealed();
2530 mPackageName = packageName;
2531 }
2532
2533 /**
2534 * Gets the class this node comes from.
2535 *
2536 * @return The class name.
2537 */
2538 public CharSequence getClassName() {
2539 return mClassName;
2540 }
2541
2542 /**
2543 * Sets the class this node comes from.
2544 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002545 * <strong>Note:</strong> Cannot be called from an
2546 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002547 * This class is made immutable before being delivered to an AccessibilityService.
2548 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002549 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002550 * @param className The class name.
2551 *
2552 * @throws IllegalStateException If called from an AccessibilityService.
2553 */
2554 public void setClassName(CharSequence className) {
2555 enforceNotSealed();
2556 mClassName = className;
2557 }
2558
2559 /**
2560 * Gets the text of this node.
Phil Weaver193520e2016-12-13 09:39:06 -08002561 * <p>
2562 * <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s,
2563 * these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)}
2564 * can be called from an {@link AccessibilityService}. When called from a service, the
2565 * {@link View} argument is ignored and the corresponding span will be found on the view that
2566 * this {@code AccessibilityNodeInfo} represents and called with that view as its argument.
2567 * <p>
2568 * This treatment of {@link ClickableSpan}s means that the text returned from this method may
2569 * different slightly one passed to {@link #setText(CharSequence)}, although they will be
2570 * equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The
2571 * {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside
2572 * of an accessibility service.
2573 * </p>
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002574 *
2575 * @return The text.
2576 */
2577 public CharSequence getText() {
Phil Weaver193520e2016-12-13 09:39:06 -08002578 // Attach this node to any spans that need it
2579 if (mText instanceof Spanned) {
2580 Spanned spanned = (Spanned) mText;
2581 AccessibilityClickableSpan[] clickableSpans =
2582 spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class);
2583 for (int i = 0; i < clickableSpans.length; i++) {
Phil Weaver23161e72017-04-19 12:16:36 -07002584 clickableSpans[i].copyConnectionDataFrom(this);
Phil Weaver193520e2016-12-13 09:39:06 -08002585 }
2586 AccessibilityURLSpan[] urlSpans =
2587 spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class);
2588 for (int i = 0; i < urlSpans.length; i++) {
Phil Weaver23161e72017-04-19 12:16:36 -07002589 urlSpans[i].copyConnectionDataFrom(this);
Phil Weaver193520e2016-12-13 09:39:06 -08002590 }
2591 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002592 return mText;
2593 }
2594
2595 /**
Phil Weaver193520e2016-12-13 09:39:06 -08002596 * Get the text passed to setText before any changes to the spans.
2597 * @hide
2598 */
2599 public CharSequence getOriginalText() {
2600 return mOriginalText;
2601 }
2602
2603 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002604 * Sets the text of this node.
2605 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002606 * <strong>Note:</strong> Cannot be called from an
2607 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002608 * This class is made immutable before being delivered to an AccessibilityService.
2609 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002610 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002611 * @param text The text.
2612 *
2613 * @throws IllegalStateException If called from an AccessibilityService.
2614 */
2615 public void setText(CharSequence text) {
2616 enforceNotSealed();
Phil Weaver193520e2016-12-13 09:39:06 -08002617 mOriginalText = text;
2618 // Replace any ClickableSpans in mText with placeholders
2619 if (text instanceof Spanned) {
2620 ClickableSpan[] spans =
2621 ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
2622 if (spans.length > 0) {
Phil Weaver0ebe6bd2017-02-21 16:24:31 -08002623 Spannable spannable = new SpannableStringBuilder(text);
Phil Weaver193520e2016-12-13 09:39:06 -08002624 for (int i = 0; i < spans.length; i++) {
2625 ClickableSpan span = spans[i];
2626 if ((span instanceof AccessibilityClickableSpan)
2627 || (span instanceof AccessibilityURLSpan)) {
2628 // We've already done enough
2629 break;
2630 }
2631 int spanToReplaceStart = spannable.getSpanStart(span);
2632 int spanToReplaceEnd = spannable.getSpanEnd(span);
2633 int spanToReplaceFlags = spannable.getSpanFlags(span);
2634 spannable.removeSpan(span);
2635 ClickableSpan replacementSpan = (span instanceof URLSpan)
2636 ? new AccessibilityURLSpan((URLSpan) span)
2637 : new AccessibilityClickableSpan(span.getId());
2638 spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
2639 spanToReplaceFlags);
2640 }
2641 mText = spannable;
2642 return;
2643 }
2644 }
Phil Weaveref955ad2016-08-25 12:58:15 -07002645 mText = (text == null) ? null : text.subSequence(0, text.length());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002646 }
2647
2648 /**
Phil Weaver776afc22016-12-21 10:55:13 -08002649 * Gets the hint text of this node. Only applies to nodes where text can be entered.
2650 *
2651 * @return The hint text.
2652 */
2653 public CharSequence getHintText() {
2654 return mHintText;
2655 }
2656
2657 /**
2658 * Sets the hint text of this node. Only applies to nodes where text can be entered.
2659 * <p>
2660 * <strong>Note:</strong> Cannot be called from an
2661 * {@link android.accessibilityservice.AccessibilityService}.
2662 * This class is made immutable before being delivered to an AccessibilityService.
2663 * </p>
2664 *
2665 * @param hintText The hint text for this mode.
2666 *
2667 * @throws IllegalStateException If called from an AccessibilityService.
2668 */
2669 public void setHintText(CharSequence hintText) {
2670 enforceNotSealed();
2671 mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length());
2672 }
2673
2674 /**
Alan Viverettefccbff52014-07-07 15:06:14 -07002675 * Sets the error text of this node.
2676 * <p>
2677 * <strong>Note:</strong> Cannot be called from an
2678 * {@link android.accessibilityservice.AccessibilityService}.
2679 * This class is made immutable before being delivered to an AccessibilityService.
2680 * </p>
2681 *
2682 * @param error The error text.
2683 *
2684 * @throws IllegalStateException If called from an AccessibilityService.
2685 */
2686 public void setError(CharSequence error) {
2687 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -07002688 mError = (error == null) ? null : error.subSequence(0, error.length());
Alan Viverettefccbff52014-07-07 15:06:14 -07002689 }
2690
2691 /**
2692 * Gets the error text of this node.
2693 *
2694 * @return The error text.
2695 */
2696 public CharSequence getError() {
2697 return mError;
2698 }
2699
2700 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002701 * Gets the content description of this node.
2702 *
2703 * @return The content description.
2704 */
2705 public CharSequence getContentDescription() {
2706 return mContentDescription;
2707 }
2708
2709 /**
2710 * Sets the content description of this node.
2711 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002712 * <strong>Note:</strong> Cannot be called from an
2713 * {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002714 * This class is made immutable before being delivered to an AccessibilityService.
2715 * </p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07002716 *
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002717 * @param contentDescription The content description.
2718 *
2719 * @throws IllegalStateException If called from an AccessibilityService.
2720 */
2721 public void setContentDescription(CharSequence contentDescription) {
2722 enforceNotSealed();
Phil Weaveref955ad2016-08-25 12:58:15 -07002723 mContentDescription = (contentDescription == null) ? null
2724 : contentDescription.subSequence(0, contentDescription.length());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002725 }
2726
2727 /**
Phil Weaverd89905f2018-01-10 08:28:04 -08002728 * Gets the tooltip text of this node.
2729 *
2730 * @return The tooltip text.
2731 */
2732 @Nullable
2733 public CharSequence getTooltipText() {
2734 return mTooltipText;
2735 }
2736
2737 /**
2738 * Sets the tooltip text of this node.
2739 * <p>
2740 * <strong>Note:</strong> Cannot be called from an
2741 * {@link android.accessibilityservice.AccessibilityService}.
2742 * This class is made immutable before being delivered to an AccessibilityService.
2743 * </p>
2744 *
2745 * @param tooltipText The tooltip text.
2746 *
2747 * @throws IllegalStateException If called from an AccessibilityService.
2748 */
2749 public void setTooltipText(@Nullable CharSequence tooltipText) {
2750 enforceNotSealed();
2751 mTooltipText = (tooltipText == null) ? null
2752 : tooltipText.subSequence(0, tooltipText.length());
2753 }
2754
2755 /**
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002756 * Sets the view for which the view represented by this info serves as a
2757 * label for accessibility purposes.
2758 *
2759 * @param labeled The view for which this info serves as a label.
2760 */
2761 public void setLabelFor(View labeled) {
Phil Weaverf00cd142017-03-03 13:44:00 -08002762 setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002763 }
2764
2765 /**
2766 * Sets the view for which the view represented by this info serves as a
2767 * label for accessibility purposes. If <code>virtualDescendantId</code>
2768 * is {@link View#NO_ID} the root is set as the labeled.
2769 * <p>
2770 * A virtual descendant is an imaginary View that is reported as a part of the view
2771 * hierarchy for accessibility purposes. This enables custom views that draw complex
2772 * content to report themselves as a tree of virtual views, thus conveying their
2773 * logical structure.
2774 * </p>
2775 * <p>
2776 * <strong>Note:</strong> Cannot be called from an
2777 * {@link android.accessibilityservice.AccessibilityService}.
2778 * This class is made immutable before being delivered to an AccessibilityService.
2779 * </p>
2780 *
2781 * @param root The root whose virtual descendant serves as a label.
2782 * @param virtualDescendantId The id of the virtual descendant.
2783 */
2784 public void setLabelFor(View root, int virtualDescendantId) {
2785 enforceNotSealed();
2786 final int rootAccessibilityViewId = (root != null)
Svetoslav8e3feb12014-02-24 13:46:47 -08002787 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002788 mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2789 }
2790
2791 /**
2792 * Gets the node info for which the view represented by this info serves as
2793 * a label for accessibility purposes.
2794 * <p>
2795 * <strong>Note:</strong> It is a client responsibility to recycle the
2796 * received info by calling {@link AccessibilityNodeInfo#recycle()}
2797 * to avoid creating of multiple instances.
2798 * </p>
2799 *
2800 * @return The labeled info.
2801 */
2802 public AccessibilityNodeInfo getLabelFor() {
2803 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08002804 return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002805 }
2806
2807 /**
2808 * Sets the view which serves as the label of the view represented by
2809 * this info for accessibility purposes.
2810 *
2811 * @param label The view that labels this node's source.
2812 */
2813 public void setLabeledBy(View label) {
Phil Weaverf00cd142017-03-03 13:44:00 -08002814 setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002815 }
2816
2817 /**
2818 * Sets the view which serves as the label of the view represented by
2819 * this info for accessibility purposes. If <code>virtualDescendantId</code>
2820 * is {@link View#NO_ID} the root is set as the label.
2821 * <p>
2822 * A virtual descendant is an imaginary View that is reported as a part of the view
2823 * hierarchy for accessibility purposes. This enables custom views that draw complex
2824 * content to report themselves as a tree of virtual views, thus conveying their
2825 * logical structure.
2826 * </p>
2827 * <p>
2828 * <strong>Note:</strong> Cannot be called from an
2829 * {@link android.accessibilityservice.AccessibilityService}.
2830 * This class is made immutable before being delivered to an AccessibilityService.
2831 * </p>
2832 *
2833 * @param root The root whose virtual descendant labels this node's source.
2834 * @param virtualDescendantId The id of the virtual descendant.
2835 */
2836 public void setLabeledBy(View root, int virtualDescendantId) {
2837 enforceNotSealed();
2838 final int rootAccessibilityViewId = (root != null)
Svetoslav8e3feb12014-02-24 13:46:47 -08002839 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002840 mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
2841 }
2842
2843 /**
2844 * Gets the node info which serves as the label of the view represented by
2845 * this info for accessibility purposes.
2846 * <p>
2847 * <strong>Note:</strong> It is a client responsibility to recycle the
2848 * received info by calling {@link AccessibilityNodeInfo#recycle()}
2849 * to avoid creating of multiple instances.
2850 * </p>
2851 *
2852 * @return The label.
2853 */
2854 public AccessibilityNodeInfo getLabeledBy() {
2855 enforceSealed();
Rhed Jaoae638752018-09-18 19:40:13 +08002856 return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById);
Svetoslav Ganov33aef982012-09-13 12:49:03 -07002857 }
2858
2859 /**
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002860 * Sets the fully qualified resource name of the source view's id.
2861 *
2862 * <p>
2863 * <strong>Note:</strong> Cannot be called from an
2864 * {@link android.accessibilityservice.AccessibilityService}.
2865 * This class is made immutable before being delivered to an AccessibilityService.
2866 * </p>
2867 *
Svetoslav92826452013-02-05 14:57:42 -08002868 * @param viewIdResName The id resource name.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002869 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07002870 public void setViewIdResourceName(String viewIdResName) {
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002871 enforceNotSealed();
Svetoslav22431a32013-02-05 14:30:19 -08002872 mViewIdResourceName = viewIdResName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002873 }
2874
2875 /**
2876 * Gets the fully qualified resource name of the source view's id.
2877 *
2878 * <p>
2879 * <strong>Note:</strong> The primary usage of this API is for UI test automation
2880 * and in order to report the source view id of an {@link AccessibilityNodeInfo} the
2881 * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
Svetoslav14ff9962013-01-29 03:21:37 -08002882 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002883 * </p>
2884
2885 * @return The id resource name.
2886 */
Svetoslav9fa1ee52013-04-22 12:43:03 -07002887 public String getViewIdResourceName() {
Svetoslav22431a32013-02-05 14:30:19 -08002888 return mViewIdResourceName;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08002889 }
2890
2891 /**
Phil Weaver40ded282016-01-25 15:49:02 -08002892 * Gets the text selection start or the cursor position.
2893 * <p>
2894 * If no text is selected, both this method and
2895 * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value:
2896 * the current location of the cursor.
2897 * </p>
Svetoslavbcc46a02013-02-06 11:56:00 -08002898 *
Phil Weaver40ded282016-01-25 15:49:02 -08002899 * @return The text selection start, the cursor location if there is no selection, or -1 if
2900 * there is no text selection and no cursor.
Svetoslavbcc46a02013-02-06 11:56:00 -08002901 */
2902 public int getTextSelectionStart() {
2903 return mTextSelectionStart;
2904 }
2905
2906 /**
Phil Weaver40ded282016-01-25 15:49:02 -08002907 * Gets the text selection end if text is selected.
2908 * <p>
2909 * If no text is selected, both this method and
2910 * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value:
2911 * the current location of the cursor.
2912 * </p>
Svetoslavbcc46a02013-02-06 11:56:00 -08002913 *
Phil Weaver40ded282016-01-25 15:49:02 -08002914 * @return The text selection end, the cursor location if there is no selection, or -1 if
2915 * there is no text selection and no cursor.
Svetoslavbcc46a02013-02-06 11:56:00 -08002916 */
2917 public int getTextSelectionEnd() {
2918 return mTextSelectionEnd;
2919 }
2920
2921 /**
2922 * Sets the text selection start and end.
2923 * <p>
2924 * <strong>Note:</strong> Cannot be called from an
2925 * {@link android.accessibilityservice.AccessibilityService}.
2926 * This class is made immutable before being delivered to an AccessibilityService.
2927 * </p>
2928 *
2929 * @param start The text selection start.
2930 * @param end The text selection end.
2931 *
2932 * @throws IllegalStateException If called from an AccessibilityService.
2933 */
2934 public void setTextSelection(int start, int end) {
2935 enforceNotSealed();
2936 mTextSelectionStart = start;
2937 mTextSelectionEnd = end;
2938 }
2939
2940 /**
Svetoslav6254f482013-06-04 17:22:14 -07002941 * Gets the input type of the source as defined by {@link InputType}.
2942 *
2943 * @return The input type.
2944 */
2945 public int getInputType() {
2946 return mInputType;
2947 }
2948
2949 /**
2950 * Sets the input type of the source as defined by {@link InputType}.
2951 * <p>
2952 * <strong>Note:</strong> Cannot be called from an
2953 * {@link android.accessibilityservice.AccessibilityService}.
2954 * This class is made immutable before being delivered to an
2955 * AccessibilityService.
2956 * </p>
2957 *
2958 * @param inputType The input type.
2959 *
2960 * @throws IllegalStateException If called from an AccessibilityService.
2961 */
2962 public void setInputType(int inputType) {
Alan Viverettedf39cb92013-08-19 12:28:04 -07002963 enforceNotSealed();
Svetoslav6254f482013-06-04 17:22:14 -07002964 mInputType = inputType;
2965 }
2966
2967 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002968 * Gets an optional bundle with extra data. The bundle
Svetoslav6254f482013-06-04 17:22:14 -07002969 * is lazily created and never <code>null</code>.
2970 * <p>
2971 * <strong>Note:</strong> It is recommended to use the package
2972 * name of your application as a prefix for the keys to avoid
2973 * collisions which may confuse an accessibility service if the
2974 * same key has different meaning when emitted from different
2975 * applications.
2976 * </p>
2977 *
2978 * @return The bundle.
2979 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002980 public Bundle getExtras() {
2981 if (mExtras == null) {
2982 mExtras = new Bundle();
Svetoslav6254f482013-06-04 17:22:14 -07002983 }
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07002984 return mExtras;
Svetoslav6254f482013-06-04 17:22:14 -07002985 }
2986
2987 /**
Phil Weaverc2e28932016-12-08 12:29:25 -08002988 * Check if a node has an extras bundle
2989 * @hide
2990 */
2991 public boolean hasExtras() {
2992 return mExtras != null;
2993 }
2994
2995 /**
Rhed Jaoae638752018-09-18 19:40:13 +08002996 * Get the {@link TouchDelegateInfo} for touch delegate behavior with the represented view.
2997 * It is possible for the same node to be pointed to by several regions. Use
2998 * {@link TouchDelegateInfo#getRegionAt(int)} to get touch delegate target {@link Region}, and
2999 * {@link TouchDelegateInfo#getTargetForRegion(Region)} for {@link AccessibilityNodeInfo} from
3000 * the given region.
3001 *
3002 * @return {@link TouchDelegateInfo} or {@code null} if there are no touch delegates.
3003 */
3004 @Nullable
3005 public TouchDelegateInfo getTouchDelegateInfo() {
3006 if (mTouchDelegateInfo != null) {
3007 mTouchDelegateInfo.setConnectionId(mConnectionId);
3008 mTouchDelegateInfo.setWindowId(mWindowId);
3009 }
3010 return mTouchDelegateInfo;
3011 }
3012
3013 /**
3014 * Set touch delegate info if the represented view has a {@link TouchDelegate}.
3015 * <p>
3016 * <strong>Note:</strong> Cannot be called from an
3017 * {@link android.accessibilityservice.AccessibilityService}.
3018 * This class is made immutable before being delivered to an
3019 * AccessibilityService.
3020 * </p>
3021 *
3022 * @param delegatedInfo {@link TouchDelegateInfo} returned from
3023 * {@link TouchDelegate#getTouchDelegateInfo()}.
3024 *
3025 * @throws IllegalStateException If called from an AccessibilityService.
3026 */
3027 public void setTouchDelegateInfo(@NonNull TouchDelegateInfo delegatedInfo) {
3028 enforceNotSealed();
3029 mTouchDelegateInfo = delegatedInfo;
3030 }
3031
3032 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003033 * Gets the value of a boolean property.
3034 *
3035 * @param property The property.
3036 * @return The value.
3037 */
3038 private boolean getBooleanProperty(int property) {
3039 return (mBooleanProperties & property) != 0;
3040 }
3041
3042 /**
3043 * Sets a boolean property.
3044 *
3045 * @param property The property.
3046 * @param value The value.
3047 *
3048 * @throws IllegalStateException If called from an AccessibilityService.
3049 */
3050 private void setBooleanProperty(int property, boolean value) {
3051 enforceNotSealed();
3052 if (value) {
3053 mBooleanProperties |= property;
3054 } else {
3055 mBooleanProperties &= ~property;
3056 }
3057 }
3058
3059 /**
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003060 * Sets the unique id of the IAccessibilityServiceConnection over which
3061 * this instance can send requests to the system.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003062 *
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003063 * @param connectionId The connection id.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003064 *
3065 * @hide
3066 */
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003067 public void setConnectionId(int connectionId) {
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003068 enforceNotSealed();
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003069 mConnectionId = connectionId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003070 }
3071
3072 /**
Phil Weaver23161e72017-04-19 12:16:36 -07003073 * Get the connection ID.
3074 *
3075 * @return The connection id
3076 *
3077 * @hide
3078 */
3079 public int getConnectionId() {
3080 return mConnectionId;
3081 }
3082
3083 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003084 * {@inheritDoc}
3085 */
Alan Viverettef0aed092013-11-06 15:33:03 -08003086 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003087 public int describeContents() {
3088 return 0;
3089 }
3090
3091 /**
Phil Weaverf00cd142017-03-03 13:44:00 -08003092 * Sets the id of the source node.
3093 *
3094 * @param sourceId The id.
3095 * @param windowId The window id.
3096 *
3097 * @hide
3098 */
3099 public void setSourceNodeId(long sourceId, int windowId) {
3100 enforceNotSealed();
3101 mSourceNodeId = sourceId;
3102 mWindowId = windowId;
3103 }
3104
3105 /**
Svetoslav Ganov79311c42012-01-17 20:24:26 -08003106 * Gets the id of the source node.
3107 *
3108 * @return The id.
3109 *
3110 * @hide
3111 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01003112 @UnsupportedAppUsage
Svetoslav Ganov79311c42012-01-17 20:24:26 -08003113 public long getSourceNodeId() {
3114 return mSourceNodeId;
3115 }
3116
3117 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003118 * Sets if this instance is sealed.
3119 *
3120 * @param sealed Whether is sealed.
3121 *
3122 * @hide
3123 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01003124 @UnsupportedAppUsage
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003125 public void setSealed(boolean sealed) {
3126 mSealed = sealed;
3127 }
3128
3129 /**
3130 * Gets if this instance is sealed.
3131 *
3132 * @return Whether is sealed.
3133 *
3134 * @hide
3135 */
Mathew Inwooda570dee2018-08-17 14:56:00 +01003136 @UnsupportedAppUsage
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003137 public boolean isSealed() {
3138 return mSealed;
3139 }
3140
3141 /**
3142 * Enforces that this instance is sealed.
3143 *
3144 * @throws IllegalStateException If this instance is not sealed.
3145 *
3146 * @hide
3147 */
3148 protected void enforceSealed() {
3149 if (!isSealed()) {
3150 throw new IllegalStateException("Cannot perform this "
3151 + "action on a not sealed instance.");
3152 }
3153 }
3154
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07003155 private void enforceValidFocusDirection(int direction) {
3156 switch (direction) {
3157 case View.FOCUS_DOWN:
3158 case View.FOCUS_UP:
3159 case View.FOCUS_LEFT:
3160 case View.FOCUS_RIGHT:
3161 case View.FOCUS_FORWARD:
3162 case View.FOCUS_BACKWARD:
Svetoslav Ganov2ef69052012-06-04 08:55:16 -07003163 return;
3164 default:
3165 throw new IllegalArgumentException("Unknown direction: " + direction);
3166 }
3167 }
3168
3169 private void enforceValidFocusType(int focusType) {
3170 switch (focusType) {
3171 case FOCUS_INPUT:
3172 case FOCUS_ACCESSIBILITY:
3173 return;
3174 default:
3175 throw new IllegalArgumentException("Unknown focus type: " + focusType);
3176 }
3177 }
3178
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003179 /**
3180 * Enforces that this instance is not sealed.
3181 *
3182 * @throws IllegalStateException If this instance is sealed.
3183 *
3184 * @hide
3185 */
3186 protected void enforceNotSealed() {
3187 if (isSealed()) {
3188 throw new IllegalStateException("Cannot perform this "
Ken Wakasaf76a50c2012-03-09 19:56:35 +09003189 + "action on a sealed instance.");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003190 }
3191 }
3192
3193 /**
3194 * Returns a cached instance if such is available otherwise a new one
3195 * and sets the source.
3196 *
Svetoslav Ganov02107852011-10-03 17:06:56 -07003197 * @param source The source view.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003198 * @return An instance.
3199 *
3200 * @see #setSource(View)
3201 */
3202 public static AccessibilityNodeInfo obtain(View source) {
3203 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
3204 info.setSource(source);
3205 return info;
3206 }
3207
3208 /**
Svetoslav Ganov02107852011-10-03 17:06:56 -07003209 * Returns a cached instance if such is available otherwise a new one
3210 * and sets the source.
3211 *
3212 * @param root The root of the virtual subtree.
3213 * @param virtualDescendantId The id of the virtual descendant.
3214 * @return An instance.
3215 *
3216 * @see #setSource(View, int)
3217 */
3218 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) {
3219 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
3220 info.setSource(root, virtualDescendantId);
3221 return info;
3222 }
3223
3224 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003225 * Returns a cached instance if such is available otherwise a new one.
3226 *
3227 * @return An instance.
3228 */
3229 public static AccessibilityNodeInfo obtain() {
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08003230 AccessibilityNodeInfo info = sPool.acquire();
Phil Weaver62d20fa2016-09-15 11:05:55 -07003231 if (sNumInstancesInUse != null) {
3232 sNumInstancesInUse.incrementAndGet();
3233 }
Phil Weavere1951292017-08-18 17:56:04 +00003234 return (info != null) ? info : new AccessibilityNodeInfo();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003235 }
3236
3237 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003238 * Returns a cached instance if such is available or a new one is
3239 * create. The returned instance is initialized from the given
3240 * <code>info</code>.
3241 *
3242 * @param info The other info.
3243 * @return An instance.
3244 */
3245 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
3246 AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
3247 infoClone.init(info);
3248 return infoClone;
3249 }
3250
3251 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003252 * Return an instance back to be reused.
3253 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003254 * <strong>Note:</strong> You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003255 *
3256 * @throws IllegalStateException If the info is already recycled.
3257 */
3258 public void recycle() {
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003259 clear();
Svetoslav Ganovf4782ec2012-11-28 09:11:41 -08003260 sPool.release(this);
Phil Weaver62d20fa2016-09-15 11:05:55 -07003261 if (sNumInstancesInUse != null) {
3262 sNumInstancesInUse.decrementAndGet();
3263 }
Phil Weaverb010b122016-08-17 17:47:48 -07003264 }
3265
3266 /**
Phil Weaver62d20fa2016-09-15 11:05:55 -07003267 * Specify a counter that will be incremented on obtain() and decremented on recycle()
Phil Weaverb010b122016-08-17 17:47:48 -07003268 *
3269 * @hide
3270 */
Phil Weaver62d20fa2016-09-15 11:05:55 -07003271 @TestApi
3272 public static void setNumInstancesInUseCounter(AtomicInteger counter) {
3273 sNumInstancesInUse = counter;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003274 }
3275
3276 /**
3277 * {@inheritDoc}
3278 * <p>
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003279 * <strong>Note:</strong> After the instance is written to a parcel it
3280 * is recycled. You must not touch the object after calling this function.
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003281 * </p>
3282 */
Alan Viverettef0aed092013-11-06 15:33:03 -08003283 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003284 public void writeToParcel(Parcel parcel, int flags) {
Phil Weaver63072402018-02-07 15:47:33 -08003285 writeToParcelNoRecycle(parcel, flags);
3286 // Since instances of this class are fetched via synchronous i.e. blocking
3287 // calls in IPCs we always recycle as soon as the instance is marshaled.
3288 recycle();
3289 }
3290
3291 /** @hide */
3292 @TestApi
3293 public void writeToParcelNoRecycle(Parcel parcel, int flags) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003294 // Write bit set of indices of fields with values differing from default
3295 long nonDefaultFields = 0;
3296 int fieldIndex = 0; // index of the current field
3297 if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex);
3298 fieldIndex++;
3299 if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex);
3300 fieldIndex++;
3301 if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex);
3302 fieldIndex++;
3303 if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex);
3304 fieldIndex++;
3305 if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex);
3306 fieldIndex++;
3307 if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex);
3308 fieldIndex++;
3309 if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex);
3310 fieldIndex++;
3311 if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex);
3312 fieldIndex++;
3313 if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex);
3314 fieldIndex++;
Eugene Susla9669e3a2018-02-08 15:14:06 -08003315 if (!LongArray.elementsEqual(mChildNodeIds, DEFAULT.mChildNodeIds)) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003316 nonDefaultFields |= bitAt(fieldIndex);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003317 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003318 fieldIndex++;
3319 if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) {
3320 nonDefaultFields |= bitAt(fieldIndex);
3321 }
3322 fieldIndex++;
3323 if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) {
3324 nonDefaultFields |= bitAt(fieldIndex);
3325 }
3326 fieldIndex++;
3327 if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex);
3328 fieldIndex++;
3329 if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex);
3330 fieldIndex++;
3331 if (mMovementGranularities != DEFAULT.mMovementGranularities) {
3332 nonDefaultFields |= bitAt(fieldIndex);
3333 }
3334 fieldIndex++;
3335 if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex);
3336 fieldIndex++;
3337 if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) {
3338 nonDefaultFields |= bitAt(fieldIndex);
3339 }
3340 fieldIndex++;
3341 if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex);
3342 fieldIndex++;
3343 if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex);
3344 fieldIndex++;
3345 if (!Objects.equals(mHintText, DEFAULT.mHintText)) {
3346 nonDefaultFields |= bitAt(fieldIndex);
3347 }
3348 fieldIndex++;
3349 if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex);
3350 fieldIndex++;
3351 if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) {
3352 nonDefaultFields |= bitAt(fieldIndex);
3353 }
3354 fieldIndex++;
Phil Weaver9f26b3d2018-01-04 10:04:37 -08003355 if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) {
3356 nonDefaultFields |= bitAt(fieldIndex);
3357 }
3358 fieldIndex++;
Phil Weaverd89905f2018-01-10 08:28:04 -08003359 if (!Objects.equals(mTooltipText, DEFAULT.mTooltipText)) {
3360 nonDefaultFields |= bitAt(fieldIndex);
3361 }
3362 fieldIndex++;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003363 if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) {
3364 nonDefaultFields |= bitAt(fieldIndex);
3365 }
3366 fieldIndex++;
3367 if (mTextSelectionStart != DEFAULT.mTextSelectionStart) {
3368 nonDefaultFields |= bitAt(fieldIndex);
3369 }
3370 fieldIndex++;
3371 if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) {
3372 nonDefaultFields |= bitAt(fieldIndex);
3373 }
3374 fieldIndex++;
3375 if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex);
3376 fieldIndex++;
3377 if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex);
3378 fieldIndex++;
3379 if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) {
3380 nonDefaultFields |= bitAt(fieldIndex);
3381 }
3382 fieldIndex++;
3383 if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) {
3384 nonDefaultFields |= bitAt(fieldIndex);
3385 }
3386 fieldIndex++;
3387 if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex);
3388 fieldIndex++;
3389 if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex);
3390 fieldIndex++;
3391 if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) {
3392 nonDefaultFields |= bitAt(fieldIndex);
3393 }
3394 fieldIndex++;
3395 if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
3396 nonDefaultFields |= bitAt(fieldIndex);
3397 }
Rhed Jaoae638752018-09-18 19:40:13 +08003398 fieldIndex++;
3399 if (!Objects.equals(mTouchDelegateInfo, DEFAULT.mTouchDelegateInfo)) {
3400 nonDefaultFields |= bitAt(fieldIndex);
3401 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003402 int totalFields = fieldIndex;
3403 parcel.writeLong(nonDefaultFields);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003404
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003405 fieldIndex = 0;
3406 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0);
3407 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId);
3408 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId);
3409 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId);
3410 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId);
3411 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById);
3412 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore);
3413 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter);
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003414
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003415 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003416
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003417 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3418 final LongArray childIds = mChildNodeIds;
3419 if (childIds == null) {
3420 parcel.writeInt(0);
3421 } else {
3422 final int childIdsSize = childIds.size();
3423 parcel.writeInt(childIdsSize);
3424 for (int i = 0; i < childIdsSize; i++) {
3425 parcel.writeLong(childIds.get(i));
Kristian Monsen74bc1942014-04-29 11:00:17 -07003426 }
3427 }
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003428 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003429
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003430 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3431 parcel.writeInt(mBoundsInParent.top);
3432 parcel.writeInt(mBoundsInParent.bottom);
3433 parcel.writeInt(mBoundsInParent.left);
3434 parcel.writeInt(mBoundsInParent.right);
3435 }
3436
3437 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3438 parcel.writeInt(mBoundsInScreen.top);
3439 parcel.writeInt(mBoundsInScreen.bottom);
3440 parcel.writeInt(mBoundsInScreen.left);
3441 parcel.writeInt(mBoundsInScreen.right);
3442 }
3443
3444 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3445 if (mActions != null && !mActions.isEmpty()) {
3446 final int actionCount = mActions.size();
3447
Eugene Susla554edd32017-05-24 16:49:59 -07003448 int nonStandardActionCount = 0;
Phil Weaver2c9e7802018-03-05 15:22:32 -08003449 long defaultStandardActions = 0;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003450 for (int i = 0; i < actionCount; i++) {
3451 AccessibilityAction action = mActions.get(i);
Eugene Susla554edd32017-05-24 16:49:59 -07003452 if (isDefaultStandardAction(action)) {
3453 defaultStandardActions |= action.mSerializationFlag;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003454 } else {
Eugene Susla554edd32017-05-24 16:49:59 -07003455 nonStandardActionCount++;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003456 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003457 }
Phil Weaver2c9e7802018-03-05 15:22:32 -08003458 parcel.writeLong(defaultStandardActions);
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003459
Eugene Susla554edd32017-05-24 16:49:59 -07003460 parcel.writeInt(nonStandardActionCount);
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003461 for (int i = 0; i < actionCount; i++) {
3462 AccessibilityAction action = mActions.get(i);
Eugene Susla554edd32017-05-24 16:49:59 -07003463 if (!isDefaultStandardAction(action)) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003464 parcel.writeInt(action.getId());
3465 parcel.writeCharSequence(action.getLabel());
3466 }
3467 }
3468 } else {
Phil Weaver2c9e7802018-03-05 15:22:32 -08003469 parcel.writeLong(0);
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003470 parcel.writeInt(0);
Kristian Monsen74bc1942014-04-29 11:00:17 -07003471 }
Kristian Monsen74bc1942014-04-29 11:00:17 -07003472 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003473
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003474 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength);
3475 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities);
3476 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003477
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003478 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName);
3479 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName);
3480 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText);
3481 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText);
3482 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError);
3483 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3484 parcel.writeCharSequence(mContentDescription);
Phil Weaverc2e28932016-12-08 12:29:25 -08003485 }
Phil Weaver9f26b3d2018-01-04 10:04:37 -08003486 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle);
Phil Weaverd89905f2018-01-10 08:28:04 -08003487 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mTooltipText);
3488
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003489 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName);
Svetoslav6254f482013-06-04 17:22:14 -07003490
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003491 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart);
3492 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd);
3493 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType);
3494 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion);
3495 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent);
Svetoslavbcc46a02013-02-06 11:56:00 -08003496
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003497 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys);
3498
3499 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras);
3500
3501 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav3577a282013-06-06 14:09:10 -07003502 parcel.writeInt(mRangeInfo.getType());
3503 parcel.writeFloat(mRangeInfo.getMin());
3504 parcel.writeFloat(mRangeInfo.getMax());
3505 parcel.writeFloat(mRangeInfo.getCurrent());
Svetoslav3577a282013-06-06 14:09:10 -07003506 }
3507
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003508 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07003509 parcel.writeInt(mCollectionInfo.getRowCount());
3510 parcel.writeInt(mCollectionInfo.getColumnCount());
Svetoslav3577a282013-06-06 14:09:10 -07003511 parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
Alan Viverette76769ae2014-02-12 16:38:10 -08003512 parcel.writeInt(mCollectionInfo.getSelectionMode());
Svetoslav3577a282013-06-06 14:09:10 -07003513 }
3514
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003515 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07003516 parcel.writeInt(mCollectionItemInfo.getRowIndex());
3517 parcel.writeInt(mCollectionItemInfo.getRowSpan());
Alan Viverettefaeac962015-06-01 09:03:27 -07003518 parcel.writeInt(mCollectionItemInfo.getColumnIndex());
3519 parcel.writeInt(mCollectionItemInfo.getColumnSpan());
Svetoslav3577a282013-06-06 14:09:10 -07003520 parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
Alan Viverette76769ae2014-02-12 16:38:10 -08003521 parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003522 }
3523
Rhed Jaoae638752018-09-18 19:40:13 +08003524 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3525 mTouchDelegateInfo.writeToParcel(parcel, flags);
3526 }
3527
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003528 if (DEBUG) {
3529 fieldIndex--;
3530 if (totalFields != fieldIndex) {
3531 throw new IllegalStateException("Number of fields mismatch: " + totalFields
3532 + " vs " + fieldIndex);
3533 }
Svetoslav3577a282013-06-06 14:09:10 -07003534 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003535 }
3536
3537 /**
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003538 * Initializes this instance from another one.
3539 *
3540 * @param other The other instance.
3541 */
3542 private void init(AccessibilityNodeInfo other) {
3543 mSealed = other.mSealed;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003544 mSourceNodeId = other.mSourceNodeId;
3545 mParentNodeId = other.mParentNodeId;
Svetoslav Ganov33aef982012-09-13 12:49:03 -07003546 mLabelForId = other.mLabelForId;
3547 mLabeledById = other.mLabeledById;
Svetoslav6c702902014-10-09 18:40:56 -07003548 mTraversalBefore = other.mTraversalBefore;
3549 mTraversalAfter = other.mTraversalAfter;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003550 mWindowId = other.mWindowId;
Svetoslav Ganovd116d7c2011-11-21 18:41:59 -08003551 mConnectionId = other.mConnectionId;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003552 mBoundsInParent.set(other.mBoundsInParent);
3553 mBoundsInScreen.set(other.mBoundsInScreen);
3554 mPackageName = other.mPackageName;
3555 mClassName = other.mClassName;
3556 mText = other.mText;
Phil Weaver6f8ec1fd2018-04-24 10:13:12 -07003557 mOriginalText = other.mOriginalText;
Phil Weaver776afc22016-12-21 10:55:13 -08003558 mHintText = other.mHintText;
Alan Viverettefccbff52014-07-07 15:06:14 -07003559 mError = other.mError;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003560 mContentDescription = other.mContentDescription;
Phil Weaver9f26b3d2018-01-04 10:04:37 -08003561 mPaneTitle = other.mPaneTitle;
Phil Weaverd89905f2018-01-10 08:28:04 -08003562 mTooltipText = other.mTooltipText;
Svetoslav22431a32013-02-05 14:30:19 -08003563 mViewIdResourceName = other.mViewIdResourceName;
Kristian Monsen74bc1942014-04-29 11:00:17 -07003564
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003565 if (mActions != null) mActions.clear();
Kristian Monsen74bc1942014-04-29 11:00:17 -07003566 final ArrayList<AccessibilityAction> otherActions = other.mActions;
3567 if (otherActions != null && otherActions.size() > 0) {
3568 if (mActions == null) {
3569 mActions = new ArrayList(otherActions);
3570 } else {
Kristian Monsen74bc1942014-04-29 11:00:17 -07003571 mActions.addAll(other.mActions);
3572 }
3573 }
3574
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003575 mBooleanProperties = other.mBooleanProperties;
Alan Viverette029942f2014-08-12 14:55:56 -07003576 mMaxTextLength = other.mMaxTextLength;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003577 mMovementGranularities = other.mMovementGranularities;
Alan Viverettef0aed092013-11-06 15:33:03 -08003578
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003579
3580 if (mChildNodeIds != null) mChildNodeIds.clear();
Alan Viverettef0aed092013-11-06 15:33:03 -08003581 final LongArray otherChildNodeIds = other.mChildNodeIds;
3582 if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
3583 if (mChildNodeIds == null) {
3584 mChildNodeIds = otherChildNodeIds.clone();
3585 } else {
3586 mChildNodeIds.addAll(otherChildNodeIds);
3587 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003588 }
Alan Viverettef0aed092013-11-06 15:33:03 -08003589
Svetoslavbcc46a02013-02-06 11:56:00 -08003590 mTextSelectionStart = other.mTextSelectionStart;
3591 mTextSelectionEnd = other.mTextSelectionEnd;
Svetoslav6254f482013-06-04 17:22:14 -07003592 mInputType = other.mInputType;
Alan Viverette77e9a282013-09-12 17:16:09 -07003593 mLiveRegion = other.mLiveRegion;
Phil Weaver1f222542016-01-08 11:49:32 -08003594 mDrawingOrderInParent = other.mDrawingOrderInParent;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003595
Phil Weaverc2e28932016-12-08 12:29:25 -08003596 mExtraDataKeys = other.mExtraDataKeys;
3597
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003598 mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
3599
3600 if (mRangeInfo != null) mRangeInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003601 mRangeInfo = (other.mRangeInfo != null)
3602 ? RangeInfo.obtain(other.mRangeInfo) : null;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003603 if (mCollectionInfo != null) mCollectionInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003604 mCollectionInfo = (other.mCollectionInfo != null)
3605 ? CollectionInfo.obtain(other.mCollectionInfo) : null;
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003606 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07003607 mCollectionItemInfo = (other.mCollectionItemInfo != null)
3608 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
Rhed Jaoae638752018-09-18 19:40:13 +08003609
3610 final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
3611 mTouchDelegateInfo = (otherInfo != null)
3612 ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
Svetoslav Ganov35bfede2011-07-14 17:57:06 -07003613 }
3614
3615 /**
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003616 * Creates a new instance from a {@link Parcel}.
3617 *
3618 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
3619 */
3620 private void initFromParcel(Parcel parcel) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003621 // Bit mask of non-default-valued field indices
3622 long nonDefaultFields = parcel.readLong();
3623 int fieldIndex = 0;
3624 final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++)
3625 ? (parcel.readInt() == 1)
3626 : DEFAULT.mSealed;
3627 if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong();
3628 if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt();
3629 if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong();
3630 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong();
3631 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong();
3632 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong();
3633 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong();
Svetoslav6c702902014-10-09 18:40:56 -07003634
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003635 if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003636
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003637 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3638 final int childrenSize = parcel.readInt();
3639 if (childrenSize <= 0) {
3640 mChildNodeIds = null;
3641 } else {
3642 mChildNodeIds = new LongArray(childrenSize);
3643 for (int i = 0; i < childrenSize; i++) {
3644 final long childId = parcel.readLong();
3645 mChildNodeIds.add(childId);
3646 }
Alan Viverettef0aed092013-11-06 15:33:03 -08003647 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003648 }
3649
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003650 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3651 mBoundsInParent.top = parcel.readInt();
3652 mBoundsInParent.bottom = parcel.readInt();
3653 mBoundsInParent.left = parcel.readInt();
3654 mBoundsInParent.right = parcel.readInt();
Kristian Monsen74bc1942014-04-29 11:00:17 -07003655 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003656
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003657 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3658 mBoundsInScreen.top = parcel.readInt();
3659 mBoundsInScreen.bottom = parcel.readInt();
3660 mBoundsInScreen.left = parcel.readInt();
3661 mBoundsInScreen.right = parcel.readInt();
Phil Weaverc2e28932016-12-08 12:29:25 -08003662 }
3663
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003664 if (isBitSet(nonDefaultFields, fieldIndex++)) {
Phil Weaver2c9e7802018-03-05 15:22:32 -08003665 final long standardActions = parcel.readLong();
Eugene Susla554edd32017-05-24 16:49:59 -07003666 addStandardActions(standardActions);
3667 final int nonStandardActionCount = parcel.readInt();
3668 for (int i = 0; i < nonStandardActionCount; i++) {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003669 final AccessibilityAction action = new AccessibilityAction(
3670 parcel.readInt(), parcel.readCharSequence());
3671 addActionUnchecked(action);
3672 }
Svetoslav6254f482013-06-04 17:22:14 -07003673 }
Svetoslav3577a282013-06-06 14:09:10 -07003674
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003675 if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt();
3676 if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt();
3677 if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt();
Svetoslav3577a282013-06-06 14:09:10 -07003678
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003679 if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence();
3680 if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence();
3681 if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence();
3682 if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence();
3683 if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence();
3684 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3685 mContentDescription = parcel.readCharSequence();
Svetoslav3577a282013-06-06 14:09:10 -07003686 }
Phil Weaver63072402018-02-07 15:47:33 -08003687 if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readCharSequence();
Phil Weaverd89905f2018-01-10 08:28:04 -08003688 if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence();
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003689 if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
Svetoslav3577a282013-06-06 14:09:10 -07003690
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003691 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt();
3692 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt();
3693
3694 if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt();
3695 if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt();
3696 if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt();
3697
3698 mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++)
3699 ? parcel.createStringArrayList()
3700 : null;
3701
3702 mExtras = isBitSet(nonDefaultFields, fieldIndex++)
3703 ? parcel.readBundle()
3704 : null;
3705
3706 if (mRangeInfo != null) mRangeInfo.recycle();
3707 mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++)
3708 ? RangeInfo.obtain(
3709 parcel.readInt(),
3710 parcel.readFloat(),
3711 parcel.readFloat(),
3712 parcel.readFloat())
3713 : null;
3714
3715 if (mCollectionInfo != null) mCollectionInfo.recycle();
3716 mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++)
3717 ? CollectionInfo.obtain(
3718 parcel.readInt(),
3719 parcel.readInt(),
3720 parcel.readInt() == 1,
3721 parcel.readInt())
3722 : null;
3723
3724 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
3725 mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
3726 ? CollectionItemInfo.obtain(
3727 parcel.readInt(),
3728 parcel.readInt(),
3729 parcel.readInt(),
3730 parcel.readInt(),
3731 parcel.readInt() == 1,
3732 parcel.readInt() == 1)
3733 : null;
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -07003734
Rhed Jaoae638752018-09-18 19:40:13 +08003735 if (isBitSet(nonDefaultFields, fieldIndex++)) {
3736 mTouchDelegateInfo = TouchDelegateInfo.CREATOR.createFromParcel(parcel);
3737 }
3738
Maxim Bogatov2f55a3f2015-06-09 15:00:44 -07003739 mSealed = sealed;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003740 }
3741
3742 /**
3743 * Clears the state of this instance.
3744 */
3745 private void clear() {
Eugene Susla0eb2b6e2017-05-15 14:06:32 -07003746 init(DEFAULT);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003747 }
3748
Eugene Susla554edd32017-05-24 16:49:59 -07003749 private static boolean isDefaultStandardAction(AccessibilityAction action) {
Phil Weaver2c9e7802018-03-05 15:22:32 -08003750 return (action.mSerializationFlag != -1L) && TextUtils.isEmpty(action.getLabel());
Kristian Monsen74bc1942014-04-29 11:00:17 -07003751 }
3752
3753 private static AccessibilityAction getActionSingleton(int actionId) {
3754 final int actions = AccessibilityAction.sStandardActions.size();
3755 for (int i = 0; i < actions; i++) {
3756 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
3757 if (actionId == currentAction.getId()) {
3758 return currentAction;
3759 }
3760 }
3761
3762 return null;
3763 }
3764
Phil Weaver2c9e7802018-03-05 15:22:32 -08003765 private static AccessibilityAction getActionSingletonBySerializationFlag(long flag) {
Eugene Susla554edd32017-05-24 16:49:59 -07003766 final int actions = AccessibilityAction.sStandardActions.size();
3767 for (int i = 0; i < actions; i++) {
3768 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
3769 if (flag == currentAction.mSerializationFlag) {
3770 return currentAction;
3771 }
3772 }
3773
3774 return null;
3775 }
3776
Phil Weaver2c9e7802018-03-05 15:22:32 -08003777 private void addStandardActions(long serializationIdMask) {
3778 long remainingIds = serializationIdMask;
Kristian Monsen74bc1942014-04-29 11:00:17 -07003779 while (remainingIds > 0) {
Phil Weaver2c9e7802018-03-05 15:22:32 -08003780 final long id = 1L << Long.numberOfTrailingZeros(remainingIds);
Kristian Monsen74bc1942014-04-29 11:00:17 -07003781 remainingIds &= ~id;
Eugene Susla554edd32017-05-24 16:49:59 -07003782 AccessibilityAction action = getActionSingletonBySerializationFlag(id);
Kristian Monsen74bc1942014-04-29 11:00:17 -07003783 addAction(action);
3784 }
3785 }
3786
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003787 /**
3788 * Gets the human readable action symbolic name.
3789 *
3790 * @param action The action.
3791 * @return The symbolic name.
3792 */
3793 private static String getActionSymbolicName(int action) {
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003794 switch (action) {
3795 case ACTION_FOCUS:
3796 return "ACTION_FOCUS";
3797 case ACTION_CLEAR_FOCUS:
3798 return "ACTION_CLEAR_FOCUS";
3799 case ACTION_SELECT:
3800 return "ACTION_SELECT";
3801 case ACTION_CLEAR_SELECTION:
3802 return "ACTION_CLEAR_SELECTION";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07003803 case ACTION_CLICK:
3804 return "ACTION_CLICK";
3805 case ACTION_LONG_CLICK:
3806 return "ACTION_LONG_CLICK";
3807 case ACTION_ACCESSIBILITY_FOCUS:
3808 return "ACTION_ACCESSIBILITY_FOCUS";
3809 case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
3810 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003811 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
3812 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
3813 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
3814 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
Svetoslav Ganove9bda152012-04-30 16:55:21 -07003815 case ACTION_NEXT_HTML_ELEMENT:
3816 return "ACTION_NEXT_HTML_ELEMENT";
3817 case ACTION_PREVIOUS_HTML_ELEMENT:
3818 return "ACTION_PREVIOUS_HTML_ELEMENT";
Svetoslav Ganova1dc7612012-05-10 04:14:53 -07003819 case ACTION_SCROLL_FORWARD:
3820 return "ACTION_SCROLL_FORWARD";
3821 case ACTION_SCROLL_BACKWARD:
3822 return "ACTION_SCROLL_BACKWARD";
Svetoslav Ganov242724e2013-02-01 14:42:18 -08003823 case ACTION_CUT:
3824 return "ACTION_CUT";
3825 case ACTION_COPY:
3826 return "ACTION_COPY";
3827 case ACTION_PASTE:
3828 return "ACTION_PASTE";
3829 case ACTION_SET_SELECTION:
3830 return "ACTION_SET_SELECTION";
Steven Dao103a577c2015-10-12 17:35:59 -07003831 case ACTION_EXPAND:
3832 return "ACTION_EXPAND";
3833 case ACTION_COLLAPSE:
3834 return "ACTION_COLLAPSE";
3835 case ACTION_DISMISS:
3836 return "ACTION_DISMISS";
3837 case ACTION_SET_TEXT:
3838 return "ACTION_SET_TEXT";
3839 case R.id.accessibilityActionShowOnScreen:
3840 return "ACTION_SHOW_ON_SCREEN";
3841 case R.id.accessibilityActionScrollToPosition:
3842 return "ACTION_SCROLL_TO_POSITION";
3843 case R.id.accessibilityActionScrollUp:
3844 return "ACTION_SCROLL_UP";
3845 case R.id.accessibilityActionScrollLeft:
3846 return "ACTION_SCROLL_LEFT";
3847 case R.id.accessibilityActionScrollDown:
3848 return "ACTION_SCROLL_DOWN";
3849 case R.id.accessibilityActionScrollRight:
3850 return "ACTION_SCROLL_RIGHT";
Qasid Ahmad Sadiq95705612018-11-09 21:11:01 -08003851 case R.id.accessibilityActionPageDown:
3852 return "ACTION_PAGE_DOWN";
3853 case R.id.accessibilityActionPageUp:
3854 return "ACTION_PAGE_UP";
3855 case R.id.accessibilityActionPageLeft:
3856 return "ACTION_PAGE_LEFT";
3857 case R.id.accessibilityActionPageRight:
3858 return "ACTION_PAGE_RIGHT";
Steven Dao103a577c2015-10-12 17:35:59 -07003859 case R.id.accessibilityActionSetProgress:
3860 return "ACTION_SET_PROGRESS";
3861 case R.id.accessibilityActionContextClick:
3862 return "ACTION_CONTEXT_CLICK";
Phil Weaverd89905f2018-01-10 08:28:04 -08003863 case R.id.accessibilityActionShowTooltip:
3864 return "ACTION_SHOW_TOOLTIP";
3865 case R.id.accessibilityActionHideTooltip:
3866 return "ACTION_HIDE_TOOLTIP";
Svetoslav Ganov38e8b4e2011-06-29 20:00:53 -07003867 default:
Steven Dao103a577c2015-10-12 17:35:59 -07003868 return "ACTION_UNKNOWN";
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003869 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003870 }
3871
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003872 /**
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003873 * Gets the human readable movement granularity symbolic name.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003874 *
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003875 * @param granularity The granularity.
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003876 * @return The symbolic name.
3877 */
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003878 private static String getMovementGranularitySymbolicName(int granularity) {
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003879 switch (granularity) {
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003880 case MOVEMENT_GRANULARITY_CHARACTER:
3881 return "MOVEMENT_GRANULARITY_CHARACTER";
3882 case MOVEMENT_GRANULARITY_WORD:
3883 return "MOVEMENT_GRANULARITY_WORD";
3884 case MOVEMENT_GRANULARITY_LINE:
3885 return "MOVEMENT_GRANULARITY_LINE";
3886 case MOVEMENT_GRANULARITY_PARAGRAPH:
3887 return "MOVEMENT_GRANULARITY_PARAGRAPH";
3888 case MOVEMENT_GRANULARITY_PAGE:
3889 return "MOVEMENT_GRANULARITY_PAGE";
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003890 default:
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003891 throw new IllegalArgumentException("Unknown movement granularity: " + granularity);
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003892 }
3893 }
3894
Rhed Jaoae638752018-09-18 19:40:13 +08003895 private static boolean canPerformRequestOverConnection(int connectionId,
3896 int windowId, long accessibilityNodeId) {
3897 return ((windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
Phil Weaver23161e72017-04-19 12:16:36 -07003898 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
Rhed Jaoae638752018-09-18 19:40:13 +08003899 && (connectionId != UNDEFINED_CONNECTION_ID));
Svetoslav Ganoveeee4d22011-06-10 20:51:30 -07003900 }
3901
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003902 @Override
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003903 public boolean equals(Object object) {
3904 if (this == object) {
3905 return true;
3906 }
3907 if (object == null) {
3908 return false;
3909 }
3910 if (getClass() != object.getClass()) {
3911 return false;
3912 }
3913 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003914 if (mSourceNodeId != other.mSourceNodeId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003915 return false;
3916 }
Svetoslav Ganov02107852011-10-03 17:06:56 -07003917 if (mWindowId != other.mWindowId) {
Svetoslav Ganov8dffad62011-06-10 12:38:36 -07003918 return false;
3919 }
3920 return true;
3921 }
3922
3923 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003924 public int hashCode() {
3925 final int prime = 31;
3926 int result = 1;
Svetoslav Ganov02107852011-10-03 17:06:56 -07003927 result = prime * result + getAccessibilityViewId(mSourceNodeId);
3928 result = prime * result + getVirtualDescendantId(mSourceNodeId);
3929 result = prime * result + mWindowId;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003930 return result;
3931 }
3932
3933 @Override
3934 public String toString() {
3935 StringBuilder builder = new StringBuilder();
3936 builder.append(super.toString());
3937
3938 if (DEBUG) {
Svetoslav8e3feb12014-02-24 13:46:47 -08003939 builder.append("; sourceNodeId: " + mSourceNodeId);
Felipe Lemeac645ba2017-12-08 14:04:28 -08003940 builder.append("; windowId: " + mWindowId);
3941 builder.append("; accessibilityViewId: ").append(getAccessibilityViewId(mSourceNodeId));
3942 builder.append("; virtualDescendantId: ").append(getVirtualDescendantId(mSourceNodeId));
Svetoslav Ganov02107852011-10-03 17:06:56 -07003943 builder.append("; mParentNodeId: " + mParentNodeId);
Svetoslav6c702902014-10-09 18:40:56 -07003944 builder.append("; traversalBefore: ").append(mTraversalBefore);
3945 builder.append("; traversalAfter: ").append(mTraversalAfter);
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003946
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003947 int granularities = mMovementGranularities;
3948 builder.append("; MovementGranularities: [");
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003949 while (granularities != 0) {
3950 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities);
3951 granularities &= ~granularity;
Svetoslav Ganov2b435aa2012-05-04 17:16:37 -07003952 builder.append(getMovementGranularitySymbolicName(granularity));
Svetoslav Ganovb7ff3252012-04-24 18:40:07 -07003953 if (granularities != 0) {
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003954 builder.append(", ");
3955 }
3956 }
3957 builder.append("]");
3958
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003959 builder.append("; childAccessibilityIds: [");
Alan Viverettef0aed092013-11-06 15:33:03 -08003960 final LongArray childIds = mChildNodeIds;
3961 if (childIds != null) {
3962 for (int i = 0, count = childIds.size(); i < count; i++) {
3963 builder.append(childIds.get(i));
3964 if (i < count - 1) {
3965 builder.append(", ");
3966 }
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003967 }
Svetoslav Ganovaa780c12012-04-19 23:01:39 -07003968 }
3969 builder.append("]");
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003970 }
3971
Felipe Lemeac645ba2017-12-08 14:04:28 -08003972 builder.append("; boundsInParent: ").append(mBoundsInParent);
3973 builder.append("; boundsInScreen: ").append(mBoundsInScreen);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003974
3975 builder.append("; packageName: ").append(mPackageName);
3976 builder.append("; className: ").append(mClassName);
3977 builder.append("; text: ").append(mText);
Alan Viverettefccbff52014-07-07 15:06:14 -07003978 builder.append("; error: ").append(mError);
Alan Viverette029942f2014-08-12 14:55:56 -07003979 builder.append("; maxTextLength: ").append(mMaxTextLength);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003980 builder.append("; contentDescription: ").append(mContentDescription);
Phil Weaverd89905f2018-01-10 08:28:04 -08003981 builder.append("; tooltipText: ").append(mTooltipText);
Svetoslav22431a32013-02-05 14:30:19 -08003982 builder.append("; viewIdResName: ").append(mViewIdResourceName);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003983
3984 builder.append("; checkable: ").append(isCheckable());
3985 builder.append("; checked: ").append(isChecked());
3986 builder.append("; focusable: ").append(isFocusable());
3987 builder.append("; focused: ").append(isFocused());
3988 builder.append("; selected: ").append(isSelected());
3989 builder.append("; clickable: ").append(isClickable());
3990 builder.append("; longClickable: ").append(isLongClickable());
Mady Mellore8608912015-06-05 09:02:55 -07003991 builder.append("; contextClickable: ").append(isContextClickable());
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003992 builder.append("; enabled: ").append(isEnabled());
3993 builder.append("; password: ").append(isPassword());
Kristian Monsen74bc1942014-04-29 11:00:17 -07003994 builder.append("; scrollable: ").append(isScrollable());
Phil Weaver4d3eec412016-09-01 16:28:34 -07003995 builder.append("; importantForAccessibility: ").append(isImportantForAccessibility());
Felipe Leme7008e702018-03-16 18:02:16 -07003996 builder.append("; visible: ").append(isVisibleToUser());
Kristian Monsen74bc1942014-04-29 11:00:17 -07003997 builder.append("; actions: ").append(mActions);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07003998
3999 return builder.toString();
4000 }
4001
Rhed Jaoae638752018-09-18 19:40:13 +08004002 private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
4003 int windowId, long accessibilityId) {
4004 if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) {
Svetoslav6c702902014-10-09 18:40:56 -07004005 return null;
4006 }
4007 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
Rhed Jaoae638752018-09-18 19:40:13 +08004008 return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
4009 windowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
Phil Weaverc2e28932016-12-08 12:29:25 -08004010 | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
Svetoslav6c702902014-10-09 18:40:56 -07004011 }
4012
Eugene Susla9af1378c2018-03-22 16:29:10 -07004013 /** @hide */
4014 public static String idToString(long accessibilityId) {
4015 int accessibilityViewId = getAccessibilityViewId(accessibilityId);
4016 int virtualDescendantId = getVirtualDescendantId(accessibilityId);
4017 return virtualDescendantId == AccessibilityNodeProvider.HOST_VIEW_ID
4018 ? idItemToString(accessibilityViewId)
4019 : idItemToString(accessibilityViewId) + ":" + idItemToString(virtualDescendantId);
4020 }
4021
4022 private static String idItemToString(int item) {
4023 switch (item) {
4024 case ROOT_ITEM_ID: return "ROOT";
4025 case UNDEFINED_ITEM_ID: return "UNDEFINED";
4026 case AccessibilityNodeProvider.HOST_VIEW_ID: return "HOST";
4027 default: return "" + item;
4028 }
4029 }
4030
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07004031 /**
Kristian Monsen74bc1942014-04-29 11:00:17 -07004032 * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
4033 * Each action has a unique id that is mandatory and optional data.
4034 * <p>
4035 * There are three categories of actions:
4036 * <ul>
4037 * <li><strong>Standard actions</strong> - These are actions that are reported and
4038 * handled by the standard UI widgets in the platform. For each standard action
4039 * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}.
Phil Weaver426361c2017-02-22 13:06:25 -08004040 * These actions will have {@code null} labels.
Kristian Monsen74bc1942014-04-29 11:00:17 -07004041 * </li>
4042 * <li><strong>Custom actions action</strong> - These are actions that are reported
4043 * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For
4044 * example, an application may define a custom action for clearing the user history.
4045 * </li>
4046 * <li><strong>Overriden standard actions</strong> - These are actions that override
4047 * standard actions to customize them. For example, an app may add a label to the
Qasid Ahmad Sadiq63eaa472018-07-24 20:14:18 -07004048 * standard {@link #ACTION_CLICK} action to indicate to the user that this action clears
4049 * browsing history.
Kristian Monsen74bc1942014-04-29 11:00:17 -07004050 * </ul>
4051 * </p>
Casey Burkhardt7ef48be2016-01-31 11:51:09 -08004052 * <p>
4053 * Actions are typically added to an {@link AccessibilityNodeInfo} by using
4054 * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within
4055 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed
4056 * within {@link View#performAccessibilityAction(int, Bundle)}.
4057 * </p>
4058 * <p class="note">
4059 * <strong>Note:</strong> Views which support these actions should invoke
4060 * {@link View#setImportantForAccessibility(int)} with
4061 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService}
4062 * can discover the set of supported actions.
4063 * </p>
Kristian Monsen74bc1942014-04-29 11:00:17 -07004064 */
4065 public static final class AccessibilityAction {
4066
Eugene Susla554edd32017-05-24 16:49:59 -07004067 /** @hide */
4068 public static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
4069
Kristian Monsen74bc1942014-04-29 11:00:17 -07004070 /**
4071 * Action that gives input focus to the node.
4072 */
4073 public static final AccessibilityAction ACTION_FOCUS =
Eugene Susla554edd32017-05-24 16:49:59 -07004074 new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004075
4076 /**
4077 * Action that clears input focus of the node.
4078 */
4079 public static final AccessibilityAction ACTION_CLEAR_FOCUS =
Eugene Susla554edd32017-05-24 16:49:59 -07004080 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004081
4082 /**
4083 * Action that selects the node.
4084 */
4085 public static final AccessibilityAction ACTION_SELECT =
Eugene Susla554edd32017-05-24 16:49:59 -07004086 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SELECT);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004087
4088 /**
4089 * Action that deselects the node.
4090 */
4091 public static final AccessibilityAction ACTION_CLEAR_SELECTION =
Eugene Susla554edd32017-05-24 16:49:59 -07004092 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004093
4094 /**
4095 * Action that clicks on the node info.
4096 */
4097 public static final AccessibilityAction ACTION_CLICK =
Eugene Susla554edd32017-05-24 16:49:59 -07004098 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004099
4100 /**
4101 * Action that long clicks on the node.
4102 */
4103 public static final AccessibilityAction ACTION_LONG_CLICK =
Eugene Susla554edd32017-05-24 16:49:59 -07004104 new AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004105
4106 /**
4107 * Action that gives accessibility focus to the node.
4108 */
4109 public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
Eugene Susla554edd32017-05-24 16:49:59 -07004110 new AccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004111
4112 /**
4113 * Action that clears accessibility focus of the node.
4114 */
4115 public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
Eugene Susla554edd32017-05-24 16:49:59 -07004116 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004117
4118 /**
4119 * Action that requests to go to the next entity in this node's text
4120 * at a given movement granularity. For example, move to the next character,
4121 * word, etc.
4122 * <p>
4123 * <strong>Arguments:</strong>
4124 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4125 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
4126 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4127 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
4128 * <strong>Example:</strong> Move to the previous character and do not extend selection.
4129 * <code><pre><p>
4130 * Bundle arguments = new Bundle();
4131 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
4132 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
4133 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
4134 * false);
4135 * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
4136 * arguments);
4137 * </code></pre></p>
4138 * </p>
4139 *
4140 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4141 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4142 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4143 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4144 *
4145 * @see AccessibilityNodeInfo#setMovementGranularities(int)
4146 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4147 * @see AccessibilityNodeInfo#getMovementGranularities()
4148 * AccessibilityNodeInfo.getMovementGranularities()
4149 *
4150 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
4151 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
4152 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
4153 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
4154 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
4155 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
4156 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
4157 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
4158 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
4159 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
4160 */
4161 public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
Eugene Susla554edd32017-05-24 16:49:59 -07004162 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004163
4164 /**
4165 * Action that requests to go to the previous entity in this node's text
4166 * at a given movement granularity. For example, move to the next character,
4167 * word, etc.
4168 * <p>
4169 * <strong>Arguments:</strong>
4170 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4171 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
4172 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4173 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
4174 * <strong>Example:</strong> Move to the next character and do not extend selection.
4175 * <code><pre><p>
4176 * Bundle arguments = new Bundle();
4177 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
4178 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
4179 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
4180 * false);
4181 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
4182 * arguments);
4183 * </code></pre></p>
4184 * </p>
4185 *
4186 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4187 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
4188 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4189 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
4190 *
4191 * @see AccessibilityNodeInfo#setMovementGranularities(int)
4192 * AccessibilityNodeInfo.setMovementGranularities(int)
4193 * @see AccessibilityNodeInfo#getMovementGranularities()
4194 * AccessibilityNodeInfo.getMovementGranularities()
4195 *
4196 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER
4197 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
4198 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD
4199 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
4200 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE
4201 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE
4202 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH
4203 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
4204 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE
4205 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
4206 */
4207 public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
4208 new AccessibilityAction(
Eugene Susla554edd32017-05-24 16:49:59 -07004209 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004210
4211 /**
4212 * Action to move to the next HTML element of a given type. For example, move
4213 * to the BUTTON, INPUT, TABLE, etc.
4214 * <p>
4215 * <strong>Arguments:</strong>
4216 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
4217 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
4218 * <strong>Example:</strong>
4219 * <code><pre><p>
4220 * Bundle arguments = new Bundle();
4221 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
4222 * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
4223 * </code></pre></p>
4224 * </p>
4225 */
4226 public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
Eugene Susla554edd32017-05-24 16:49:59 -07004227 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004228
4229 /**
4230 * Action to move to the previous HTML element of a given type. For example, move
4231 * to the BUTTON, INPUT, TABLE, etc.
4232 * <p>
4233 * <strong>Arguments:</strong>
4234 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING
4235 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
4236 * <strong>Example:</strong>
4237 * <code><pre><p>
4238 * Bundle arguments = new Bundle();
4239 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
4240 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
4241 * </code></pre></p>
4242 * </p>
4243 */
4244 public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
Eugene Susla554edd32017-05-24 16:49:59 -07004245 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004246
4247 /**
4248 * Action to scroll the node content forward.
4249 */
4250 public static final AccessibilityAction ACTION_SCROLL_FORWARD =
Eugene Susla554edd32017-05-24 16:49:59 -07004251 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004252
4253 /**
4254 * Action to scroll the node content backward.
4255 */
4256 public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
Eugene Susla554edd32017-05-24 16:49:59 -07004257 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004258
4259 /**
4260 * Action to copy the current selection to the clipboard.
4261 */
4262 public static final AccessibilityAction ACTION_COPY =
Eugene Susla554edd32017-05-24 16:49:59 -07004263 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COPY);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004264
4265 /**
4266 * Action to paste the current clipboard content.
4267 */
4268 public static final AccessibilityAction ACTION_PASTE =
Eugene Susla554edd32017-05-24 16:49:59 -07004269 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PASTE);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004270
4271 /**
4272 * Action to cut the current selection and place it to the clipboard.
4273 */
4274 public static final AccessibilityAction ACTION_CUT =
Eugene Susla554edd32017-05-24 16:49:59 -07004275 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CUT);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004276
4277 /**
4278 * Action to set the selection. Performing this action with no arguments
4279 * clears the selection.
4280 * <p>
4281 * <strong>Arguments:</strong>
4282 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
4283 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT},
4284 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
4285 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br>
4286 * <strong>Example:</strong>
4287 * <code><pre><p>
4288 * Bundle arguments = new Bundle();
4289 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
4290 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
4291 * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments);
4292 * </code></pre></p>
4293 * </p>
4294 *
4295 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT
4296 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT
4297 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT
4298 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
4299 */
4300 public static final AccessibilityAction ACTION_SET_SELECTION =
Eugene Susla554edd32017-05-24 16:49:59 -07004301 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004302
4303 /**
4304 * Action to expand an expandable node.
4305 */
4306 public static final AccessibilityAction ACTION_EXPAND =
Eugene Susla554edd32017-05-24 16:49:59 -07004307 new AccessibilityAction(AccessibilityNodeInfo.ACTION_EXPAND);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004308
4309 /**
4310 * Action to collapse an expandable node.
4311 */
4312 public static final AccessibilityAction ACTION_COLLAPSE =
Eugene Susla554edd32017-05-24 16:49:59 -07004313 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004314
4315 /**
4316 * Action to dismiss a dismissable node.
4317 */
4318 public static final AccessibilityAction ACTION_DISMISS =
Eugene Susla554edd32017-05-24 16:49:59 -07004319 new AccessibilityAction(AccessibilityNodeInfo.ACTION_DISMISS);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004320
4321 /**
4322 * Action that sets the text of the node. Performing the action without argument,
4323 * using <code> null</code> or empty {@link CharSequence} will clear the text. This
4324 * action will also put the cursor at the end of text.
4325 * <p>
4326 * <strong>Arguments:</strong>
4327 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
4328 * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
4329 * <strong>Example:</strong>
4330 * <code><pre><p>
4331 * Bundle arguments = new Bundle();
4332 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
4333 * "android");
4334 * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments);
4335 * </code></pre></p>
4336 */
4337 public static final AccessibilityAction ACTION_SET_TEXT =
Eugene Susla554edd32017-05-24 16:49:59 -07004338 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004339
Alan Viverette26c44ee2015-03-25 14:54:13 -07004340 /**
4341 * Action that requests the node make its bounding rectangle visible
4342 * on the screen, scrolling if necessary just enough.
4343 *
4344 * @see View#requestRectangleOnScreen(Rect)
4345 */
4346 public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
Eugene Susla554edd32017-05-24 16:49:59 -07004347 new AccessibilityAction(R.id.accessibilityActionShowOnScreen);
Alan Viverette26c44ee2015-03-25 14:54:13 -07004348
Alan Viverette23f44322015-04-06 16:04:56 -07004349 /**
4350 * Action that scrolls the node to make the specified collection
4351 * position visible on screen.
4352 * <p>
4353 * <strong>Arguments:</strong>
4354 * <ul>
4355 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
4356 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
4357 * <ul>
4358 *
4359 * @see AccessibilityNodeInfo#getCollectionInfo()
4360 */
4361 public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
Eugene Susla554edd32017-05-24 16:49:59 -07004362 new AccessibilityAction(R.id.accessibilityActionScrollToPosition);
Alan Viverette23f44322015-04-06 16:04:56 -07004363
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004364 /**
4365 * Action to scroll the node content up.
4366 */
4367 public static final AccessibilityAction ACTION_SCROLL_UP =
Eugene Susla554edd32017-05-24 16:49:59 -07004368 new AccessibilityAction(R.id.accessibilityActionScrollUp);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004369
4370 /**
4371 * Action to scroll the node content left.
4372 */
4373 public static final AccessibilityAction ACTION_SCROLL_LEFT =
Eugene Susla554edd32017-05-24 16:49:59 -07004374 new AccessibilityAction(R.id.accessibilityActionScrollLeft);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004375
4376 /**
4377 * Action to scroll the node content down.
4378 */
4379 public static final AccessibilityAction ACTION_SCROLL_DOWN =
Eugene Susla554edd32017-05-24 16:49:59 -07004380 new AccessibilityAction(R.id.accessibilityActionScrollDown);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004381
4382 /**
4383 * Action to scroll the node content right.
4384 */
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004385 public static final AccessibilityAction ACTION_SCROLL_RIGHT =
Eugene Susla554edd32017-05-24 16:49:59 -07004386 new AccessibilityAction(R.id.accessibilityActionScrollRight);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004387
Mady Mellord2744002015-04-30 16:17:16 -07004388 /**
Qasid Ahmad Sadiq95705612018-11-09 21:11:01 -08004389 * Action to move to the page above.
4390 */
4391 public static final AccessibilityAction ACTION_PAGE_UP =
4392 new AccessibilityAction(R.id.accessibilityActionPageUp);
4393
4394 /**
4395 * Action to move to the page below.
4396 */
4397 public static final AccessibilityAction ACTION_PAGE_DOWN =
4398 new AccessibilityAction(R.id.accessibilityActionPageDown);
4399
4400 /**
4401 * Action to move to the page left.
4402 */
4403 public static final AccessibilityAction ACTION_PAGE_LEFT =
4404 new AccessibilityAction(R.id.accessibilityActionPageLeft);
4405
4406 /**
4407 * Action to move to the page right.
4408 */
4409 public static final AccessibilityAction ACTION_PAGE_RIGHT =
4410 new AccessibilityAction(R.id.accessibilityActionPageRight);
4411
4412 /**
Mady Mellore8608912015-06-05 09:02:55 -07004413 * Action that context clicks the node.
Mady Mellore82067b2015-04-30 09:58:35 -07004414 */
Mady Mellore8608912015-06-05 09:02:55 -07004415 public static final AccessibilityAction ACTION_CONTEXT_CLICK =
Eugene Susla554edd32017-05-24 16:49:59 -07004416 new AccessibilityAction(R.id.accessibilityActionContextClick);
Maxim Bogatovac6ffce2015-04-27 13:45:52 -07004417
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004418 /**
4419 * Action that sets progress between {@link RangeInfo#getMin() RangeInfo.getMin()} and
4420 * {@link RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as
4421 * {@link RangeInfo#getType() RangeInfo.getType()}
4422 * <p>
4423 * <strong>Arguments:</strong>
4424 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE}
4425 *
4426 * @see RangeInfo
4427 */
4428 public static final AccessibilityAction ACTION_SET_PROGRESS =
Eugene Susla554edd32017-05-24 16:49:59 -07004429 new AccessibilityAction(R.id.accessibilityActionSetProgress);
Maxim Bogatov32e59d52015-04-30 16:57:33 -07004430
Phil Weaverf00cd142017-03-03 13:44:00 -08004431 /**
4432 * Action to move a window to a new location.
4433 * <p>
4434 * <strong>Arguments:</strong>
4435 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X}
4436 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y}
4437 */
4438 public static final AccessibilityAction ACTION_MOVE_WINDOW =
Eugene Susla554edd32017-05-24 16:49:59 -07004439 new AccessibilityAction(R.id.accessibilityActionMoveWindow);
Kristian Monsen74bc1942014-04-29 11:00:17 -07004440
Phil Weaverd89905f2018-01-10 08:28:04 -08004441 /**
4442 * Action to show a tooltip. A node should expose this action only for views with tooltip
4443 * text that but are not currently showing a tooltip.
4444 */
4445 public static final AccessibilityAction ACTION_SHOW_TOOLTIP =
4446 new AccessibilityAction(R.id.accessibilityActionShowTooltip);
4447
4448 /**
4449 * Action to hide a tooltip. A node should expose this action only for views that are
4450 * currently showing a tooltip.
4451 */
4452 public static final AccessibilityAction ACTION_HIDE_TOOLTIP =
4453 new AccessibilityAction(R.id.accessibilityActionHideTooltip);
4454
Kristian Monsen74bc1942014-04-29 11:00:17 -07004455 private final int mActionId;
4456 private final CharSequence mLabel;
4457
Eugene Susla554edd32017-05-24 16:49:59 -07004458 /** @hide */
Phil Weaver2c9e7802018-03-05 15:22:32 -08004459 public long mSerializationFlag = -1L;
Eugene Susla554edd32017-05-24 16:49:59 -07004460
Kristian Monsen74bc1942014-04-29 11:00:17 -07004461 /**
4462 * Creates a new AccessibilityAction. For adding a standard action without a specific label,
4463 * use the static constants.
4464 *
4465 * You can also override the description for one the standard actions. Below is an example
4466 * how to override the standard click action by adding a custom label:
4467 * <pre>
4468 * AccessibilityAction action = new AccessibilityAction(
Phil Weaverc3791292016-09-12 11:06:49 -07004469 * AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel());
Kristian Monsen74bc1942014-04-29 11:00:17 -07004470 * node.addAction(action);
4471 * </pre>
4472 *
4473 * @param actionId The id for this action. This should either be one of the
4474 * standard actions or a specific action for your app. In that case it is
4475 * required to use a resource identifier.
4476 * @param label The label for the new AccessibilityAction.
4477 */
4478 public AccessibilityAction(int actionId, @Nullable CharSequence label) {
Svetoslav5c4cd182014-05-21 14:53:16 -07004479 if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
Kristian Monsen74bc1942014-04-29 11:00:17 -07004480 throw new IllegalArgumentException("Invalid standard action id");
4481 }
4482
Kristian Monsen74bc1942014-04-29 11:00:17 -07004483 mActionId = actionId;
4484 mLabel = label;
4485 }
4486
4487 /**
Eugene Susla554edd32017-05-24 16:49:59 -07004488 * Constructor for a {@link #sStandardActions standard} action
4489 */
4490 private AccessibilityAction(int standardActionId) {
4491 this(standardActionId, null);
4492
Phil Weaver2c9e7802018-03-05 15:22:32 -08004493 mSerializationFlag = bitAt(sStandardActions.size());
Eugene Susla554edd32017-05-24 16:49:59 -07004494 sStandardActions.add(this);
4495 }
4496
4497 /**
Kristian Monsen74bc1942014-04-29 11:00:17 -07004498 * Gets the id for this action.
4499 *
4500 * @return The action id.
4501 */
4502 public int getId() {
4503 return mActionId;
4504 }
4505
4506 /**
4507 * Gets the label for this action. Its purpose is to describe the
4508 * action to user.
4509 *
4510 * @return The label.
4511 */
4512 public CharSequence getLabel() {
4513 return mLabel;
4514 }
4515
4516 @Override
4517 public int hashCode() {
4518 return mActionId;
4519 }
4520
4521 @Override
4522 public boolean equals(Object other) {
4523 if (other == null) {
4524 return false;
4525 }
4526
4527 if (other == this) {
4528 return true;
4529 }
4530
4531 if (getClass() != other.getClass()) {
4532 return false;
4533 }
4534
4535 return mActionId == ((AccessibilityAction)other).mActionId;
4536 }
4537
4538 @Override
4539 public String toString() {
4540 return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel;
4541 }
4542 }
4543
4544 /**
Svetoslav3577a282013-06-06 14:09:10 -07004545 * Class with information if a node is a range. Use
Phil Weaver764152b2016-07-19 11:32:27 -07004546 * {@link RangeInfo#obtain(int, float, float, float)} to get an instance. Recycling is
4547 * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
Svetoslav3577a282013-06-06 14:09:10 -07004548 */
4549 public static final class RangeInfo {
4550 private static final int MAX_POOL_SIZE = 10;
4551
4552 /** Range type: integer. */
4553 public static final int RANGE_TYPE_INT = 0;
4554 /** Range type: float. */
4555 public static final int RANGE_TYPE_FLOAT = 1;
4556 /** Range type: percent with values from zero to one.*/
4557 public static final int RANGE_TYPE_PERCENT = 2;
4558
4559 private static final SynchronizedPool<RangeInfo> sPool =
4560 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
4561
4562 private int mType;
4563 private float mMin;
4564 private float mMax;
4565 private float mCurrent;
4566
4567 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004568 * Obtains a pooled instance that is a clone of another one.
4569 *
4570 * @param other The instance to clone.
4571 *
4572 * @hide
4573 */
4574 public static RangeInfo obtain(RangeInfo other) {
4575 return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
4576 }
4577
4578 /**
Svetoslav3577a282013-06-06 14:09:10 -07004579 * Obtains a pooled instance.
4580 *
4581 * @param type The type of the range.
Phil Weaver79e44192016-12-19 14:24:49 -08004582 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
4583 * minimum.
4584 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
4585 * maximum.
Svetoslav3577a282013-06-06 14:09:10 -07004586 * @param current The current value.
4587 */
4588 public static RangeInfo obtain(int type, float min, float max, float current) {
4589 RangeInfo info = sPool.acquire();
Steven Dao24142812016-04-13 15:25:09 -07004590 if (info == null) {
4591 return new RangeInfo(type, min, max, current);
4592 }
4593
4594 info.mType = type;
4595 info.mMin = min;
4596 info.mMax = max;
4597 info.mCurrent = current;
4598 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004599 }
4600
4601 /**
4602 * Creates a new range.
4603 *
4604 * @param type The type of the range.
Phil Weaver79e44192016-12-19 14:24:49 -08004605 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
4606 * minimum.
4607 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no
4608 * maximum.
Svetoslav3577a282013-06-06 14:09:10 -07004609 * @param current The current value.
4610 */
4611 private RangeInfo(int type, float min, float max, float current) {
4612 mType = type;
4613 mMin = min;
4614 mMax = max;
4615 mCurrent = current;
4616 }
4617
4618 /**
4619 * Gets the range type.
4620 *
4621 * @return The range type.
4622 *
4623 * @see #RANGE_TYPE_INT
4624 * @see #RANGE_TYPE_FLOAT
4625 * @see #RANGE_TYPE_PERCENT
4626 */
4627 public int getType() {
4628 return mType;
4629 }
4630
4631 /**
Phil Weaver79e44192016-12-19 14:24:49 -08004632 * Gets the minimum value.
Svetoslav3577a282013-06-06 14:09:10 -07004633 *
Phil Weaver79e44192016-12-19 14:24:49 -08004634 * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists.
Svetoslav3577a282013-06-06 14:09:10 -07004635 */
4636 public float getMin() {
4637 return mMin;
4638 }
4639
4640 /**
Phil Weaver79e44192016-12-19 14:24:49 -08004641 * Gets the maximum value.
Svetoslav3577a282013-06-06 14:09:10 -07004642 *
Phil Weaver79e44192016-12-19 14:24:49 -08004643 * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists.
Svetoslav3577a282013-06-06 14:09:10 -07004644 */
4645 public float getMax() {
4646 return mMax;
4647 }
4648
4649 /**
4650 * Gets the current value.
4651 *
4652 * @return The current value.
4653 */
4654 public float getCurrent() {
4655 return mCurrent;
4656 }
4657
4658 /**
4659 * Recycles this instance.
4660 */
4661 void recycle() {
4662 clear();
4663 sPool.release(this);
4664 }
4665
4666 private void clear() {
4667 mType = 0;
4668 mMin = 0;
4669 mMax = 0;
4670 mCurrent = 0;
4671 }
4672 }
4673
4674 /**
4675 * Class with information if a node is a collection. Use
Phil Weaver764152b2016-07-19 11:32:27 -07004676 * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance. Recycling is
4677 * handled by the {@link AccessibilityNodeInfo} to which this object is attached.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004678 * <p>
4679 * A collection of items has rows and columns and may be hierarchical.
4680 * For example, a horizontal list is a collection with one column, as
4681 * many rows as the list items, and is not hierarchical; A table is a
4682 * collection with several rows, several columns, and is not hierarchical;
4683 * A vertical tree is a hierarchical collection with one column and
4684 * as many rows as the first level children.
4685 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07004686 */
4687 public static final class CollectionInfo {
Alan Viverette76769ae2014-02-12 16:38:10 -08004688 /** Selection mode where items are not selectable. */
4689 public static final int SELECTION_MODE_NONE = 0;
4690
4691 /** Selection mode where a single item may be selected. */
4692 public static final int SELECTION_MODE_SINGLE = 1;
4693
4694 /** Selection mode where multiple items may be selected. */
4695 public static final int SELECTION_MODE_MULTIPLE = 2;
4696
Svetoslav3577a282013-06-06 14:09:10 -07004697 private static final int MAX_POOL_SIZE = 20;
4698
4699 private static final SynchronizedPool<CollectionInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -07004700 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav3577a282013-06-06 14:09:10 -07004701
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004702 private int mRowCount;
4703 private int mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004704 private boolean mHierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004705 private int mSelectionMode;
Svetoslav3577a282013-06-06 14:09:10 -07004706
4707 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004708 * Obtains a pooled instance that is a clone of another one.
4709 *
4710 * @param other The instance to clone.
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004711 * @hide
4712 */
4713 public static CollectionInfo obtain(CollectionInfo other) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004714 return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
4715 other.mSelectionMode);
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004716 }
4717
4718 /**
Svetoslav3577a282013-06-06 14:09:10 -07004719 * Obtains a pooled instance.
4720 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004721 * @param rowCount The number of rows.
4722 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004723 * @param hierarchical Whether the collection is hierarchical.
4724 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004725 public static CollectionInfo obtain(int rowCount, int columnCount,
4726 boolean hierarchical) {
4727 return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
4728 }
4729
4730 /**
4731 * Obtains a pooled instance.
4732 *
4733 * @param rowCount The number of rows.
4734 * @param columnCount The number of columns.
4735 * @param hierarchical Whether the collection is hierarchical.
4736 * @param selectionMode The collection's selection mode, one of:
4737 * <ul>
4738 * <li>{@link #SELECTION_MODE_NONE}
4739 * <li>{@link #SELECTION_MODE_SINGLE}
4740 * <li>{@link #SELECTION_MODE_MULTIPLE}
4741 * </ul>
4742 */
4743 public static CollectionInfo obtain(int rowCount, int columnCount,
4744 boolean hierarchical, int selectionMode) {
4745 final CollectionInfo info = sPool.acquire();
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004746 if (info == null) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004747 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004748 }
4749
4750 info.mRowCount = rowCount;
4751 info.mColumnCount = columnCount;
4752 info.mHierarchical = hierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004753 info.mSelectionMode = selectionMode;
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004754 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004755 }
4756
4757 /**
4758 * Creates a new instance.
4759 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004760 * @param rowCount The number of rows.
4761 * @param columnCount The number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004762 * @param hierarchical Whether the collection is hierarchical.
Alan Viverette76769ae2014-02-12 16:38:10 -08004763 * @param selectionMode The collection's selection mode.
Svetoslav3577a282013-06-06 14:09:10 -07004764 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004765 private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
4766 int selectionMode) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004767 mRowCount = rowCount;
4768 mColumnCount = columnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004769 mHierarchical = hierarchical;
Alan Viverette76769ae2014-02-12 16:38:10 -08004770 mSelectionMode = selectionMode;
Svetoslav3577a282013-06-06 14:09:10 -07004771 }
4772
4773 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004774 * Gets the number of rows.
Svetoslav3577a282013-06-06 14:09:10 -07004775 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004776 * @return The row count.
Svetoslav3577a282013-06-06 14:09:10 -07004777 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004778 public int getRowCount() {
4779 return mRowCount;
Svetoslav3577a282013-06-06 14:09:10 -07004780 }
4781
4782 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004783 * Gets the number of columns.
Svetoslav3577a282013-06-06 14:09:10 -07004784 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004785 * @return The column count.
Svetoslav3577a282013-06-06 14:09:10 -07004786 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004787 public int getColumnCount() {
4788 return mColumnCount;
Svetoslav3577a282013-06-06 14:09:10 -07004789 }
4790
4791 /**
4792 * Gets if the collection is a hierarchically ordered.
4793 *
4794 * @return Whether the collection is hierarchical.
4795 */
4796 public boolean isHierarchical() {
4797 return mHierarchical;
4798 }
4799
4800 /**
Alan Viverette76769ae2014-02-12 16:38:10 -08004801 * Gets the collection's selection mode.
4802 *
4803 * @return The collection's selection mode, one of:
4804 * <ul>
4805 * <li>{@link #SELECTION_MODE_NONE}
4806 * <li>{@link #SELECTION_MODE_SINGLE}
4807 * <li>{@link #SELECTION_MODE_MULTIPLE}
4808 * </ul>
4809 */
4810 public int getSelectionMode() {
4811 return mSelectionMode;
4812 }
4813
4814 /**
Svetoslav3577a282013-06-06 14:09:10 -07004815 * Recycles this instance.
4816 */
4817 void recycle() {
4818 clear();
4819 sPool.release(this);
4820 }
4821
4822 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004823 mRowCount = 0;
4824 mColumnCount = 0;
Svetoslav3577a282013-06-06 14:09:10 -07004825 mHierarchical = false;
Alan Viverette76769ae2014-02-12 16:38:10 -08004826 mSelectionMode = SELECTION_MODE_NONE;
Svetoslav3577a282013-06-06 14:09:10 -07004827 }
4828 }
4829
4830 /**
4831 * Class with information if a node is a collection item. Use
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004832 * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)}
Phil Weaver764152b2016-07-19 11:32:27 -07004833 * to get an instance. Recycling is handled by the {@link AccessibilityNodeInfo} to which this
4834 * object is attached.
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004835 * <p>
4836 * A collection item is contained in a collection, it starts at
4837 * a given row and column in the collection, and spans one or
4838 * more rows and columns. For example, a header of two related
4839 * table columns starts at the first row and the first column,
4840 * spans one row and two columns.
4841 * </p>
Svetoslav3577a282013-06-06 14:09:10 -07004842 */
4843 public static final class CollectionItemInfo {
4844 private static final int MAX_POOL_SIZE = 20;
4845
4846 private static final SynchronizedPool<CollectionItemInfo> sPool =
Alan Viverette23f44322015-04-06 16:04:56 -07004847 new SynchronizedPool<>(MAX_POOL_SIZE);
Svetoslav3577a282013-06-06 14:09:10 -07004848
4849 /**
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004850 * Obtains a pooled instance that is a clone of another one.
4851 *
4852 * @param other The instance to clone.
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004853 * @hide
4854 */
4855 public static CollectionItemInfo obtain(CollectionItemInfo other) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004856 return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
4857 other.mColumnSpan, other.mHeading, other.mSelected);
Svetoslav Ganov6685f1b2013-09-09 13:36:43 -07004858 }
4859
4860 /**
Svetoslav3577a282013-06-06 14:09:10 -07004861 * Obtains a pooled instance.
4862 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004863 * @param rowIndex The row index at which the item is located.
4864 * @param rowSpan The number of rows the item spans.
4865 * @param columnIndex The column index at which the item is located.
4866 * @param columnSpan The number of columns the item spans.
Phil Weaver6290fb592018-01-08 17:42:18 -08004867 * @param heading Whether the item is a heading. (Prefer
4868 * {@link AccessibilityNodeInfo#setHeading(boolean)}).
Svetoslav3577a282013-06-06 14:09:10 -07004869 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004870 public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4871 int columnIndex, int columnSpan, boolean heading) {
4872 return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
4873 }
4874
4875 /**
4876 * Obtains a pooled instance.
4877 *
4878 * @param rowIndex The row index at which the item is located.
4879 * @param rowSpan The number of rows the item spans.
4880 * @param columnIndex The column index at which the item is located.
4881 * @param columnSpan The number of columns the item spans.
Phil Weaver6290fb592018-01-08 17:42:18 -08004882 * @param heading Whether the item is a heading. (Prefer
4883 * {@link AccessibilityNodeInfo#setHeading(boolean)})
Alan Viverette76769ae2014-02-12 16:38:10 -08004884 * @param selected Whether the item is selected.
4885 */
4886 public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
4887 int columnIndex, int columnSpan, boolean heading, boolean selected) {
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004888 final CollectionItemInfo info = sPool.acquire();
4889 if (info == null) {
Alan Viverette76769ae2014-02-12 16:38:10 -08004890 return new CollectionItemInfo(
4891 rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004892 }
4893
4894 info.mRowIndex = rowIndex;
4895 info.mRowSpan = rowSpan;
4896 info.mColumnIndex = columnIndex;
4897 info.mColumnSpan = columnSpan;
4898 info.mHeading = heading;
Alan Viverette76769ae2014-02-12 16:38:10 -08004899 info.mSelected = selected;
Alan Viverettecdd2edd2014-02-12 11:28:33 -08004900 return info;
Svetoslav3577a282013-06-06 14:09:10 -07004901 }
4902
4903 private boolean mHeading;
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004904 private int mColumnIndex;
4905 private int mRowIndex;
4906 private int mColumnSpan;
4907 private int mRowSpan;
Alan Viverette76769ae2014-02-12 16:38:10 -08004908 private boolean mSelected;
Svetoslav3577a282013-06-06 14:09:10 -07004909
4910 /**
4911 * Creates a new instance.
4912 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004913 * @param rowIndex The row index at which the item is located.
4914 * @param rowSpan The number of rows the item spans.
4915 * @param columnIndex The column index at which the item is located.
4916 * @param columnSpan The number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004917 * @param heading Whether the item is a heading.
4918 */
Alan Viverette76769ae2014-02-12 16:38:10 -08004919 private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
4920 boolean heading, boolean selected) {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004921 mRowIndex = rowIndex;
4922 mRowSpan = rowSpan;
4923 mColumnIndex = columnIndex;
4924 mColumnSpan = columnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004925 mHeading = heading;
Alan Viverette76769ae2014-02-12 16:38:10 -08004926 mSelected = selected;
Svetoslav3577a282013-06-06 14:09:10 -07004927 }
4928
4929 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004930 * Gets the column index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07004931 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004932 * @return The column index.
Svetoslav3577a282013-06-06 14:09:10 -07004933 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004934 public int getColumnIndex() {
4935 return mColumnIndex;
Svetoslav3577a282013-06-06 14:09:10 -07004936 }
4937
4938 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004939 * Gets the row index at which the item is located.
Svetoslav3577a282013-06-06 14:09:10 -07004940 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004941 * @return The row index.
Svetoslav3577a282013-06-06 14:09:10 -07004942 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004943 public int getRowIndex() {
4944 return mRowIndex;
Svetoslav3577a282013-06-06 14:09:10 -07004945 }
4946
4947 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004948 * Gets the number of columns the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004949 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004950 * @return The column span.
Svetoslav3577a282013-06-06 14:09:10 -07004951 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004952 public int getColumnSpan() {
4953 return mColumnSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004954 }
4955
4956 /**
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004957 * Gets the number of rows the item spans.
Svetoslav3577a282013-06-06 14:09:10 -07004958 *
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004959 * @return The row span.
Svetoslav3577a282013-06-06 14:09:10 -07004960 */
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004961 public int getRowSpan() {
4962 return mRowSpan;
Svetoslav3577a282013-06-06 14:09:10 -07004963 }
4964
4965 /**
4966 * Gets if the collection item is a heading. For example, section
4967 * heading, table header, etc.
4968 *
4969 * @return If the item is a heading.
Phil Weaver6290fb592018-01-08 17:42:18 -08004970 * @deprecated Use {@link AccessibilityNodeInfo#isHeading()}
Svetoslav3577a282013-06-06 14:09:10 -07004971 */
4972 public boolean isHeading() {
4973 return mHeading;
4974 }
4975
4976 /**
Alan Viverette76769ae2014-02-12 16:38:10 -08004977 * Gets if the collection item is selected.
4978 *
4979 * @return If the item is selected.
4980 */
4981 public boolean isSelected() {
4982 return mSelected;
4983 }
4984
4985 /**
Svetoslav3577a282013-06-06 14:09:10 -07004986 * Recycles this instance.
4987 */
4988 void recycle() {
4989 clear();
4990 sPool.release(this);
4991 }
4992
4993 private void clear() {
Svetoslav Ganovcb8ed392013-08-23 20:37:28 -07004994 mColumnIndex = 0;
4995 mColumnSpan = 0;
4996 mRowIndex = 0;
4997 mRowSpan = 0;
Svetoslav3577a282013-06-06 14:09:10 -07004998 mHeading = false;
Alan Viverette76769ae2014-02-12 16:38:10 -08004999 mSelected = false;
Svetoslav3577a282013-06-06 14:09:10 -07005000 }
5001 }
5002
5003 /**
Rhed Jaoae638752018-09-18 19:40:13 +08005004 * Class with information of touch delegated views and regions from {@link TouchDelegate} for
5005 * the {@link AccessibilityNodeInfo}.
5006 *
5007 * @see AccessibilityNodeInfo#setTouchDelegateInfo(TouchDelegateInfo)
5008 */
5009 public static final class TouchDelegateInfo implements Parcelable {
5010 private ArrayMap<Region, Long> mTargetMap;
5011 // Two ids are initialized lazily in AccessibilityNodeInfo#getTouchDelegateInfo
5012 private int mConnectionId;
5013 private int mWindowId;
5014
5015 /**
5016 * Create a new instance of {@link TouchDelegateInfo}.
5017 *
5018 * @param targetMap A map from regions (in view coordinates) to delegated views.
5019 * @throws IllegalArgumentException if targetMap is empty or {@code null} in
5020 * Regions or Views.
5021 */
5022 public TouchDelegateInfo(@NonNull Map<Region, View> targetMap) {
5023 Preconditions.checkArgument(!targetMap.isEmpty()
5024 && !targetMap.containsKey(null) && !targetMap.containsValue(null));
5025 mTargetMap = new ArrayMap<>(targetMap.size());
5026 for (final Region region : targetMap.keySet()) {
5027 final View view = targetMap.get(region);
5028 mTargetMap.put(region, (long) view.getAccessibilityViewId());
5029 }
5030 }
5031
5032 /**
5033 * Create a new instance from target map.
5034 *
5035 * @param targetMap A map from regions (in view coordinates) to delegated views'
5036 * accessibility id.
5037 * @param doCopy True if shallow copy targetMap.
5038 * @throws IllegalArgumentException if targetMap is empty or {@code null} in
5039 * Regions or Views.
5040 */
5041 TouchDelegateInfo(@NonNull ArrayMap<Region, Long> targetMap, boolean doCopy) {
5042 Preconditions.checkArgument(!targetMap.isEmpty()
5043 && !targetMap.containsKey(null) && !targetMap.containsValue(null));
5044 if (doCopy) {
5045 mTargetMap = new ArrayMap<>(targetMap.size());
5046 mTargetMap.putAll(targetMap);
5047 } else {
5048 mTargetMap = targetMap;
5049 }
5050 }
5051
5052 /**
5053 * Set the connection ID.
5054 *
5055 * @param connectionId The connection id.
5056 */
5057 private void setConnectionId(int connectionId) {
5058 mConnectionId = connectionId;
5059 }
5060
5061 /**
5062 * Set the window ID.
5063 *
5064 * @param windowId The window id.
5065 */
5066 private void setWindowId(int windowId) {
5067 mWindowId = windowId;
5068 }
5069
5070 /**
5071 * Returns the number of touch delegate target region.
5072 *
5073 * @return Number of touch delegate target region.
5074 */
5075 public int getRegionCount() {
5076 return mTargetMap.size();
5077 }
5078
5079 /**
5080 * Return the {@link Region} at the given index in the {@link TouchDelegateInfo}.
5081 *
5082 * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1.
5083 * @return Returns the {@link Region} stored at the given index.
5084 */
5085 @NonNull
5086 public Region getRegionAt(int index) {
5087 return mTargetMap.keyAt(index);
5088 }
5089
5090 /**
5091 * Return the target {@link AccessibilityNodeInfo} for the given {@link Region}.
5092 * <p>
5093 * <strong>Note:</strong> This api can only be called from {@link AccessibilityService}.
5094 * </p>
5095 * <p>
5096 * <strong>Note:</strong> It is a client responsibility to recycle the
5097 * received info by calling {@link AccessibilityNodeInfo#recycle()}
5098 * to avoid creating of multiple instances.
5099 * </p>
5100 *
5101 * @param region The region retrieved from {@link #getRegionAt(int)}.
5102 * @return The target node associates with the given region.
5103 */
5104 @Nullable
5105 public AccessibilityNodeInfo getTargetForRegion(@NonNull Region region) {
5106 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTargetMap.get(region));
5107 }
5108
5109 /**
5110 * Return the accessibility id of target node.
5111 *
5112 * @param region The region retrieved from {@link #getRegionAt(int)}.
5113 * @return The accessibility id of target node.
5114 *
5115 * @hide
5116 */
5117 @TestApi
5118 public long getAccessibilityIdForRegion(@NonNull Region region) {
5119 return mTargetMap.get(region);
5120 }
5121
5122 /**
5123 * {@inheritDoc}
5124 */
5125 @Override
5126 public int describeContents() {
5127 return 0;
5128 }
5129
5130 /**
5131 * {@inheritDoc}
5132 */
5133 @Override
5134 public void writeToParcel(Parcel dest, int flags) {
5135 dest.writeInt(mTargetMap.size());
5136 for (int i = 0; i < mTargetMap.size(); i++) {
5137 final Region region = mTargetMap.keyAt(i);
5138 final Long accessibilityId = mTargetMap.valueAt(i);
5139 region.writeToParcel(dest, flags);
5140 dest.writeLong(accessibilityId);
5141 }
5142 }
5143
5144 /**
5145 * @see android.os.Parcelable.Creator
5146 */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07005147 public static final @android.annotation.NonNull Parcelable.Creator<TouchDelegateInfo> CREATOR =
Rhed Jaoae638752018-09-18 19:40:13 +08005148 new Parcelable.Creator<TouchDelegateInfo>() {
5149 @Override
5150 public TouchDelegateInfo createFromParcel(Parcel parcel) {
5151 final int size = parcel.readInt();
5152 if (size == 0) {
5153 return null;
5154 }
5155 final ArrayMap<Region, Long> targetMap = new ArrayMap<>(size);
5156 for (int i = 0; i < size; i++) {
5157 final Region region = Region.CREATOR.createFromParcel(parcel);
5158 final long accessibilityId = parcel.readLong();
5159 targetMap.put(region, accessibilityId);
5160 }
5161 final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo(
5162 targetMap, false);
5163 return touchDelegateInfo;
5164 }
5165
5166 @Override
5167 public TouchDelegateInfo[] newArray(int size) {
5168 return new TouchDelegateInfo[size];
5169 }
5170 };
5171 }
5172
5173 /**
Alan Viverettef0aed092013-11-06 15:33:03 -08005174 * @see android.os.Parcelable.Creator
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005175 */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07005176 public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005177 new Parcelable.Creator<AccessibilityNodeInfo>() {
Alan Viverettef0aed092013-11-06 15:33:03 -08005178 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005179 public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
5180 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
5181 info.initFromParcel(parcel);
5182 return info;
5183 }
5184
Alan Viverettef0aed092013-11-06 15:33:03 -08005185 @Override
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07005186 public AccessibilityNodeInfo[] newArray(int size) {
5187 return new AccessibilityNodeInfo[size];
5188 }
5189 };
5190}