1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view.accessibility; 18 19 import static com.android.internal.util.BitUtils.bitAt; 20 import static com.android.internal.util.BitUtils.isBitSet; 21 22 import static java.util.Collections.EMPTY_LIST; 23 24 import android.accessibilityservice.AccessibilityService; 25 import android.accessibilityservice.AccessibilityServiceInfo; 26 import android.annotation.FlaggedApi; 27 import android.annotation.IntDef; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.SuppressLint; 31 import android.annotation.TestApi; 32 import android.compat.annotation.UnsupportedAppUsage; 33 import android.content.ClipData; 34 import android.graphics.Rect; 35 import android.graphics.Region; 36 import android.os.Build; 37 import android.os.Bundle; 38 import android.os.IBinder; 39 import android.os.Parcel; 40 import android.os.Parcelable; 41 import android.text.InputType; 42 import android.text.Spannable; 43 import android.text.SpannableStringBuilder; 44 import android.text.Spanned; 45 import android.text.TextUtils; 46 import android.text.style.AccessibilityClickableSpan; 47 import android.text.style.AccessibilityReplacementSpan; 48 import android.text.style.AccessibilityURLSpan; 49 import android.text.style.ClickableSpan; 50 import android.text.style.ReplacementSpan; 51 import android.text.style.URLSpan; 52 import android.util.ArrayMap; 53 import android.util.ArraySet; 54 import android.util.Log; 55 import android.util.LongArray; 56 import android.util.Size; 57 import android.util.TypedValue; 58 import android.view.SurfaceView; 59 import android.view.TouchDelegate; 60 import android.view.View; 61 import android.view.ViewGroup; 62 import android.view.ViewRootImpl; 63 import android.widget.TextView; 64 65 import com.android.internal.R; 66 import com.android.internal.util.CollectionUtils; 67 import com.android.internal.util.Preconditions; 68 69 import java.lang.annotation.Retention; 70 import java.lang.annotation.RetentionPolicy; 71 import java.time.Duration; 72 import java.util.ArrayList; 73 import java.util.Collections; 74 import java.util.List; 75 import java.util.Map; 76 import java.util.Objects; 77 78 /** 79 * This class represents a node of the window content as well as actions that 80 * can be requested from its source. From the point of view of an 81 * {@link android.accessibilityservice.AccessibilityService} a window's content is 82 * presented as a tree of accessibility node infos, which may or may not map one-to-one 83 * to the view hierarchy. In other words, a custom view is free to report itself as 84 * a tree of accessibility node info. 85 * </p> 86 * <p> 87 * Once an accessibility node info is delivered to an accessibility service it is 88 * made immutable and calling a state mutation method generates an error. See 89 * {@link #setQueryFromAppProcessEnabled} if you would like to inspect the 90 * node tree from the app process for testing or debugging tools. 91 * </p> 92 * <p> 93 * Please refer to {@link android.accessibilityservice.AccessibilityService} for 94 * details about how to obtain a handle to window content as a tree of accessibility 95 * node info as well as details about the security model. 96 * </p> 97 * <div class="special reference"> 98 * <h3>Developer Guides</h3> 99 * <p>For more information about making applications accessible, read the 100 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 101 * developer guide.</p> 102 * </div> 103 * <aside class="note"> 104 * <b>Note:</b> Use a {@link androidx.core.view.accessibility.AccessibilityNodeInfoCompat} 105 * wrapper instead of this class for backwards-compatibility. </aside> 106 * 107 * @see android.accessibilityservice.AccessibilityService 108 * @see AccessibilityEvent 109 * @see AccessibilityManager 110 */ 111 public class AccessibilityNodeInfo implements Parcelable { 112 113 private static final String TAG = "AccessibilityNodeInfo"; 114 115 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG) && Build.IS_DEBUGGABLE; 116 117 /** @hide */ 118 public static final int UNDEFINED_CONNECTION_ID = -1; 119 120 /** @hide */ 121 public static final int UNDEFINED_SELECTION_INDEX = -1; 122 123 /** @hide */ 124 public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE; 125 126 /** @hide */ 127 public static final int ROOT_ITEM_ID = Integer.MAX_VALUE - 1; 128 129 /** @hide */ 130 public static final int LEASHED_ITEM_ID = Integer.MAX_VALUE - 2; 131 132 /** @hide */ 133 public static final long UNDEFINED_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID); 134 135 /** @hide */ 136 public static final long ROOT_NODE_ID = makeNodeId(ROOT_ITEM_ID, 137 AccessibilityNodeProvider.HOST_VIEW_ID); 138 139 /** @hide */ 140 public static final long LEASHED_NODE_ID = makeNodeId(LEASHED_ITEM_ID, 141 AccessibilityNodeProvider.HOST_VIEW_ID); 142 143 // Prefetch flags. 144 145 /** 146 * Prefetching strategy that prefetches the ancestors of the requested node. 147 * <p> Ancestors will be prefetched before siblings and descendants. 148 * 149 * @see #getChild(int, int) 150 * @see #getParent(int) 151 * @see AccessibilityWindowInfo#getRoot(int) 152 * @see AccessibilityService#getRootInActiveWindow(int) 153 * @see AccessibilityEvent#getSource(int) 154 */ 155 public static final int FLAG_PREFETCH_ANCESTORS = 1 /* << 0 */; 156 157 /** 158 * Prefetching strategy that prefetches the siblings of the requested node. 159 * <p> To avoid disconnected trees, this flag will also prefetch the parent. Siblings will be 160 * prefetched before descendants. 161 * 162 * <p> See {@link #FLAG_PREFETCH_ANCESTORS} for information on where these flags can be used. 163 */ 164 public static final int FLAG_PREFETCH_SIBLINGS = 1 << 1; 165 166 /** 167 * Prefetching strategy that prefetches the descendants in a hybrid depth first and breadth 168 * first approach. 169 * <p> The children of the root node is prefetched before recursing on the children. This 170 * must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or 171 * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an 172 * IllegalArgumentException. 173 * 174 * <p> See {@link #FLAG_PREFETCH_ANCESTORS} for information on where these flags can be used. 175 */ 176 public static final int FLAG_PREFETCH_DESCENDANTS_HYBRID = 1 << 2; 177 178 /** 179 * Prefetching strategy that prefetches the descendants of the requested node depth-first. 180 * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or 181 * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an 182 * IllegalArgumentException. 183 * 184 * <p> See {@link #FLAG_PREFETCH_ANCESTORS} for information on where these flags can be used. 185 */ 186 public static final int FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST = 1 << 3; 187 188 /** 189 * Prefetching strategy that prefetches the descendants of the requested node breadth-first. 190 * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or 191 * {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or this will trigger an 192 * IllegalArgumentException. 193 * 194 * <p> See {@link #FLAG_PREFETCH_ANCESTORS} for information on where these flags can be used. 195 */ 196 public static final int FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST = 1 << 4; 197 198 /** 199 * Prefetching flag that specifies prefetching should not be interrupted by a request to 200 * retrieve a node or perform an action on a node. 201 * 202 * <p> See {@link #FLAG_PREFETCH_ANCESTORS} for information on where these flags can be used. 203 */ 204 public static final int FLAG_PREFETCH_UNINTERRUPTIBLE = 1 << 5; 205 206 /** 207 * Mask for {@link PrefetchingStrategy} all types. 208 * 209 * @see #FLAG_PREFETCH_ANCESTORS 210 * @see #FLAG_PREFETCH_SIBLINGS 211 * @see #FLAG_PREFETCH_DESCENDANTS_HYBRID 212 * @see #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST 213 * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST 214 * @see #FLAG_PREFETCH_UNINTERRUPTIBLE 215 * 216 * @hide 217 */ 218 public static final int FLAG_PREFETCH_MASK = 0x0000003F; 219 220 /** 221 * Mask for {@link PrefetchingStrategy} that includes only descendants-related strategies. 222 * 223 * @see #FLAG_PREFETCH_DESCENDANTS_HYBRID 224 * @see #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST 225 * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST 226 * 227 * @hide 228 */ 229 public static final int FLAG_PREFETCH_DESCENDANTS_MASK = 0x0000001C; 230 231 /** 232 * Maximum batch size of prefetched nodes for a request. 233 */ 234 @SuppressLint("MinMaxConstant") 235 public static final int MAX_NUMBER_OF_PREFETCHED_NODES = 50; 236 237 /** @hide */ 238 @Retention(RetentionPolicy.SOURCE) 239 @IntDef(flag = true, prefix = { "FLAG_PREFETCH" }, value = { 240 FLAG_PREFETCH_ANCESTORS, 241 FLAG_PREFETCH_SIBLINGS, 242 FLAG_PREFETCH_DESCENDANTS_HYBRID, 243 FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST, 244 FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST, 245 FLAG_PREFETCH_UNINTERRUPTIBLE 246 }) 247 public @interface PrefetchingStrategy {} 248 249 // Service flags. 250 251 /** 252 * @see AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 253 * @hide 254 */ 255 public static final int FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS = 1 << 7; 256 257 /** 258 * @see AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS 259 * @hide 260 */ 261 public static final int FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS = 1 << 8; 262 263 /** 264 * @see AccessibilityServiceInfo#isAccessibilityTool() 265 * @hide 266 */ 267 public static final int FLAG_SERVICE_IS_ACCESSIBILITY_TOOL = 1 << 9; 268 269 /** 270 * Mask for all types of additional view data exposed to services. 271 * 272 * @hide 273 */ 274 public static final int FLAG_REPORT_MASK = 275 FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS 276 | FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS 277 | FLAG_SERVICE_IS_ACCESSIBILITY_TOOL; 278 279 // Actions. 280 281 /** 282 * Action that gives input focus to the node. 283 * See {@link AccessibilityAction#ACTION_FOCUS} 284 */ 285 public static final int ACTION_FOCUS = 1 /* << 0 */; 286 287 /** 288 * Action that clears input focus of the node. 289 * See {@link AccessibilityAction#ACTION_CLEAR_FOCUS} 290 */ 291 public static final int ACTION_CLEAR_FOCUS = 1 << 1; 292 293 /** 294 * Action that selects the node. 295 * @see AccessibilityAction#ACTION_SELECT 296 */ 297 public static final int ACTION_SELECT = 1 << 2; 298 299 /** 300 * Action that deselects the node. 301 */ 302 public static final int ACTION_CLEAR_SELECTION = 1 << 3; 303 304 /** 305 * Action that clicks on the node info. 306 * 307 * @see AccessibilityAction#ACTION_CLICK 308 */ 309 public static final int ACTION_CLICK = 1 << 4; 310 311 /** 312 * Action that long clicks on the node. 313 * 314 * <p>It does not support coordinate information for anchoring.</p> 315 * @see AccessibilityAction#ACTION_LONG_CLICK 316 */ 317 public static final int ACTION_LONG_CLICK = 1 << 5; 318 319 /** 320 * Action that gives accessibility focus to the node. 321 * See {@link AccessibilityAction#ACTION_ACCESSIBILITY_FOCUS} 322 */ 323 public static final int ACTION_ACCESSIBILITY_FOCUS = 1 << 6; 324 325 /** 326 * Action that clears accessibility focus of the node. 327 * See {@link AccessibilityAction#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 328 */ 329 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 1 << 7; 330 331 /** 332 * Action that requests to go to the next entity in this node's text 333 * at a given movement granularity. For example, move to the next character, 334 * word, etc. 335 * <p> 336 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 337 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 338 * <strong>Example:</strong> Move to the previous character and do not extend selection. 339 * <code><pre><p> 340 * Bundle arguments = new Bundle(); 341 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 342 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 343 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 344 * false); 345 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments); 346 * </code></pre></p> 347 * </p> 348 * 349 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 350 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 351 * 352 * @see #setMovementGranularities(int) 353 * @see #getMovementGranularities() 354 * 355 * @see #MOVEMENT_GRANULARITY_CHARACTER 356 * @see #MOVEMENT_GRANULARITY_WORD 357 * @see #MOVEMENT_GRANULARITY_LINE 358 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 359 * @see #MOVEMENT_GRANULARITY_PAGE 360 */ 361 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 1 << 8; 362 363 /** 364 * Action that requests to go to the previous entity in this node's text 365 * at a given movement granularity. For example, move to the next character, 366 * word, etc. 367 * <p> 368 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 369 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 370 * <strong>Example:</strong> Move to the next character and do not extend selection. 371 * <code><pre><p> 372 * Bundle arguments = new Bundle(); 373 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 374 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 375 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 376 * false); 377 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, 378 * arguments); 379 * </code></pre></p> 380 * </p> 381 * 382 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 383 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 384 * 385 * @see #setMovementGranularities(int) 386 * @see #getMovementGranularities() 387 * 388 * @see #MOVEMENT_GRANULARITY_CHARACTER 389 * @see #MOVEMENT_GRANULARITY_WORD 390 * @see #MOVEMENT_GRANULARITY_LINE 391 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 392 * @see #MOVEMENT_GRANULARITY_PAGE 393 */ 394 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 1 << 9; 395 396 /** 397 * Action to move to the next HTML element of a given type. For example, move 398 * to the BUTTON, INPUT, TABLE, etc. 399 * <p> 400 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 401 * <strong>Example:</strong> 402 * <code><pre><p> 403 * Bundle arguments = new Bundle(); 404 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 405 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments); 406 * </code></pre></p> 407 * </p> 408 */ 409 public static final int ACTION_NEXT_HTML_ELEMENT = 1 << 10; 410 411 /** 412 * Action to move to the previous HTML element of a given type. For example, move 413 * to the BUTTON, INPUT, TABLE, etc. 414 * <p> 415 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 416 * <strong>Example:</strong> 417 * <code><pre><p> 418 * Bundle arguments = new Bundle(); 419 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 420 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments); 421 * </code></pre></p> 422 * </p> 423 */ 424 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 1 << 11; 425 426 /** 427 * Action to scroll the node content forward. 428 * @see AccessibilityAction#ACTION_SCROLL_FORWARD 429 */ 430 public static final int ACTION_SCROLL_FORWARD = 1 << 12; 431 432 /** 433 * Action to scroll the node content backward. 434 * @see AccessibilityAction#ACTION_SCROLL_BACKWARD 435 */ 436 public static final int ACTION_SCROLL_BACKWARD = 1 << 13; 437 438 /** 439 * Action to copy the current selection to the clipboard. 440 */ 441 public static final int ACTION_COPY = 1 << 14; 442 443 /** 444 * Action to paste the current clipboard content. 445 */ 446 public static final int ACTION_PASTE = 1 << 15; 447 448 /** 449 * Action to cut the current selection and place it to the clipboard. 450 */ 451 public static final int ACTION_CUT = 1 << 16; 452 453 /** 454 * Action to set the selection. Performing this action with no arguments 455 * clears the selection. 456 * 457 * @see AccessibilityAction#ACTION_SET_SELECTION 458 * @see #ACTION_ARGUMENT_SELECTION_START_INT 459 * @see #ACTION_ARGUMENT_SELECTION_END_INT 460 */ 461 public static final int ACTION_SET_SELECTION = 1 << 17; 462 463 /** 464 * Action to expand an expandable node. 465 */ 466 public static final int ACTION_EXPAND = 1 << 18; 467 468 /** 469 * Action to collapse an expandable node. 470 */ 471 public static final int ACTION_COLLAPSE = 1 << 19; 472 473 /** 474 * Action to dismiss a dismissable node. 475 */ 476 public static final int ACTION_DISMISS = 1 << 20; 477 478 /** 479 * Action that sets the text of the node. Performing the action without argument, using <code> 480 * null</code> or empty {@link CharSequence} will clear the text. This action will also put the 481 * cursor at the end of text. 482 * @see AccessibilityAction#ACTION_SET_TEXT 483 */ 484 public static final int ACTION_SET_TEXT = 1 << 21; 485 486 /** @hide */ 487 public static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT; 488 489 /** 490 * Mask to verify if a given value is a combination of the existing ACTION_ constants. 491 * 492 * The smallest possible action is 1, and the largest is 1 << 21, or {@link ACTION_SET_TEXT}. A 493 * node can have any combination of actions present, so a node's max action int is: 494 * 495 * 0000 0000 0011 1111 1111 1111 1111 1111 496 * 497 * Therefore, if an action has any of the following bits flipped, it will be invalid: 498 * 499 * 1111 1111 11-- ---- ---- ---- ---- ---- 500 * 501 * This can be represented in hexadecimal as 0xFFC00000. 502 * 503 * @see AccessibilityNodeInfo#addAction(int) 504 */ 505 private static final int INVALID_ACTIONS_MASK = 0xFFC00000; 506 507 // Action arguments. 508 509 /** 510 * Argument for which movement granularity to be used when traversing the node text. 511 * <p> 512 * <strong>Type:</strong> int<br> 513 * <strong>Actions:</strong> 514 * <ul> 515 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li> 516 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li> 517 * </ul> 518 * </p> 519 * 520 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 521 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 522 */ 523 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = 524 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; 525 526 /** 527 * Argument for which HTML element to get moving to the next/previous HTML element. 528 * <p> 529 * <strong>Type:</strong> String<br> 530 * <strong>Actions:</strong> 531 * <ul> 532 * <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li> 533 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li> 534 * </ul> 535 * </p> 536 * 537 * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT 538 * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT 539 */ 540 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = 541 "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; 542 543 /** 544 * Argument for whether when moving at granularity to extend the selection 545 * or to move it otherwise. 546 * <p> 547 * <strong>Type:</strong> boolean<br> 548 * <strong>Actions:</strong> 549 * <ul> 550 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li> 551 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li> 552 * </ul> 553 * 554 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 555 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 556 */ 557 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = 558 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN"; 559 560 /** 561 * Argument for specifying the selection start. 562 * <p> 563 * <strong>Type:</strong> int<br> 564 * <strong>Actions:</strong> 565 * <ul> 566 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li> 567 * </ul> 568 * 569 * @see AccessibilityAction#ACTION_SET_SELECTION 570 */ 571 public static final String ACTION_ARGUMENT_SELECTION_START_INT = 572 "ACTION_ARGUMENT_SELECTION_START_INT"; 573 574 /** 575 * Argument for specifying the selection end. 576 * <p> 577 * <strong>Type:</strong> int<br> 578 * <strong>Actions:</strong> 579 * <ul> 580 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li> 581 * </ul> 582 * 583 * @see AccessibilityAction#ACTION_SET_SELECTION 584 */ 585 public static final String ACTION_ARGUMENT_SELECTION_END_INT = 586 "ACTION_ARGUMENT_SELECTION_END_INT"; 587 588 /** 589 * Argument for specifying the text content to set. 590 * <p> 591 * <strong>Type:</strong> CharSequence<br> 592 * <strong>Actions:</strong> 593 * <ul> 594 * <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li> 595 * </ul> 596 * 597 * @see AccessibilityAction#ACTION_SET_TEXT 598 */ 599 public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = 600 "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; 601 602 /** 603 * Argument for specifying the collection row to make visible on screen. 604 * <p> 605 * <strong>Type:</strong> int<br> 606 * <strong>Actions:</strong> 607 * <ul> 608 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li> 609 * </ul> 610 * 611 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION 612 */ 613 public static final String ACTION_ARGUMENT_ROW_INT = 614 "android.view.accessibility.action.ARGUMENT_ROW_INT"; 615 616 /** 617 * Argument for specifying the collection column to make visible on screen. 618 * <p> 619 * <strong>Type:</strong> int<br> 620 * <strong>Actions:</strong> 621 * <ul> 622 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li> 623 * </ul> 624 * 625 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION 626 */ 627 public static final String ACTION_ARGUMENT_COLUMN_INT = 628 "android.view.accessibility.action.ARGUMENT_COLUMN_INT"; 629 630 /** 631 * Argument for specifying the progress value to set. 632 * <p> 633 * <strong>Type:</strong> float<br> 634 * <strong>Actions:</strong> 635 * <ul> 636 * <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li> 637 * </ul> 638 * 639 * @see AccessibilityAction#ACTION_SET_PROGRESS 640 */ 641 public static final String ACTION_ARGUMENT_PROGRESS_VALUE = 642 "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE"; 643 644 /** 645 * Argument for specifying the x coordinate to which to move a window. 646 * <p> 647 * <strong>Type:</strong> int<br> 648 * <strong>Actions:</strong> 649 * <ul> 650 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li> 651 * </ul> 652 * 653 * @see AccessibilityAction#ACTION_MOVE_WINDOW 654 */ 655 public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = 656 "ACTION_ARGUMENT_MOVE_WINDOW_X"; 657 658 /** 659 * Argument for specifying the y coordinate to which to move a window. 660 * <p> 661 * <strong>Type:</strong> int<br> 662 * <strong>Actions:</strong> 663 * <ul> 664 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li> 665 * </ul> 666 * 667 * @see AccessibilityAction#ACTION_MOVE_WINDOW 668 */ 669 public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = 670 "ACTION_ARGUMENT_MOVE_WINDOW_Y"; 671 672 /** 673 * Argument to pass the {@link AccessibilityClickableSpan}. 674 * For use with R.id.accessibilityActionClickOnClickableSpan 675 * @hide 676 */ 677 public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN = 678 "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN"; 679 680 /** 681 * Argument to represent the duration in milliseconds to press and hold a node. 682 * <p> 683 * <strong>Type:</strong> int<br> 684 * <strong>Actions:</strong> 685 * <ul> 686 * <li>{@link AccessibilityAction#ACTION_PRESS_AND_HOLD}</li> 687 * </ul> 688 * 689 * @see AccessibilityAction#ACTION_PRESS_AND_HOLD 690 */ 691 public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = 692 "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT"; 693 694 /** 695 * <p>Argument to represent the direction when using 696 * {@link AccessibilityAction#ACTION_SCROLL_IN_DIRECTION}.</p> 697 * 698 * <p> 699 * The value of this argument can be one of: 700 * <ul> 701 * <li>{@link View#FOCUS_DOWN}</li> 702 * <li>{@link View#FOCUS_UP}</li> 703 * <li>{@link View#FOCUS_LEFT}</li> 704 * <li>{@link View#FOCUS_RIGHT}</li> 705 * <li>{@link View#FOCUS_FORWARD}</li> 706 * <li>{@link View#FOCUS_BACKWARD}</li> 707 * </ul> 708 * </p> 709 */ 710 public static final String ACTION_ARGUMENT_DIRECTION_INT = 711 "android.view.accessibility.action.ARGUMENT_DIRECTION_INT"; 712 713 /** 714 * <p>Argument to represent the scroll amount as a percent of the visible area of a node, with 715 * 1.0F as the default. Values smaller than 1.0F represent a partial scroll of the node, and 716 * values larger than 1.0F represent a scroll that extends beyond the currently visible node 717 * Rect. Setting this to {@link Float#POSITIVE_INFINITY} or to another "too large" value should 718 * scroll to the end of the node. Negative values should not be used with this argument. 719 * </p> 720 * 721 * <p> 722 * This argument should be used with the following scroll actions: 723 * <ul> 724 * <li>{@link AccessibilityAction#ACTION_SCROLL_FORWARD}</li> 725 * <li>{@link AccessibilityAction#ACTION_SCROLL_BACKWARD}</li> 726 * <li>{@link AccessibilityAction#ACTION_SCROLL_UP}</li> 727 * <li>{@link AccessibilityAction#ACTION_SCROLL_DOWN}</li> 728 * <li>{@link AccessibilityAction#ACTION_SCROLL_LEFT}</li> 729 * <li>{@link AccessibilityAction#ACTION_SCROLL_RIGHT}</li> 730 * </ul> 731 * </p> 732 * <p> 733 * Example: if a view representing a list of items implements 734 * {@link AccessibilityAction#ACTION_SCROLL_FORWARD} to scroll forward by an entire screen 735 * (one "page"), then passing a value of .25F via this argument should scroll that view 736 * only by 1/4th of a screen. Passing a value of 1.50F via this argument should scroll the 737 * view by 1 1/2 screens or to end of the node if the node doesn't extend to 1 1/2 screens. 738 * </p> 739 * 740 * <p> 741 * This argument should not be used with the following scroll actions, which don't cleanly 742 * conform to granular scroll semantics: 743 * <ul> 744 * <li>{@link AccessibilityAction#ACTION_SCROLL_IN_DIRECTION}</li> 745 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li> 746 * </ul> 747 * </p> 748 * 749 * <p> 750 * Views that support this argument should set 751 * {@link #setGranularScrollingSupported(boolean)} to true. Clients should use 752 * {@link #isGranularScrollingSupported()} to check if granular scrolling is supported. 753 * </p> 754 */ 755 @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING) 756 public static final String ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT = 757 "android.view.accessibility.action.ARGUMENT_SCROLL_AMOUNT_FLOAT"; 758 759 // Focus types. 760 761 /** 762 * The input focus. 763 */ 764 public static final int FOCUS_INPUT = 1; 765 766 /** 767 * The accessibility focus. 768 */ 769 public static final int FOCUS_ACCESSIBILITY = 2; 770 771 // Movement granularities. 772 773 /** 774 * Movement granularity bit for traversing the text of a node by character. 775 */ 776 public static final int MOVEMENT_GRANULARITY_CHARACTER = 1 /* << 0 */; 777 778 /** 779 * Movement granularity bit for traversing the text of a node by word. 780 */ 781 public static final int MOVEMENT_GRANULARITY_WORD = 1 << 1; 782 783 /** 784 * Movement granularity bit for traversing the text of a node by line. 785 */ 786 public static final int MOVEMENT_GRANULARITY_LINE = 1 << 2; 787 788 /** 789 * Movement granularity bit for traversing the text of a node by paragraph. 790 */ 791 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 1 << 3; 792 793 /** 794 * Movement granularity bit for traversing the text of a node by page. 795 */ 796 public static final int MOVEMENT_GRANULARITY_PAGE = 1 << 4; 797 798 // Extra data arguments. 799 800 /** 801 * Key used to request and locate extra data for text character location. This key requests that 802 * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with 803 * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two 804 * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and 805 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid 806 * inside the CharSequence returned by {@link #getText()}, and the length must be positive. 807 * <p> 808 * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this 809 * string as a key for {@link Bundle#getParcelableArray(String)}. The 810 * {@link android.graphics.RectF} will be null for characters that either do not exist or are 811 * off the screen. 812 * 813 * {@see #refreshWithExtraData(String, Bundle)} 814 */ 815 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = 816 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; 817 818 /** 819 * Integer argument specifying the start index of the requested text location data. Must be 820 * valid inside the CharSequence returned by {@link #getText()}. 821 * 822 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 823 */ 824 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = 825 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX"; 826 827 /** 828 * Integer argument specifying the end index of the requested text location data. Must be 829 * positive and no larger than {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH}. 830 * 831 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 832 */ 833 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = 834 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; 835 836 /** 837 * The maximum allowed length of the requested text location data. 838 */ 839 public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; 840 841 /** 842 * Key used to request extra data for the rendering information. 843 * The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this 844 * info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without 845 * argument. 846 * <p> 847 * The data can be retrieved from the {@link ExtraRenderingInfo} returned by 848 * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutSize}, 849 * {@link ExtraRenderingInfo#getTextSizeInPx()} and 850 * {@link ExtraRenderingInfo#getTextSizeUnit()}. For layout params, it is supported by both 851 * {@link TextView} and {@link ViewGroup}. For text size and unit, it is only supported by 852 * {@link TextView}. 853 * 854 * @see #refreshWithExtraData(String, Bundle) 855 */ 856 public static final String EXTRA_DATA_RENDERING_INFO_KEY = 857 "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY"; 858 859 /** @hide */ 860 public static final String EXTRA_DATA_REQUESTED_KEY = 861 "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested"; 862 863 // Boolean attributes. 864 865 private static final int BOOLEAN_PROPERTY_CHECKABLE = 1 /* << 0 */; 866 867 private static final int BOOLEAN_PROPERTY_CHECKED = 1 << 1; 868 869 private static final int BOOLEAN_PROPERTY_FOCUSABLE = 1 << 2; 870 871 private static final int BOOLEAN_PROPERTY_FOCUSED = 1 << 3; 872 873 private static final int BOOLEAN_PROPERTY_SELECTED = 1 << 4; 874 875 private static final int BOOLEAN_PROPERTY_CLICKABLE = 1 << 5; 876 877 private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 1 << 6; 878 879 private static final int BOOLEAN_PROPERTY_ENABLED = 1 << 7; 880 881 private static final int BOOLEAN_PROPERTY_PASSWORD = 1 << 8; 882 883 private static final int BOOLEAN_PROPERTY_SCROLLABLE = 1 << 9; 884 885 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 1 << 10; 886 887 private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 1 << 11; 888 889 private static final int BOOLEAN_PROPERTY_EDITABLE = 1 << 12; 890 891 private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 1 << 13; 892 893 private static final int BOOLEAN_PROPERTY_DISMISSABLE = 1 << 14; 894 895 private static final int BOOLEAN_PROPERTY_MULTI_LINE = 1 << 15; 896 897 private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 1 << 16; 898 899 private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 1 << 17; 900 901 private static final int BOOLEAN_PROPERTY_IMPORTANCE = 1 << 18; 902 903 private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 1 << 19; 904 905 private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 1 << 20; 906 907 private static final int BOOLEAN_PROPERTY_IS_HEADING = 1 << 21; 908 909 private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 1 << 22; 910 911 private static final int BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE = 1 << 23; 912 913 private static final int BOOLEAN_PROPERTY_REQUEST_INITIAL_ACCESSIBILITY_FOCUS = 1 << 24; 914 915 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 1 << 25; 916 917 private static final int BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING = 1 << 26; 918 919 /** 920 * Bits that provide the id of a virtual descendant of a view. 921 */ 922 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L; 923 /** 924 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a 925 * virtual descendant of a view. Such a descendant does not exist in the view 926 * hierarchy and is only reported via the accessibility APIs. 927 */ 928 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32; 929 930 /** 931 * Gets the accessibility view id which identifies a View in the view three. 932 * 933 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}. 934 * @return The accessibility view id part of the node id. 935 * 936 * @hide 937 */ 938 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getAccessibilityViewId(long accessibilityNodeId)939 public static int getAccessibilityViewId(long accessibilityNodeId) { 940 return (int) accessibilityNodeId; 941 } 942 943 /** 944 * Gets the virtual descendant id which identifies an imaginary view in a 945 * containing View. 946 * 947 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}. 948 * @return The virtual view id part of the node id. 949 * 950 * @hide 951 */ 952 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getVirtualDescendantId(long accessibilityNodeId)953 public static int getVirtualDescendantId(long accessibilityNodeId) { 954 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK) 955 >> VIRTUAL_DESCENDANT_ID_SHIFT); 956 } 957 958 /** 959 * Makes a node id by shifting the <code>virtualDescendantId</code> 960 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking 961 * the bitwise or with the <code>accessibilityViewId</code>. 962 * 963 * @param accessibilityViewId A View accessibility id. 964 * @param virtualDescendantId A virtual descendant id. 965 * @return The node id. 966 * 967 * @hide 968 */ makeNodeId(int accessibilityViewId, int virtualDescendantId)969 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) { 970 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId; 971 } 972 973 private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo(); 974 975 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 976 private boolean mSealed; 977 978 // Data. 979 private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 980 @UnsupportedAppUsage 981 private long mSourceNodeId = UNDEFINED_NODE_ID; 982 private long mParentNodeId = UNDEFINED_NODE_ID; 983 private long mLabelForId = UNDEFINED_NODE_ID; 984 private long mLabeledById = UNDEFINED_NODE_ID; 985 private long mTraversalBefore = UNDEFINED_NODE_ID; 986 private long mTraversalAfter = UNDEFINED_NODE_ID; 987 988 private long mMinDurationBetweenContentChanges = 0; 989 990 private int mBooleanProperties; 991 private final Rect mBoundsInParent = new Rect(); 992 private final Rect mBoundsInScreen = new Rect(); 993 private final Rect mBoundsInWindow = new Rect(); 994 private int mDrawingOrderInParent; 995 996 private CharSequence mPackageName; 997 private CharSequence mClassName; 998 // Hidden, unparceled value used to hold the original value passed to setText 999 private CharSequence mOriginalText; 1000 private CharSequence mText; 1001 private CharSequence mHintText; 1002 private CharSequence mError; 1003 private CharSequence mPaneTitle; 1004 private CharSequence mStateDescription; 1005 private CharSequence mContentDescription; 1006 private CharSequence mTooltipText; 1007 private String mViewIdResourceName; 1008 private String mUniqueId; 1009 private CharSequence mContainerTitle; 1010 private ArrayList<String> mExtraDataKeys; 1011 1012 @UnsupportedAppUsage 1013 private LongArray mChildNodeIds; 1014 private ArrayList<AccessibilityAction> mActions; 1015 1016 private int mMaxTextLength = -1; 1017 private int mMovementGranularities; 1018 1019 private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX; 1020 private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX; 1021 private int mInputType = InputType.TYPE_NULL; 1022 private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; 1023 1024 private Bundle mExtras; 1025 1026 private int mConnectionId = UNDEFINED_CONNECTION_ID; 1027 1028 private RangeInfo mRangeInfo; 1029 private CollectionInfo mCollectionInfo; 1030 private CollectionItemInfo mCollectionItemInfo; 1031 1032 private TouchDelegateInfo mTouchDelegateInfo; 1033 1034 private ExtraRenderingInfo mExtraRenderingInfo; 1035 1036 private IBinder mLeashedChild; 1037 private IBinder mLeashedParent; 1038 private long mLeashedParentNodeId = UNDEFINED_NODE_ID; 1039 1040 /** 1041 * Creates a new {@link AccessibilityNodeInfo}. 1042 */ AccessibilityNodeInfo()1043 public AccessibilityNodeInfo() { 1044 } 1045 1046 /** 1047 * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>. 1048 * 1049 * @param source The source view. 1050 */ AccessibilityNodeInfo(@onNull View source)1051 public AccessibilityNodeInfo(@NonNull View source) { 1052 setSource(source); 1053 } 1054 1055 /** 1056 * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>. 1057 * 1058 * @param root The root of the virtual subtree. 1059 * @param virtualDescendantId The id of the virtual descendant. 1060 */ AccessibilityNodeInfo(@onNull View root, int virtualDescendantId)1061 public AccessibilityNodeInfo(@NonNull View root, int virtualDescendantId) { 1062 setSource(root, virtualDescendantId); 1063 } 1064 1065 /** 1066 * Copy constructor. Creates a new {@link AccessibilityNodeInfo}, and this new instance is 1067 * initialized from the given <code>info</code>. 1068 * 1069 * @param info The other info. 1070 */ AccessibilityNodeInfo(@onNull AccessibilityNodeInfo info)1071 public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { 1072 init(info); 1073 } 1074 1075 /** 1076 * Sets the source. 1077 * <p> 1078 * <strong>Note:</strong> Cannot be called from an 1079 * {@link android.accessibilityservice.AccessibilityService}. 1080 * This class is made immutable before being delivered to an AccessibilityService. 1081 * </p> 1082 * 1083 * @param source The info source. 1084 */ setSource(View source)1085 public void setSource(View source) { 1086 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID); 1087 } 1088 1089 /** 1090 * Sets the source to be a virtual descendant of the given <code>root</code>. 1091 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 1092 * is set as the source. 1093 * <p> 1094 * A virtual descendant is an imaginary View that is reported as a part of the view 1095 * hierarchy for accessibility purposes. This enables custom views that draw complex 1096 * content to report themselves as a tree of virtual views, thus conveying their 1097 * logical structure. 1098 * </p> 1099 * <p> 1100 * <strong>Note:</strong> Cannot be called from an 1101 * {@link android.accessibilityservice.AccessibilityService}. 1102 * This class is made immutable before being delivered to an AccessibilityService. 1103 * </p> 1104 * 1105 * @param root The root of the virtual subtree. 1106 * @param virtualDescendantId The id of the virtual descendant. 1107 */ setSource(View root, int virtualDescendantId)1108 public void setSource(View root, int virtualDescendantId) { 1109 enforceNotSealed(); 1110 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID; 1111 final int rootAccessibilityViewId = 1112 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1113 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1114 } 1115 1116 /** 1117 * Find the view that has the specified focus type. The search starts from 1118 * the view represented by this node info. 1119 * 1120 * <p> 1121 * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another 1122 * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that 1123 * this API won't be able to find the node for the view on the embedded view hierarchy. It's 1124 * because views don't know about the embedded hierarchies. Instead, you could traverse all 1125 * the children to find the node. Or, use {@link AccessibilityService#findFocus(int)} for 1126 * {@link #FOCUS_ACCESSIBILITY} only since it has no such limitation. 1127 * </p> 1128 * 1129 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or 1130 * {@link #FOCUS_ACCESSIBILITY}. 1131 * @return The node info of the focused view or null. 1132 * 1133 * @see #FOCUS_INPUT 1134 * @see #FOCUS_ACCESSIBILITY 1135 */ findFocus(int focus)1136 public AccessibilityNodeInfo findFocus(int focus) { 1137 enforceSealed(); 1138 enforceValidFocusType(focus); 1139 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1140 return null; 1141 } 1142 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId, 1143 mSourceNodeId, focus); 1144 } 1145 1146 /** 1147 * Searches for the nearest view in the specified direction that can take 1148 * the input focus. 1149 * 1150 * <p> 1151 * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another 1152 * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that 1153 * this API won't be able to find the node for the view in the specified direction on the 1154 * embedded view hierarchy. It's because views don't know about the embedded hierarchies. 1155 * Instead, you could traverse all the children to find the node. 1156 * </p> 1157 * 1158 * @param direction The direction. Can be one of: 1159 * {@link View#FOCUS_DOWN}, 1160 * {@link View#FOCUS_UP}, 1161 * {@link View#FOCUS_LEFT}, 1162 * {@link View#FOCUS_RIGHT}, 1163 * {@link View#FOCUS_FORWARD}, 1164 * {@link View#FOCUS_BACKWARD}. 1165 * 1166 * @return The node info for the view that can take accessibility focus. 1167 */ focusSearch(int direction)1168 public AccessibilityNodeInfo focusSearch(int direction) { 1169 enforceSealed(); 1170 enforceValidFocusDirection(direction); 1171 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1172 return null; 1173 } 1174 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId, 1175 mSourceNodeId, direction); 1176 } 1177 1178 /** 1179 * Gets the id of the window from which the info comes from. 1180 * 1181 * @return The window id. 1182 */ getWindowId()1183 public int getWindowId() { 1184 return mWindowId; 1185 } 1186 1187 /** 1188 * Refreshes this info with the latest state of the view it represents. 1189 * 1190 * @param bypassCache Whether to bypass the cache. 1191 * @return Whether the refresh succeeded. 1192 * 1193 * @hide 1194 */ 1195 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) refresh(Bundle arguments, boolean bypassCache)1196 public boolean refresh(Bundle arguments, boolean bypassCache) { 1197 enforceSealed(); 1198 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1199 return false; 1200 } 1201 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1202 AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId( 1203 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments); 1204 if (refreshedInfo == null) { 1205 return false; 1206 } 1207 init(refreshedInfo); 1208 return true; 1209 } 1210 1211 /** 1212 * Refreshes this info with the latest state of the view it represents. 1213 * 1214 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented 1215 * by this node is no longer in the view tree (and thus this node is obsolete). 1216 */ refresh()1217 public boolean refresh() { 1218 return refresh(null, true); 1219 } 1220 1221 /** 1222 * Refreshes this info with the latest state of the view it represents, and request new 1223 * data be added by the View. 1224 * 1225 * @param extraDataKey The extra data requested. Data that must be requested 1226 * with this mechanism is generally expensive to retrieve, so should only be 1227 * requested when needed. See 1228 * {@link #EXTRA_DATA_RENDERING_INFO_KEY}, 1229 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY}, 1230 * {@link #getAvailableExtraData()} and {@link #getExtraRenderingInfo()}. 1231 * @param args A bundle of arguments for the request. These depend on the particular request. 1232 * 1233 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented 1234 * by this node is no longer in the view tree (and thus this node is obsolete). 1235 */ refreshWithExtraData(String extraDataKey, Bundle args)1236 public boolean refreshWithExtraData(String extraDataKey, Bundle args) { 1237 // limits the text location length to make sure the rectangle array allocation avoids 1238 // the binder transaction failure and OOM crash. 1239 if (args.getInt(EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, -1) 1240 > EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH) { 1241 args.putInt(EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, 1242 EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH); 1243 } 1244 1245 args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey); 1246 return refresh(args, true); 1247 } 1248 1249 /** 1250 * Returns the array containing the IDs of this node's children. 1251 * 1252 * @hide 1253 */ getChildNodeIds()1254 public LongArray getChildNodeIds() { 1255 return mChildNodeIds; 1256 } 1257 1258 /** 1259 * Returns the id of the child at the specified index. 1260 * 1261 * @throws IndexOutOfBoundsException when index < 0 || index >= 1262 * getChildCount() 1263 * @hide 1264 */ getChildId(int index)1265 public long getChildId(int index) { 1266 if (mChildNodeIds == null) { 1267 throw new IndexOutOfBoundsException(); 1268 } 1269 return mChildNodeIds.get(index); 1270 } 1271 1272 /** 1273 * Gets the number of children. 1274 * 1275 * @return The child count. 1276 */ getChildCount()1277 public int getChildCount() { 1278 return mChildNodeIds == null ? 0 : mChildNodeIds.size(); 1279 } 1280 1281 /** 1282 * Get the child at given index. 1283 * 1284 * @param index The child index. 1285 * @return The child node. 1286 * 1287 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 1288 * calling {@link #setQueryFromAppProcessEnabled}. 1289 */ getChild(int index)1290 public AccessibilityNodeInfo getChild(int index) { 1291 return getChild(index, FLAG_PREFETCH_DESCENDANTS_HYBRID); 1292 } 1293 1294 1295 /** 1296 * Get the child at given index. 1297 * 1298 * <p> 1299 * See {@link #getParent(int)} for a description of prefetching. 1300 * @param index The child index. 1301 * @param prefetchingStrategy the prefetching strategy. 1302 * @return The child node. 1303 * 1304 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 1305 * calling {@link #setQueryFromAppProcessEnabled}. 1306 * 1307 */ 1308 @Nullable getChild(int index, @PrefetchingStrategy int prefetchingStrategy)1309 public AccessibilityNodeInfo getChild(int index, @PrefetchingStrategy int prefetchingStrategy) { 1310 enforceSealed(); 1311 if (mChildNodeIds == null) { 1312 return null; 1313 } 1314 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1315 return null; 1316 } 1317 final long childId = mChildNodeIds.get(index); 1318 final AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1319 if (mLeashedChild != null && childId == LEASHED_NODE_ID) { 1320 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mLeashedChild, 1321 ROOT_NODE_ID, false, prefetchingStrategy, null); 1322 } 1323 1324 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId, 1325 childId, false, prefetchingStrategy, null); 1326 } 1327 1328 /** 1329 * Adds a child. 1330 * <p> 1331 * <strong>Note:</strong> Cannot be called from an 1332 * {@link android.accessibilityservice.AccessibilityService}. 1333 * This class is made immutable before being delivered to an AccessibilityService. 1334 * Note that a view cannot be made its own child. 1335 * </p> 1336 * 1337 * @param child The child. 1338 * 1339 * @throws IllegalStateException If called from an AccessibilityService. 1340 */ addChild(View child)1341 public void addChild(View child) { 1342 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, true); 1343 } 1344 1345 /** 1346 * Adds a view root from leashed content as a child. This method is used to embedded another 1347 * view hierarchy. 1348 * <p> 1349 * <strong>Note:</strong> Only one leashed child is permitted. 1350 * </p> 1351 * <p> 1352 * <strong>Note:</strong> Cannot be called from an 1353 * {@link android.accessibilityservice.AccessibilityService}. 1354 * This class is made immutable before being delivered to an AccessibilityService. 1355 * Note that a view cannot be made its own child. 1356 * </p> 1357 * 1358 * @param token The token to which a view root is added. 1359 * 1360 * @throws IllegalStateException If called from an AccessibilityService. 1361 * @hide 1362 */ 1363 @TestApi addChild(@onNull IBinder token)1364 public void addChild(@NonNull IBinder token) { 1365 enforceNotSealed(); 1366 if (token == null) { 1367 return; 1368 } 1369 if (mChildNodeIds == null) { 1370 mChildNodeIds = new LongArray(); 1371 } 1372 1373 mLeashedChild = token; 1374 // Checking uniqueness. 1375 // Since only one leashed child is permitted, skip adding ID if the ID already exists. 1376 if (mChildNodeIds.indexOf(LEASHED_NODE_ID) >= 0) { 1377 return; 1378 } 1379 mChildNodeIds.add(LEASHED_NODE_ID); 1380 } 1381 1382 /** 1383 * Unchecked version of {@link #addChild(View)} that does not verify 1384 * uniqueness. For framework use only. 1385 * 1386 * @hide 1387 */ addChildUnchecked(View child)1388 public void addChildUnchecked(View child) { 1389 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, false); 1390 } 1391 1392 /** 1393 * Removes a child. If the child was not previously added to the node, 1394 * calling this method has no effect. 1395 * <p> 1396 * <strong>Note:</strong> Cannot be called from an 1397 * {@link android.accessibilityservice.AccessibilityService}. 1398 * This class is made immutable before being delivered to an AccessibilityService. 1399 * </p> 1400 * 1401 * @param child The child. 1402 * @return true if the child was present 1403 * 1404 * @throws IllegalStateException If called from an AccessibilityService. 1405 */ removeChild(View child)1406 public boolean removeChild(View child) { 1407 return removeChild(child, AccessibilityNodeProvider.HOST_VIEW_ID); 1408 } 1409 1410 /** 1411 * Removes a leashed child. If the child was not previously added to the node, 1412 * calling this method has no effect. 1413 * <p> 1414 * <strong>Note:</strong> Cannot be called from an 1415 * {@link android.accessibilityservice.AccessibilityService}. 1416 * This class is made immutable before being delivered to an AccessibilityService. 1417 * </p> 1418 * 1419 * @param token The token of the leashed child 1420 * @return true if the child was present 1421 * 1422 * @throws IllegalStateException If called from an AccessibilityService. 1423 * @hide 1424 */ removeChild(IBinder token)1425 public boolean removeChild(IBinder token) { 1426 enforceNotSealed(); 1427 if (mChildNodeIds == null || mLeashedChild == null) { 1428 return false; 1429 } 1430 if (!mLeashedChild.equals(token)) { 1431 return false; 1432 } 1433 final int index = mChildNodeIds.indexOf(LEASHED_NODE_ID); 1434 mLeashedChild = null; 1435 if (index < 0) { 1436 return false; 1437 } 1438 mChildNodeIds.remove(index); 1439 return true; 1440 } 1441 1442 /** 1443 * Adds a virtual child which is a descendant of the given <code>root</code>. 1444 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 1445 * is added as a child. 1446 * <p> 1447 * A virtual descendant is an imaginary View that is reported as a part of the view 1448 * hierarchy for accessibility purposes. This enables custom views that draw complex 1449 * content to report them selves as a tree of virtual views, thus conveying their 1450 * logical structure. 1451 * Note that a view cannot be made its own child. 1452 * </p> 1453 * 1454 * @param root The root of the virtual subtree. 1455 * @param virtualDescendantId The id of the virtual child. 1456 */ addChild(View root, int virtualDescendantId)1457 public void addChild(View root, int virtualDescendantId) { 1458 addChildInternal(root, virtualDescendantId, true); 1459 } 1460 addChildInternal(View root, int virtualDescendantId, boolean checked)1461 private void addChildInternal(View root, int virtualDescendantId, boolean checked) { 1462 enforceNotSealed(); 1463 if (mChildNodeIds == null) { 1464 mChildNodeIds = new LongArray(); 1465 } 1466 final int rootAccessibilityViewId = 1467 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1468 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1469 if (childNodeId == mSourceNodeId) { 1470 Log.e(TAG, "Rejecting attempt to make a View its own child"); 1471 return; 1472 } 1473 1474 // If we're checking uniqueness and the ID already exists, abort. 1475 if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) { 1476 return; 1477 } 1478 mChildNodeIds.add(childNodeId); 1479 } 1480 1481 /** 1482 * Removes a virtual child which is a descendant of the given 1483 * <code>root</code>. If the child was not previously added to the node, 1484 * calling this method has no effect. 1485 * 1486 * @param root The root of the virtual subtree. 1487 * @param virtualDescendantId The id of the virtual child. 1488 * @return true if the child was present 1489 * @see #addChild(View, int) 1490 */ removeChild(View root, int virtualDescendantId)1491 public boolean removeChild(View root, int virtualDescendantId) { 1492 enforceNotSealed(); 1493 final LongArray childIds = mChildNodeIds; 1494 if (childIds == null) { 1495 return false; 1496 } 1497 final int rootAccessibilityViewId = 1498 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1499 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1500 final int index = childIds.indexOf(childNodeId); 1501 if (index < 0) { 1502 return false; 1503 } 1504 childIds.remove(index); 1505 return true; 1506 } 1507 1508 /** 1509 * Gets the actions that can be performed on the node. 1510 */ getActionList()1511 public List<AccessibilityAction> getActionList() { 1512 return CollectionUtils.emptyIfNull(mActions); 1513 } 1514 1515 /** 1516 * Gets the actions that can be performed on the node. 1517 * 1518 * @return The bit mask of with actions. 1519 * 1520 * @see AccessibilityNodeInfo#ACTION_FOCUS 1521 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS 1522 * @see AccessibilityNodeInfo#ACTION_SELECT 1523 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION 1524 * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS 1525 * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS 1526 * @see AccessibilityNodeInfo#ACTION_CLICK 1527 * @see AccessibilityNodeInfo#ACTION_LONG_CLICK 1528 * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 1529 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 1530 * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT 1531 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT 1532 * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD 1533 * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD 1534 * 1535 * @deprecated Use {@link #getActionList()}. 1536 */ 1537 @Deprecated getActions()1538 public int getActions() { 1539 int returnValue = 0; 1540 1541 if (mActions == null) { 1542 return returnValue; 1543 } 1544 1545 final int actionSize = mActions.size(); 1546 for (int i = 0; i < actionSize; i++) { 1547 int actionId = mActions.get(i).getId(); 1548 if (actionId <= LAST_LEGACY_STANDARD_ACTION) { 1549 returnValue |= actionId; 1550 } 1551 } 1552 1553 return returnValue; 1554 } 1555 1556 /** 1557 * Adds an action that can be performed on the node. 1558 * <p> 1559 * To add a standard action use the static constants on {@link AccessibilityAction}. 1560 * To add a custom action create a new {@link AccessibilityAction} by passing in a 1561 * resource id from your application as the action id and an optional label that 1562 * describes the action. To override one of the standard actions use as the action 1563 * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that 1564 * describes the action. 1565 * </p> 1566 * <p> 1567 * Use {@link androidx.core.view.ViewCompat#addAccessibilityAction(View, CharSequence, 1568 * AccessibilityViewCommand)} to register an action directly on the view. 1569 * <p> 1570 * <strong>Note:</strong> Cannot be called from an 1571 * {@link android.accessibilityservice.AccessibilityService}. 1572 * This class is made immutable before being delivered to an AccessibilityService. 1573 * </p> 1574 * 1575 * @param action The action. 1576 * 1577 * @throws IllegalStateException If called from an AccessibilityService. 1578 */ addAction(AccessibilityAction action)1579 public void addAction(AccessibilityAction action) { 1580 enforceNotSealed(); 1581 1582 addActionUnchecked(action); 1583 } 1584 addActionUnchecked(AccessibilityAction action)1585 private void addActionUnchecked(AccessibilityAction action) { 1586 if (action == null) { 1587 return; 1588 } 1589 1590 if (mActions == null) { 1591 mActions = new ArrayList<>(); 1592 } 1593 1594 mActions.remove(action); 1595 mActions.add(action); 1596 } 1597 1598 /** 1599 * Adds an action that can be performed on the node. 1600 * <p> 1601 * <strong>Note:</strong> Cannot be called from an 1602 * {@link android.accessibilityservice.AccessibilityService}. 1603 * This class is made immutable before being delivered to an AccessibilityService. 1604 * </p> 1605 * 1606 * @param action The action. 1607 * 1608 * @throws IllegalStateException If called from an AccessibilityService. 1609 * @throws IllegalArgumentException If the argument is not one of the standard actions. 1610 * 1611 * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)} 1612 */ 1613 @Deprecated addAction(int action)1614 public void addAction(int action) { 1615 enforceNotSealed(); 1616 1617 if ((action & INVALID_ACTIONS_MASK) != 0) { 1618 throw new IllegalArgumentException("Action is not a combination of the standard " + 1619 "actions: " + action); 1620 } 1621 1622 addStandardActions(action); 1623 } 1624 1625 /** 1626 * Removes an action that can be performed on the node. If the action was 1627 * not already added to the node, calling this method has no effect. 1628 * <p> 1629 * <strong>Note:</strong> Cannot be called from an 1630 * {@link android.accessibilityservice.AccessibilityService}. 1631 * This class is made immutable before being delivered to an AccessibilityService. 1632 * </p> 1633 * 1634 * @param action The action to be removed. 1635 * 1636 * @throws IllegalStateException If called from an AccessibilityService. 1637 * @deprecated Use {@link #removeAction(AccessibilityAction)} 1638 */ 1639 @Deprecated removeAction(int action)1640 public void removeAction(int action) { 1641 enforceNotSealed(); 1642 1643 removeAction(getActionSingleton(action)); 1644 } 1645 1646 /** 1647 * Removes an action that can be performed on the node. If the action was 1648 * not already added to the node, calling this method has no effect. 1649 * <p> 1650 * <strong>Note:</strong> Cannot be called from an 1651 * {@link android.accessibilityservice.AccessibilityService}. 1652 * This class is made immutable before being delivered to an AccessibilityService. 1653 * </p> 1654 * 1655 * @param action The action to be removed. 1656 * @return The action removed from the list of actions. 1657 * 1658 * @throws IllegalStateException If called from an AccessibilityService. 1659 */ removeAction(AccessibilityAction action)1660 public boolean removeAction(AccessibilityAction action) { 1661 enforceNotSealed(); 1662 1663 if (mActions == null || action == null) { 1664 return false; 1665 } 1666 1667 return mActions.remove(action); 1668 } 1669 1670 /** 1671 * Removes all actions. 1672 * 1673 * @hide 1674 */ removeAllActions()1675 public void removeAllActions() { 1676 if (mActions != null) { 1677 mActions.clear(); 1678 } 1679 } 1680 1681 /** 1682 * Gets the node before which this one is visited during traversal. A screen-reader 1683 * must visit the content of this node before the content of the one it precedes. 1684 * 1685 * @return The succeeding node if such or <code>null</code>. 1686 * 1687 * @see #setTraversalBefore(android.view.View) 1688 * @see #setTraversalBefore(android.view.View, int) 1689 */ getTraversalBefore()1690 public AccessibilityNodeInfo getTraversalBefore() { 1691 enforceSealed(); 1692 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalBefore); 1693 } 1694 1695 /** 1696 * Sets the view before whose node this one should be visited during traversal. A 1697 * screen-reader must visit the content of this node before the content of the one 1698 * it precedes. 1699 * <p> 1700 * <strong>Note:</strong> Cannot be called from an 1701 * {@link android.accessibilityservice.AccessibilityService}. 1702 * This class is made immutable before being delivered to an AccessibilityService. 1703 * </p> 1704 * 1705 * @param view The view providing the preceding node. 1706 * 1707 * @see #getTraversalBefore() 1708 */ setTraversalBefore(View view)1709 public void setTraversalBefore(View view) { 1710 setTraversalBefore(view, AccessibilityNodeProvider.HOST_VIEW_ID); 1711 } 1712 1713 /** 1714 * Sets the node before which this one is visited during traversal. A screen-reader 1715 * must visit the content of this node before the content of the one it precedes. 1716 * The successor is a virtual descendant of the given <code>root</code>. If 1717 * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set 1718 * as the successor. 1719 * <p> 1720 * A virtual descendant is an imaginary View that is reported as a part of the view 1721 * hierarchy for accessibility purposes. This enables custom views that draw complex 1722 * content to report them selves as a tree of virtual views, thus conveying their 1723 * logical structure. 1724 * </p> 1725 * <p> 1726 * <strong>Note:</strong> Cannot be called from an 1727 * {@link android.accessibilityservice.AccessibilityService}. 1728 * This class is made immutable before being delivered to an AccessibilityService. 1729 * </p> 1730 * 1731 * @param root The root of the virtual subtree. 1732 * @param virtualDescendantId The id of the virtual descendant. 1733 */ setTraversalBefore(View root, int virtualDescendantId)1734 public void setTraversalBefore(View root, int virtualDescendantId) { 1735 enforceNotSealed(); 1736 final int rootAccessibilityViewId = (root != null) 1737 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1738 mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1739 } 1740 1741 /** 1742 * Gets the node after which this one is visited in accessibility traversal. 1743 * A screen-reader must visit the content of the other node before the content 1744 * of this one. 1745 * 1746 * @return The succeeding node if such or <code>null</code>. 1747 * 1748 * @see #setTraversalAfter(android.view.View) 1749 * @see #setTraversalAfter(android.view.View, int) 1750 */ getTraversalAfter()1751 public AccessibilityNodeInfo getTraversalAfter() { 1752 enforceSealed(); 1753 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalAfter); 1754 } 1755 1756 /** 1757 * Sets the view whose node is visited after this one in accessibility traversal. 1758 * A screen-reader must visit the content of the other node before the content 1759 * of this one. 1760 * <p> 1761 * <strong>Note:</strong> Cannot be called from an 1762 * {@link android.accessibilityservice.AccessibilityService}. 1763 * This class is made immutable before being delivered to an AccessibilityService. 1764 * </p> 1765 * 1766 * @param view The previous view. 1767 * 1768 * @see #getTraversalAfter() 1769 */ setTraversalAfter(View view)1770 public void setTraversalAfter(View view) { 1771 setTraversalAfter(view, AccessibilityNodeProvider.HOST_VIEW_ID); 1772 } 1773 1774 /** 1775 * Sets the node after which this one is visited in accessibility traversal. 1776 * A screen-reader must visit the content of the other node before the content 1777 * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID} 1778 * the root is set as the predecessor. 1779 * <p> 1780 * A virtual descendant is an imaginary View that is reported as a part of the view 1781 * hierarchy for accessibility purposes. This enables custom views that draw complex 1782 * content to report them selves as a tree of virtual views, thus conveying their 1783 * logical structure. 1784 * </p> 1785 * <p> 1786 * <strong>Note:</strong> Cannot be called from an 1787 * {@link android.accessibilityservice.AccessibilityService}. 1788 * This class is made immutable before being delivered to an AccessibilityService. 1789 * </p> 1790 * 1791 * @param root The root of the virtual subtree. 1792 * @param virtualDescendantId The id of the virtual descendant. 1793 */ setTraversalAfter(View root, int virtualDescendantId)1794 public void setTraversalAfter(View root, int virtualDescendantId) { 1795 enforceNotSealed(); 1796 final int rootAccessibilityViewId = (root != null) 1797 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1798 mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1799 } 1800 1801 /** 1802 * Get the extra data available for this node. 1803 * <p> 1804 * Some data that is useful for some accessibility services is expensive to compute, and would 1805 * place undue overhead on apps to compute all the time. That data can be requested with 1806 * {@link #refreshWithExtraData(String, Bundle)}. 1807 * 1808 * @return An unmodifiable list of keys corresponding to extra data that can be requested. 1809 * @see #EXTRA_DATA_RENDERING_INFO_KEY 1810 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 1811 */ getAvailableExtraData()1812 public List<String> getAvailableExtraData() { 1813 if (mExtraDataKeys != null) { 1814 return Collections.unmodifiableList(mExtraDataKeys); 1815 } else { 1816 return EMPTY_LIST; 1817 } 1818 } 1819 1820 /** 1821 * Set the extra data available for this node. 1822 * <p> 1823 * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that 1824 * it will populate the node's extras with corresponding pieces of information in 1825 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}. 1826 * <p> 1827 * <strong>Note:</strong> Cannot be called from an 1828 * {@link android.accessibilityservice.AccessibilityService}. 1829 * This class is made immutable before being delivered to an AccessibilityService. 1830 * 1831 * @param extraDataKeys A list of types of extra data that are available. 1832 * @see #getAvailableExtraData() 1833 * 1834 * @throws IllegalStateException If called from an AccessibilityService. 1835 */ setAvailableExtraData(List<String> extraDataKeys)1836 public void setAvailableExtraData(List<String> extraDataKeys) { 1837 enforceNotSealed(); 1838 mExtraDataKeys = new ArrayList<>(extraDataKeys); 1839 } 1840 1841 /** 1842 * Sets the maximum text length, or -1 for no limit. 1843 * <p> 1844 * Typically used to indicate that an editable text field has a limit on 1845 * the number of characters entered. 1846 * <p> 1847 * <strong>Note:</strong> Cannot be called from an 1848 * {@link android.accessibilityservice.AccessibilityService}. 1849 * This class is made immutable before being delivered to an AccessibilityService. 1850 * 1851 * @param max The maximum text length. 1852 * @see #getMaxTextLength() 1853 * 1854 * @throws IllegalStateException If called from an AccessibilityService. 1855 */ setMaxTextLength(int max)1856 public void setMaxTextLength(int max) { 1857 enforceNotSealed(); 1858 mMaxTextLength = max; 1859 } 1860 1861 /** 1862 * Returns the maximum text length for this node. 1863 * 1864 * @return The maximum text length, or -1 for no limit. 1865 * @see #setMaxTextLength(int) 1866 */ getMaxTextLength()1867 public int getMaxTextLength() { 1868 return mMaxTextLength; 1869 } 1870 1871 /** 1872 * Sets the movement granularities for traversing the text of this node. 1873 * <p> 1874 * <strong>Note:</strong> Cannot be called from an 1875 * {@link android.accessibilityservice.AccessibilityService}. 1876 * This class is made immutable before being delivered to an AccessibilityService. 1877 * </p> 1878 * 1879 * @param granularities The bit mask with granularities. 1880 * 1881 * @throws IllegalStateException If called from an AccessibilityService. 1882 */ setMovementGranularities(int granularities)1883 public void setMovementGranularities(int granularities) { 1884 enforceNotSealed(); 1885 mMovementGranularities = granularities; 1886 } 1887 1888 /** 1889 * Gets the movement granularities for traversing the text of this node. 1890 * 1891 * @return The bit mask with granularities. 1892 */ getMovementGranularities()1893 public int getMovementGranularities() { 1894 return mMovementGranularities; 1895 } 1896 1897 /** 1898 * Sets the minimum time duration between two content change events, which is used in throttling 1899 * content change events in accessibility services. 1900 * 1901 * <p> 1902 * Example: An app can set MinMillisBetweenContentChanges as 1 min for a view which sends 1903 * content change events to accessibility services one event per second. 1904 * Accessibility service will throttle those content change events and only handle one event 1905 * per minute for that view. 1906 * </p> 1907 * <p> 1908 * Example UI elements that frequently update and may benefit from a duration are progress bars, 1909 * timers, and stopwatches. 1910 * </p> 1911 * 1912 * @see AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 1913 * @see AccessibilityEvent#getContentChangeTypes 1914 * @param duration the minimum duration between content change events. 1915 * Negative duration would be treated as zero. 1916 */ setMinDurationBetweenContentChanges(@onNull Duration duration)1917 public void setMinDurationBetweenContentChanges(@NonNull Duration duration) { 1918 enforceNotSealed(); 1919 mMinDurationBetweenContentChanges = duration.toMillis(); 1920 } 1921 1922 /** 1923 * Gets the minimum time duration between two content change events. 1924 */ 1925 @NonNull getMinDurationBetweenContentChanges()1926 public Duration getMinDurationBetweenContentChanges() { 1927 return Duration.ofMillis(mMinDurationBetweenContentChanges); 1928 } 1929 1930 /** 1931 * Performs an action on the node. 1932 * <p> 1933 * <strong>Note:</strong> An action can be performed only if the request is made 1934 * from an {@link android.accessibilityservice.AccessibilityService}. 1935 * </p> 1936 * 1937 * @param action The action to perform. 1938 * @return True if the action was performed. 1939 * 1940 * @throws IllegalStateException If called outside of an AccessibilityService. 1941 */ performAction(int action)1942 public boolean performAction(int action) { 1943 enforceSealed(); 1944 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1945 return false; 1946 } 1947 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1948 Bundle arguments = null; 1949 if (mExtras != null) { 1950 arguments = mExtras; 1951 } 1952 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId, 1953 action, arguments); 1954 } 1955 1956 /** 1957 * Performs an action on the node. 1958 * <p> 1959 * <strong>Note:</strong> An action can be performed only if the request is made 1960 * from an {@link android.accessibilityservice.AccessibilityService}. 1961 * </p> 1962 * 1963 * @param action The action to perform. 1964 * @param arguments A bundle with additional arguments. 1965 * @return True if the action was performed. 1966 * 1967 * @throws IllegalStateException If called outside of an AccessibilityService. 1968 */ performAction(int action, Bundle arguments)1969 public boolean performAction(int action, Bundle arguments) { 1970 enforceSealed(); 1971 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1972 return false; 1973 } 1974 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1975 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId, 1976 action, arguments); 1977 } 1978 1979 /** 1980 * Finds {@link AccessibilityNodeInfo}s by text. The match is case 1981 * insensitive containment. The search is relative to this info i.e. 1982 * this info is the root of the traversed tree. 1983 * 1984 * <p> 1985 * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another 1986 * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that 1987 * this API won't be able to find the node for the view on the embedded view hierarchy. It's 1988 * because views don't know about the embedded hierarchies. Instead, you could traverse all 1989 * the children to find the node. 1990 * </p> 1991 * 1992 * @param text The searched text. 1993 * @return A list of node info. 1994 */ findAccessibilityNodeInfosByText(String text)1995 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) { 1996 enforceSealed(); 1997 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 1998 return Collections.emptyList(); 1999 } 2000 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 2001 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId, 2002 text); 2003 } 2004 2005 /** 2006 * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource 2007 * name where a fully qualified id is of the from "package:id/id_resource_name". 2008 * For example, if the target application's package is "foo.bar" and the id 2009 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz". 2010 * 2011 * <p> 2012 * <strong>Note:</strong> The primary usage of this API is for UI test automation 2013 * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo} 2014 * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} 2015 * flag when configuring the {@link android.accessibilityservice.AccessibilityService}. 2016 * </p> 2017 * <p> 2018 * <strong>Note:</strong> If this view hierarchy has a {@link SurfaceView} embedding another 2019 * view hierarchy via {@link SurfaceView#setChildSurfacePackage}, there is a limitation that 2020 * this API won't be able to find the node for the view on the embedded view hierarchy. It's 2021 * because views don't know about the embedded hierarchies. Instead, you could traverse all 2022 * the children to find the node. 2023 * </p> 2024 * 2025 * @param viewId The fully qualified resource name of the view id to find. 2026 * @return A list of node info. 2027 */ findAccessibilityNodeInfosByViewId(@onNull String viewId)2028 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(@NonNull String viewId) { 2029 enforceSealed(); 2030 if (viewId == null) { 2031 Log.e(TAG, "returns empty list due to null viewId."); 2032 return Collections.emptyList(); 2033 } 2034 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 2035 return Collections.emptyList(); 2036 } 2037 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 2038 return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId, 2039 viewId); 2040 } 2041 2042 /** 2043 * Gets the window to which this node belongs. 2044 * 2045 * @return The window. 2046 * 2047 * @see android.accessibilityservice.AccessibilityService#getWindows() 2048 */ getWindow()2049 public AccessibilityWindowInfo getWindow() { 2050 enforceSealed(); 2051 if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) { 2052 return null; 2053 } 2054 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 2055 return client.getWindow(mConnectionId, mWindowId); 2056 } 2057 2058 /** 2059 * Gets the parent. 2060 * 2061 * @return The parent. 2062 * 2063 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 2064 * calling {@link #setQueryFromAppProcessEnabled}. 2065 */ getParent()2066 public AccessibilityNodeInfo getParent() { 2067 enforceSealed(); 2068 if (mLeashedParent != null && mLeashedParentNodeId != UNDEFINED_NODE_ID) { 2069 return getNodeForAccessibilityId(mConnectionId, mLeashedParent, mLeashedParentNodeId, 2070 FLAG_PREFETCH_ANCESTORS | FLAG_PREFETCH_SIBLINGS); 2071 } 2072 return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId); 2073 } 2074 2075 /** 2076 * Gets the parent. 2077 * 2078 * <p> 2079 * Use {@code prefetchingStrategy} to determine the types of 2080 * nodes prefetched from the app if the requested node is not in the cache and must be retrieved 2081 * by the app. The default strategy for {@link #getParent()} is a combination of ancestor and 2082 * sibling strategies. The app will prefetch until all nodes fulfilling the strategies are 2083 * fetched, another node request is sent, or the maximum prefetch batch size of 2084 * {@link #MAX_NUMBER_OF_PREFETCHED_NODES} nodes is reached. To prevent interruption by another 2085 * request and to force prefetching of the max batch size, use 2086 * {@link AccessibilityNodeInfo#FLAG_PREFETCH_UNINTERRUPTIBLE}. 2087 * </p> 2088 * 2089 * @param prefetchingStrategy the prefetching strategy. 2090 * @return The parent. 2091 * 2092 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 2093 * calling {@link #setQueryFromAppProcessEnabled}. 2094 * 2095 * @see #FLAG_PREFETCH_ANCESTORS 2096 * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST 2097 * @see #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST 2098 * @see #FLAG_PREFETCH_DESCENDANTS_HYBRID 2099 * @see #FLAG_PREFETCH_SIBLINGS 2100 * @see #FLAG_PREFETCH_UNINTERRUPTIBLE 2101 */ 2102 @Nullable getParent(@refetchingStrategy int prefetchingStrategy)2103 public AccessibilityNodeInfo getParent(@PrefetchingStrategy int prefetchingStrategy) { 2104 enforceSealed(); 2105 if (mLeashedParent != null && mLeashedParentNodeId != UNDEFINED_NODE_ID) { 2106 return getNodeForAccessibilityId(mConnectionId, mLeashedParent, mLeashedParentNodeId, 2107 prefetchingStrategy); 2108 } 2109 return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId, 2110 prefetchingStrategy); 2111 } 2112 2113 /** 2114 * @return The parent node id. 2115 * 2116 * @hide 2117 */ getParentNodeId()2118 public long getParentNodeId() { 2119 return mParentNodeId; 2120 } 2121 2122 /** 2123 * Sets the parent. 2124 * <p> 2125 * <strong>Note:</strong> Cannot be called from an 2126 * {@link android.accessibilityservice.AccessibilityService}. 2127 * This class is made immutable before being delivered to an AccessibilityService. 2128 * </p> 2129 * 2130 * @param parent The parent. 2131 * 2132 * @throws IllegalStateException If called from an AccessibilityService. 2133 */ setParent(View parent)2134 public void setParent(View parent) { 2135 setParent(parent, AccessibilityNodeProvider.HOST_VIEW_ID); 2136 } 2137 2138 /** 2139 * Sets the parent to be a virtual descendant of the given <code>root</code>. 2140 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root 2141 * is set as the parent. 2142 * <p> 2143 * A virtual descendant is an imaginary View that is reported as a part of the view 2144 * hierarchy for accessibility purposes. This enables custom views that draw complex 2145 * content to report them selves as a tree of virtual views, thus conveying their 2146 * logical structure. 2147 * </p> 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 root The root of the virtual subtree. 2155 * @param virtualDescendantId The id of the virtual descendant. 2156 */ setParent(View root, int virtualDescendantId)2157 public void setParent(View root, int virtualDescendantId) { 2158 enforceNotSealed(); 2159 final int rootAccessibilityViewId = 2160 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 2161 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 2162 } 2163 2164 /** 2165 * Gets the node bounds in the viewParent's coordinates. 2166 * {@link #getParent()} does not represent the source's viewParent. 2167 * Instead it represents the result of {@link View#getParentForAccessibility()}, 2168 * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. 2169 * So this method is not reliable. 2170 * <p> 2171 * When magnification is enabled, the bounds in parent are also scaled up by magnification 2172 * scale. For example, it returns Rect(20, 20, 200, 200) for original bounds 2173 * Rect(10, 10, 100, 100), when the magnification scale is 2. 2174 * <p/> 2175 * 2176 * @param outBounds The output node bounds. 2177 * @deprecated Use {@link #getBoundsInScreen(Rect)} instead. 2178 * 2179 */ 2180 @Deprecated getBoundsInParent(Rect outBounds)2181 public void getBoundsInParent(Rect outBounds) { 2182 outBounds.set(mBoundsInParent.left, mBoundsInParent.top, 2183 mBoundsInParent.right, mBoundsInParent.bottom); 2184 } 2185 2186 /** 2187 * Sets the node bounds in the viewParent's coordinates. 2188 * {@link #getParent()} does not represent the source's viewParent. 2189 * Instead it represents the result of {@link View#getParentForAccessibility()}, 2190 * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. 2191 * So this method is not reliable. 2192 * 2193 * <p> 2194 * <strong>Note:</strong> Cannot be called from an 2195 * {@link android.accessibilityservice.AccessibilityService}. 2196 * This class is made immutable before being delivered to an AccessibilityService. 2197 * </p> 2198 * 2199 * @param bounds The node bounds. 2200 * 2201 * @throws IllegalStateException If called from an AccessibilityService. 2202 * @deprecated Accessibility services should not care about these bounds. 2203 */ 2204 @Deprecated setBoundsInParent(Rect bounds)2205 public void setBoundsInParent(Rect bounds) { 2206 enforceNotSealed(); 2207 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom); 2208 } 2209 2210 /** 2211 * Gets the node bounds in screen coordinates. 2212 * <p> 2213 * When magnification is enabled, the bounds in screen are scaled up by magnification scale 2214 * and the positions are also adjusted according to the offset of magnification viewport. 2215 * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100), 2216 * when the magnification scale is 2 and offsets for X and Y are both 200. 2217 * <p/> 2218 * 2219 * @param outBounds The output node bounds. 2220 */ getBoundsInScreen(Rect outBounds)2221 public void getBoundsInScreen(Rect outBounds) { 2222 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top, 2223 mBoundsInScreen.right, mBoundsInScreen.bottom); 2224 } 2225 2226 /** 2227 * Returns the actual rect containing the node bounds in screen coordinates. 2228 * 2229 * @hide Not safe to expose outside the framework. 2230 */ getBoundsInScreen()2231 public Rect getBoundsInScreen() { 2232 return mBoundsInScreen; 2233 } 2234 2235 /** 2236 * Sets the node bounds in screen coordinates. 2237 * <p> 2238 * <strong>Note:</strong> Cannot be called from an 2239 * {@link android.accessibilityservice.AccessibilityService}. 2240 * This class is made immutable before being delivered to an AccessibilityService. 2241 * </p> 2242 * 2243 * @param bounds The node bounds. 2244 * 2245 * @throws IllegalStateException If called from an AccessibilityService. 2246 */ setBoundsInScreen(Rect bounds)2247 public void setBoundsInScreen(Rect bounds) { 2248 enforceNotSealed(); 2249 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom); 2250 } 2251 2252 /** 2253 * Gets the node bounds in window coordinates. 2254 * <p> 2255 * When magnification is enabled, the bounds in window are scaled up by magnification scale 2256 * and the positions are also adjusted according to the offset of magnification viewport. 2257 * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100), 2258 * when the magnification scale is 2 and offsets for X and Y are both 200. 2259 * <p/> 2260 * 2261 * @param outBounds The output node bounds. 2262 */ getBoundsInWindow(@onNull Rect outBounds)2263 public void getBoundsInWindow(@NonNull Rect outBounds) { 2264 outBounds.set(mBoundsInWindow.left, mBoundsInWindow.top, 2265 mBoundsInWindow.right, mBoundsInWindow.bottom); 2266 } 2267 2268 /** 2269 * Returns the actual rect containing the node bounds in window coordinates. 2270 * 2271 * @hide Not safe to expose outside the framework. 2272 */ 2273 @NonNull getBoundsInWindow()2274 public Rect getBoundsInWindow() { 2275 return mBoundsInWindow; 2276 } 2277 2278 /** 2279 * Sets the node bounds in window coordinates. 2280 * <p> 2281 * <strong>Note:</strong> Cannot be called from an 2282 * {@link android.accessibilityservice.AccessibilityService}. 2283 * This class is made immutable before being delivered to an AccessibilityService. 2284 * </p> 2285 * 2286 * @param bounds The node bounds. 2287 * 2288 * @throws IllegalStateException If called from an AccessibilityService. 2289 */ setBoundsInWindow(@onNull Rect bounds)2290 public void setBoundsInWindow(@NonNull Rect bounds) { 2291 enforceNotSealed(); 2292 mBoundsInWindow.set(bounds); 2293 } 2294 2295 /** 2296 * Gets whether this node is checkable. 2297 * 2298 * @return True if the node is checkable. 2299 */ isCheckable()2300 public boolean isCheckable() { 2301 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE); 2302 } 2303 2304 /** 2305 * Sets whether this node is checkable. 2306 * <p> 2307 * <strong>Note:</strong> Cannot be called from an 2308 * {@link android.accessibilityservice.AccessibilityService}. 2309 * This class is made immutable before being delivered to an AccessibilityService. 2310 * </p> 2311 * 2312 * @param checkable True if the node is checkable. 2313 * 2314 * @throws IllegalStateException If called from an AccessibilityService. 2315 */ setCheckable(boolean checkable)2316 public void setCheckable(boolean checkable) { 2317 setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable); 2318 } 2319 2320 /** 2321 * Gets whether this node is checked. 2322 * 2323 * @return True if the node is checked. 2324 */ isChecked()2325 public boolean isChecked() { 2326 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED); 2327 } 2328 2329 /** 2330 * Sets whether this node is checked. 2331 * <p> 2332 * <strong>Note:</strong> Cannot be called from an 2333 * {@link android.accessibilityservice.AccessibilityService}. 2334 * This class is made immutable before being delivered to an AccessibilityService. 2335 * </p> 2336 * 2337 * @param checked True if the node is checked. 2338 * 2339 * @throws IllegalStateException If called from an AccessibilityService. 2340 */ setChecked(boolean checked)2341 public void setChecked(boolean checked) { 2342 setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked); 2343 } 2344 2345 /** 2346 * Gets whether this node is focusable. 2347 * 2348 * <p>In the View system, this typically maps to {@link View#isFocusable()}. 2349 * @return True if the node is focusable. 2350 */ isFocusable()2351 public boolean isFocusable() { 2352 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE); 2353 } 2354 2355 /** 2356 * Sets whether this node is focusable. 2357 * <p> 2358 * <strong>Note:</strong> Cannot be called from an 2359 * {@link android.accessibilityservice.AccessibilityService}. 2360 * This class is made immutable before being delivered to an AccessibilityService. 2361 * </p> 2362 * <p>To mark a node as explicitly focusable for a screen reader, consider using 2363 * {@link #setScreenReaderFocusable(boolean)} instead. 2364 * 2365 * @param focusable True if the node is focusable. 2366 * 2367 * @throws IllegalStateException If called from an AccessibilityService. 2368 */ setFocusable(boolean focusable)2369 public void setFocusable(boolean focusable) { 2370 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable); 2371 } 2372 2373 /** 2374 * Gets whether this node is focused. 2375 * 2376 * <p>This is distinct from {@link #isAccessibilityFocused()}, which is used by screen readers. 2377 * See {@link AccessibilityAction#ACTION_ACCESSIBILITY_FOCUS} for details. 2378 * 2379 * @return True if the node is focused. 2380 */ isFocused()2381 public boolean isFocused() { 2382 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED); 2383 } 2384 2385 /** 2386 * Sets whether this node is focused. 2387 * <p> 2388 * <strong>Note:</strong> Cannot be called from an 2389 * {@link android.accessibilityservice.AccessibilityService}. 2390 * This class is made immutable before being delivered to an AccessibilityService. 2391 * </p> 2392 * 2393 * @param focused True if the node is focused. 2394 * 2395 * @throws IllegalStateException If called from an AccessibilityService. 2396 */ setFocused(boolean focused)2397 public void setFocused(boolean focused) { 2398 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused); 2399 } 2400 2401 /** 2402 * Gets whether this node is visible to the user. 2403 * <p> 2404 * Between {@link Build.VERSION_CODES#JELLY_BEAN API 16} and 2405 * {@link Build.VERSION_CODES#Q API 29}, this method may incorrectly return false when 2406 * magnification is enabled. On other versions, a node is considered visible even if it is not 2407 * on the screen because magnification is active. 2408 * </p> 2409 * 2410 * @return Whether the node is visible to the user. 2411 */ isVisibleToUser()2412 public boolean isVisibleToUser() { 2413 return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER); 2414 } 2415 2416 /** 2417 * Sets whether this node is visible to the user. 2418 * <p> 2419 * <strong>Note:</strong> Cannot be called from an 2420 * {@link android.accessibilityservice.AccessibilityService}. 2421 * This class is made immutable before being delivered to an AccessibilityService. 2422 * </p> 2423 * 2424 * @param visibleToUser Whether the node is visible to the user. 2425 * 2426 * @throws IllegalStateException If called from an AccessibilityService. 2427 */ setVisibleToUser(boolean visibleToUser)2428 public void setVisibleToUser(boolean visibleToUser) { 2429 setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser); 2430 } 2431 2432 /** 2433 * Gets whether this node is accessibility focused. 2434 * 2435 * <p>This is distinct from {@link #isFocused()}, which is used to track system focus. 2436 * See {@link #ACTION_ACCESSIBILITY_FOCUS} for details. 2437 * @return True if the node is accessibility focused. 2438 */ isAccessibilityFocused()2439 public boolean isAccessibilityFocused() { 2440 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED); 2441 } 2442 2443 /** 2444 * Sets whether this node is accessibility focused. 2445 * <p> 2446 * <strong>Note:</strong> Cannot be called from an 2447 * {@link android.accessibilityservice.AccessibilityService}. 2448 * This class is made immutable before being delivered to an AccessibilityService. 2449 * </p> 2450 * <p>The UI element updating this property should send an event of 2451 * {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED} 2452 * or {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED} if its 2453 * accessibility-focused state changes. 2454 * @param focused True if the node is accessibility focused. 2455 * 2456 * @throws IllegalStateException If called from an AccessibilityService. 2457 */ setAccessibilityFocused(boolean focused)2458 public void setAccessibilityFocused(boolean focused) { 2459 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused); 2460 } 2461 2462 /** 2463 * Gets whether this node is selected. 2464 * 2465 * @return True if the node is selected. 2466 */ isSelected()2467 public boolean isSelected() { 2468 return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED); 2469 } 2470 2471 /** 2472 * Sets whether this node is selected. 2473 * <p> 2474 * <strong>Note:</strong> Cannot be called from an 2475 * {@link android.accessibilityservice.AccessibilityService}. 2476 * This class is made immutable before being delivered to an AccessibilityService. 2477 * </p> 2478 * 2479 * @param selected True if the node is selected. 2480 * 2481 * @throws IllegalStateException If called from an AccessibilityService. 2482 */ setSelected(boolean selected)2483 public void setSelected(boolean selected) { 2484 setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected); 2485 } 2486 2487 /** 2488 * Gets whether this node is clickable. 2489 * 2490 * @return True if the node is clickable. 2491 */ isClickable()2492 public boolean isClickable() { 2493 return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE); 2494 } 2495 2496 /** 2497 * Sets whether this node is clickable. 2498 * <p> 2499 * <strong>Note:</strong> Cannot be called from an 2500 * {@link android.accessibilityservice.AccessibilityService}. 2501 * This class is made immutable before being delivered to an AccessibilityService. 2502 * </p> 2503 * 2504 * @param clickable True if the node is clickable. 2505 * 2506 * @throws IllegalStateException If called from an AccessibilityService. 2507 */ setClickable(boolean clickable)2508 public void setClickable(boolean clickable) { 2509 setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable); 2510 } 2511 2512 /** 2513 * Gets whether this node is long clickable. 2514 * 2515 * @return True if the node is long clickable. 2516 */ isLongClickable()2517 public boolean isLongClickable() { 2518 return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE); 2519 } 2520 2521 /** 2522 * Sets whether this node is long clickable. 2523 * <p> 2524 * <strong>Note:</strong> Cannot be called from an 2525 * {@link android.accessibilityservice.AccessibilityService}. 2526 * This class is made immutable before being delivered to an AccessibilityService. 2527 * </p> 2528 * 2529 * @param longClickable True if the node is long clickable. 2530 * 2531 * @throws IllegalStateException If called from an AccessibilityService. 2532 */ setLongClickable(boolean longClickable)2533 public void setLongClickable(boolean longClickable) { 2534 setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable); 2535 } 2536 2537 /** 2538 * Gets whether this node is enabled. 2539 * 2540 * @return True if the node is enabled. 2541 */ isEnabled()2542 public boolean isEnabled() { 2543 return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED); 2544 } 2545 2546 /** 2547 * Sets whether this node is enabled. 2548 * <p> 2549 * <strong>Note:</strong> Cannot be called from an 2550 * {@link android.accessibilityservice.AccessibilityService}. 2551 * This class is made immutable before being delivered to an AccessibilityService. 2552 * </p> 2553 * 2554 * @param enabled True if the node is enabled. 2555 * 2556 * @throws IllegalStateException If called from an AccessibilityService. 2557 */ setEnabled(boolean enabled)2558 public void setEnabled(boolean enabled) { 2559 setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled); 2560 } 2561 2562 /** 2563 * Gets whether this node is a password. 2564 * 2565 * @return True if the node is a password. 2566 */ isPassword()2567 public boolean isPassword() { 2568 return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD); 2569 } 2570 2571 /** 2572 * Sets whether this node is a password. 2573 * <p> 2574 * <strong>Note:</strong> Cannot be called from an 2575 * {@link android.accessibilityservice.AccessibilityService}. 2576 * This class is made immutable before being delivered to an AccessibilityService. 2577 * </p> 2578 * 2579 * @param password True if the node is a password. 2580 * 2581 * @throws IllegalStateException If called from an AccessibilityService. 2582 */ setPassword(boolean password)2583 public void setPassword(boolean password) { 2584 setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password); 2585 } 2586 2587 /** 2588 * Gets if the node is scrollable. 2589 * 2590 * @return True if the node is scrollable, false otherwise. 2591 */ isScrollable()2592 public boolean isScrollable() { 2593 return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE); 2594 } 2595 2596 /** 2597 * Sets if the node is scrollable. 2598 * <p> 2599 * <strong>Note:</strong> Cannot be called from an 2600 * {@link android.accessibilityservice.AccessibilityService}. 2601 * This class is made immutable before being delivered to an AccessibilityService. 2602 * </p> 2603 * 2604 * @param scrollable True if the node is scrollable, false otherwise. 2605 * 2606 * @throws IllegalStateException If called from an AccessibilityService. 2607 */ setScrollable(boolean scrollable)2608 public void setScrollable(boolean scrollable) { 2609 setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable); 2610 } 2611 2612 /** 2613 * Gets if the node supports granular scrolling. 2614 * 2615 * @return True if all scroll actions that could support 2616 * {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT} have done so, false otherwise. 2617 */ 2618 @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING) isGranularScrollingSupported()2619 public boolean isGranularScrollingSupported() { 2620 return getBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING); 2621 } 2622 2623 /** 2624 * Sets if the node supports granular scrolling. This should be set to true if all scroll 2625 * actions which could support {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT} have done so. 2626 * <p> 2627 * <strong>Note:</strong> Cannot be called from an 2628 * {@link android.accessibilityservice.AccessibilityService}. 2629 * This class is made immutable before being delivered to an AccessibilityService. 2630 * </p> 2631 * 2632 * @param granularScrollingSupported True if the node supports granular scrolling, false 2633 * otherwise. 2634 * 2635 * @throws IllegalStateException If called from an AccessibilityService. 2636 */ 2637 @FlaggedApi(Flags.FLAG_GRANULAR_SCROLLING) setGranularScrollingSupported(boolean granularScrollingSupported)2638 public void setGranularScrollingSupported(boolean granularScrollingSupported) { 2639 setBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING, 2640 granularScrollingSupported); 2641 } 2642 2643 /** 2644 * Gets if the node has selectable text. 2645 * 2646 * <p> 2647 * Services should use {@link #ACTION_SET_SELECTION} for selection. Editable text nodes must 2648 * also be selectable. But not all UIs will populate this field, so services should consider 2649 * 'isTextSelectable | isEditable' to ensure they don't miss nodes with selectable text. 2650 * </p> 2651 * 2652 * @see #isEditable 2653 * @return True if the node has selectable text. 2654 */ isTextSelectable()2655 public boolean isTextSelectable() { 2656 return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE); 2657 } 2658 2659 /** 2660 * Sets if the node has selectable text. 2661 * <p> 2662 * <strong>Note:</strong> Cannot be called from an 2663 * {@link android.accessibilityservice.AccessibilityService}. 2664 * This class is made immutable before being delivered to an AccessibilityService. 2665 * </p> 2666 * 2667 * @param selectableText True if the node has selectable text, false otherwise. 2668 * 2669 * @throws IllegalStateException If called from an AccessibilityService. 2670 */ setTextSelectable(boolean selectableText)2671 public void setTextSelectable(boolean selectableText) { 2672 setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_SELECTABLE, selectableText); 2673 } 2674 2675 /** 2676 * Gets whether the node has {@link #setRequestInitialAccessibilityFocus}. 2677 * 2678 * @return True if the node has requested initial accessibility focus. 2679 */ hasRequestInitialAccessibilityFocus()2680 public boolean hasRequestInitialAccessibilityFocus() { 2681 return getBooleanProperty(BOOLEAN_PROPERTY_REQUEST_INITIAL_ACCESSIBILITY_FOCUS); 2682 } 2683 2684 /** 2685 * Sets whether the node has requested initial accessibility focus. 2686 * 2687 * <p> 2688 * If the node {@link #hasRequestInitialAccessibilityFocus}, this node would be one of 2689 * candidates to be accessibility focused when the window appears. 2690 * </p> 2691 * 2692 * <p> 2693 * <strong>Note:</strong> Cannot be called from an 2694 * {@link android.accessibilityservice.AccessibilityService}. 2695 * This class is made immutable before being delivered to an AccessibilityService. 2696 * </p> 2697 * 2698 * @param requestInitialAccessibilityFocus True if the node requests to receive initial 2699 * accessibility focus. 2700 * @throws IllegalStateException If called from an AccessibilityService. 2701 */ setRequestInitialAccessibilityFocus(boolean requestInitialAccessibilityFocus)2702 public void setRequestInitialAccessibilityFocus(boolean requestInitialAccessibilityFocus) { 2703 setBooleanProperty(BOOLEAN_PROPERTY_REQUEST_INITIAL_ACCESSIBILITY_FOCUS, 2704 requestInitialAccessibilityFocus); 2705 } 2706 2707 /** 2708 * Gets if the node is editable. 2709 * 2710 * @return True if the node is editable, false otherwise. 2711 */ isEditable()2712 public boolean isEditable() { 2713 return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE); 2714 } 2715 2716 /** 2717 * Sets whether this node is editable. 2718 * <p> 2719 * <strong>Note:</strong> Cannot be called from an 2720 * {@link android.accessibilityservice.AccessibilityService}. 2721 * This class is made immutable before being delivered to an AccessibilityService. 2722 * </p> 2723 * 2724 * @param editable True if the node is editable. 2725 * 2726 * @throws IllegalStateException If called from an AccessibilityService. 2727 */ setEditable(boolean editable)2728 public void setEditable(boolean editable) { 2729 setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable); 2730 } 2731 2732 /** 2733 * Gets if the node's accessibility data is considered sensitive. 2734 * 2735 * @return True if the node's data is considered sensitive, false otherwise. 2736 * @see View#isAccessibilityDataSensitive() 2737 */ isAccessibilityDataSensitive()2738 public boolean isAccessibilityDataSensitive() { 2739 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); 2740 } 2741 2742 /** 2743 * Sets whether this node's accessibility data is considered sensitive. 2744 * 2745 * <p> 2746 * <strong>Note:</strong> Cannot be called from an {@link AccessibilityService}. 2747 * This class is made immutable before being delivered to an AccessibilityService. 2748 * </p> 2749 * 2750 * @param accessibilityDataSensitive True if the node's accessibility data is considered 2751 * sensitive. 2752 * @throws IllegalStateException If called from an AccessibilityService. 2753 * @see View#setAccessibilityDataSensitive 2754 */ setAccessibilityDataSensitive(boolean accessibilityDataSensitive)2755 public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { 2756 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, 2757 accessibilityDataSensitive); 2758 } 2759 2760 /** 2761 * If this node represents a visually distinct region of the screen that may update separately 2762 * from the rest of the window, it is considered a pane. Set the pane title to indicate that 2763 * the node is a pane, and to provide a title for it. 2764 * <p> 2765 * <strong>Note:</strong> Cannot be called from an 2766 * {@link android.accessibilityservice.AccessibilityService}. 2767 * This class is made immutable before being delivered to an AccessibilityService. 2768 * </p> 2769 * @param paneTitle The title of the pane represented by this node. 2770 */ setPaneTitle(@ullable CharSequence paneTitle)2771 public void setPaneTitle(@Nullable CharSequence paneTitle) { 2772 enforceNotSealed(); 2773 mPaneTitle = (paneTitle == null) 2774 ? null : paneTitle.subSequence(0, paneTitle.length()); 2775 } 2776 2777 /** 2778 * Get the title of the pane represented by this node. 2779 * 2780 * @return The title of the pane represented by this node, or {@code null} if this node does 2781 * not represent a pane. 2782 */ getPaneTitle()2783 public @Nullable CharSequence getPaneTitle() { 2784 return mPaneTitle; 2785 } 2786 2787 /** 2788 * Get the drawing order of the view corresponding it this node. 2789 * <p> 2790 * Drawing order is determined only within the node's parent, so this index is only relative 2791 * to its siblings. 2792 * <p> 2793 * In some cases, the drawing order is essentially simultaneous, so it is possible for two 2794 * siblings to return the same value. It is also possible that values will be skipped. 2795 * 2796 * @return The drawing position of the view corresponding to this node relative to its siblings. 2797 */ getDrawingOrder()2798 public int getDrawingOrder() { 2799 return mDrawingOrderInParent; 2800 } 2801 2802 /** 2803 * Set the drawing order of the view corresponding it this node. 2804 * 2805 * <p> 2806 * <strong>Note:</strong> Cannot be called from an 2807 * {@link android.accessibilityservice.AccessibilityService}. 2808 * This class is made immutable before being delivered to an AccessibilityService. 2809 * </p> 2810 * @param drawingOrderInParent 2811 * @throws IllegalStateException If called from an AccessibilityService. 2812 */ setDrawingOrder(int drawingOrderInParent)2813 public void setDrawingOrder(int drawingOrderInParent) { 2814 enforceNotSealed(); 2815 mDrawingOrderInParent = drawingOrderInParent; 2816 } 2817 2818 /** 2819 * Gets the collection info if the node is a collection. A collection 2820 * child is always a collection item. 2821 * 2822 * @return The collection info. 2823 */ getCollectionInfo()2824 public CollectionInfo getCollectionInfo() { 2825 return mCollectionInfo; 2826 } 2827 2828 /** 2829 * Sets the collection info if the node is a collection. A collection 2830 * child is always a collection item. 2831 * <p> 2832 * <strong>Note:</strong> Cannot be called from an 2833 * {@link android.accessibilityservice.AccessibilityService}. 2834 * This class is made immutable before being delivered to an AccessibilityService. 2835 * </p> 2836 * 2837 * @param collectionInfo The collection info. 2838 */ setCollectionInfo(CollectionInfo collectionInfo)2839 public void setCollectionInfo(CollectionInfo collectionInfo) { 2840 enforceNotSealed(); 2841 mCollectionInfo = collectionInfo; 2842 } 2843 2844 /** 2845 * Gets the collection item info if the node is a collection item. A collection 2846 * item is always a child of a collection. 2847 * 2848 * @return The collection item info. 2849 */ getCollectionItemInfo()2850 public CollectionItemInfo getCollectionItemInfo() { 2851 return mCollectionItemInfo; 2852 } 2853 2854 /** 2855 * Sets the collection item info if the node is a collection item. A collection 2856 * item is always a child of a collection. 2857 * <p> 2858 * <strong>Note:</strong> Cannot be called from an 2859 * {@link android.accessibilityservice.AccessibilityService}. 2860 * This class is made immutable before being delivered to an AccessibilityService. 2861 * </p> 2862 */ setCollectionItemInfo(CollectionItemInfo collectionItemInfo)2863 public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) { 2864 enforceNotSealed(); 2865 mCollectionItemInfo = collectionItemInfo; 2866 } 2867 2868 /** 2869 * Gets the range info if this node is a range. 2870 * 2871 * @return The range. 2872 */ getRangeInfo()2873 public RangeInfo getRangeInfo() { 2874 return mRangeInfo; 2875 } 2876 2877 /** 2878 * Sets the range info if this node is a range. 2879 * <p> 2880 * <strong>Note:</strong> Cannot be called from an 2881 * {@link android.accessibilityservice.AccessibilityService}. 2882 * This class is made immutable before being delivered to an AccessibilityService. 2883 * </p> 2884 * 2885 * @param rangeInfo The range info. 2886 */ setRangeInfo(RangeInfo rangeInfo)2887 public void setRangeInfo(RangeInfo rangeInfo) { 2888 enforceNotSealed(); 2889 mRangeInfo = rangeInfo; 2890 } 2891 2892 /** 2893 * Gets the {@link ExtraRenderingInfo extra rendering info} if the node is meant to be 2894 * refreshed with extra data to examine rendering related accessibility issues. 2895 * 2896 * @return The {@link ExtraRenderingInfo extra rendering info}. 2897 * 2898 * @see #EXTRA_DATA_RENDERING_INFO_KEY 2899 * @see #refreshWithExtraData(String, Bundle) 2900 */ 2901 @Nullable getExtraRenderingInfo()2902 public ExtraRenderingInfo getExtraRenderingInfo() { 2903 return mExtraRenderingInfo; 2904 } 2905 2906 /** 2907 * Sets the extra rendering info, <code>extraRenderingInfo<code/>, if the node is meant to be 2908 * refreshed with extra data. 2909 * <p> 2910 * <strong>Note:</strong> Cannot be called from an 2911 * {@link android.accessibilityservice.AccessibilityService}. 2912 * This class is made immutable before being delivered to an AccessibilityService. 2913 * </p> 2914 * 2915 * @param extraRenderingInfo The {@link ExtraRenderingInfo extra rendering info}. 2916 * @hide 2917 */ setExtraRenderingInfo(@onNull ExtraRenderingInfo extraRenderingInfo)2918 public void setExtraRenderingInfo(@NonNull ExtraRenderingInfo extraRenderingInfo) { 2919 enforceNotSealed(); 2920 mExtraRenderingInfo = extraRenderingInfo; 2921 } 2922 2923 /** 2924 * Gets if the content of this node is invalid. For example, 2925 * a date is not well-formed. 2926 * 2927 * @return If the node content is invalid. 2928 */ isContentInvalid()2929 public boolean isContentInvalid() { 2930 return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID); 2931 } 2932 2933 /** 2934 * Sets if the content of this node is invalid. For example, 2935 * a date is not well-formed. 2936 * <p> 2937 * <strong>Note:</strong> Cannot be called from an 2938 * {@link android.accessibilityservice.AccessibilityService}. 2939 * This class is made immutable before being delivered to an AccessibilityService. 2940 * </p> 2941 * 2942 * @param contentInvalid If the node content is invalid. 2943 */ setContentInvalid(boolean contentInvalid)2944 public void setContentInvalid(boolean contentInvalid) { 2945 setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid); 2946 } 2947 2948 /** 2949 * Gets whether this node is context clickable. 2950 * 2951 * @return True if the node is context clickable. 2952 */ isContextClickable()2953 public boolean isContextClickable() { 2954 return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE); 2955 } 2956 2957 /** 2958 * Sets whether this node is context clickable. 2959 * <p> 2960 * <strong>Note:</strong> Cannot be called from an 2961 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable 2962 * before being delivered to an AccessibilityService. 2963 * </p> 2964 * 2965 * @param contextClickable True if the node is context clickable. 2966 * @throws IllegalStateException If called from an AccessibilityService. 2967 */ setContextClickable(boolean contextClickable)2968 public void setContextClickable(boolean contextClickable) { 2969 setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable); 2970 } 2971 2972 /** 2973 * Gets the node's live region mode. 2974 * <p> 2975 * A live region is a node that contains information that is important for 2976 * the user and when it changes the user should be notified. For example, 2977 * a Snackbar that displays a confirmation notification should be marked 2978 * as a live region with mode 2979 * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}. 2980 * <p> 2981 * It is the responsibility of the accessibility service to monitor 2982 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating 2983 * changes to live region nodes and their children. 2984 * 2985 * @return The live region mode, or 2986 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a 2987 * live region. 2988 * @see android.view.View#getAccessibilityLiveRegion() 2989 */ getLiveRegion()2990 public int getLiveRegion() { 2991 return mLiveRegion; 2992 } 2993 2994 /** 2995 * Sets the node's live region mode. 2996 * <p> 2997 * <strong>Note:</strong> Cannot be called from an 2998 * {@link android.accessibilityservice.AccessibilityService}. This class is 2999 * made immutable before being delivered to an AccessibilityService. 3000 * 3001 * @param mode The live region mode, or 3002 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a 3003 * live region. 3004 * @see android.view.View#setAccessibilityLiveRegion(int) 3005 */ setLiveRegion(int mode)3006 public void setLiveRegion(int mode) { 3007 enforceNotSealed(); 3008 mLiveRegion = mode; 3009 } 3010 3011 /** 3012 * Gets if the node is a multi line editable text. 3013 * 3014 * @return True if the node is multi line. 3015 */ isMultiLine()3016 public boolean isMultiLine() { 3017 return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE); 3018 } 3019 3020 /** 3021 * Sets if the node is a multi line editable text. 3022 * <p> 3023 * <strong>Note:</strong> Cannot be called from an 3024 * {@link android.accessibilityservice.AccessibilityService}. 3025 * This class is made immutable before being delivered to an AccessibilityService. 3026 * </p> 3027 * 3028 * @param multiLine True if the node is multi line. 3029 */ setMultiLine(boolean multiLine)3030 public void setMultiLine(boolean multiLine) { 3031 setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine); 3032 } 3033 3034 /** 3035 * Gets if this node opens a popup or a dialog. 3036 * 3037 * @return If the the node opens a popup. 3038 */ canOpenPopup()3039 public boolean canOpenPopup() { 3040 return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP); 3041 } 3042 3043 /** 3044 * Sets if this node opens a popup or a dialog. 3045 * <p> 3046 * <strong>Note:</strong> Cannot be called from an 3047 * {@link android.accessibilityservice.AccessibilityService}. 3048 * This class is made immutable before being delivered to an AccessibilityService. 3049 * </p> 3050 * 3051 * @param opensPopup If the the node opens a popup. 3052 */ setCanOpenPopup(boolean opensPopup)3053 public void setCanOpenPopup(boolean opensPopup) { 3054 enforceNotSealed(); 3055 setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup); 3056 } 3057 3058 /** 3059 * Gets if the node can be dismissed. 3060 * 3061 * @return If the node can be dismissed. 3062 */ isDismissable()3063 public boolean isDismissable() { 3064 return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE); 3065 } 3066 3067 /** 3068 * Sets if the node can be dismissed. 3069 * <p> 3070 * <strong>Note:</strong> Cannot be called from an 3071 * {@link android.accessibilityservice.AccessibilityService}. 3072 * This class is made immutable before being delivered to an AccessibilityService. 3073 * </p> 3074 * 3075 * @param dismissable If the node can be dismissed. 3076 */ setDismissable(boolean dismissable)3077 public void setDismissable(boolean dismissable) { 3078 setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable); 3079 } 3080 3081 /** 3082 * Returns whether the node originates from a view considered important for accessibility. 3083 * 3084 * @return {@code true} if the node originates from a view considered important for 3085 * accessibility, {@code false} otherwise 3086 * 3087 * @see View#isImportantForAccessibility() 3088 */ isImportantForAccessibility()3089 public boolean isImportantForAccessibility() { 3090 return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE); 3091 } 3092 3093 /** 3094 * Sets whether the node is considered important for accessibility. 3095 * <p> 3096 * <strong>Note:</strong> Cannot be called from an 3097 * {@link android.accessibilityservice.AccessibilityService}. 3098 * This class is made immutable before being delivered to an AccessibilityService. 3099 * </p> 3100 * 3101 * @param important {@code true} if the node is considered important for accessibility, 3102 * {@code false} otherwise 3103 */ setImportantForAccessibility(boolean important)3104 public void setImportantForAccessibility(boolean important) { 3105 setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important); 3106 } 3107 3108 /** 3109 * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note 3110 * that {@code false} indicates that it is not explicitly marked, not that the node is not 3111 * a focusable unit. Screen readers should generally use other signals, such as 3112 * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive 3113 * focus. 3114 * 3115 * @return {@code true} if the node is specifically marked as a focusable unit for screen 3116 * readers, {@code false} otherwise. 3117 * 3118 * @see View#isScreenReaderFocusable() 3119 */ isScreenReaderFocusable()3120 public boolean isScreenReaderFocusable() { 3121 return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE); 3122 } 3123 3124 /** 3125 * Sets whether the node should be considered a focusable unit by a screen reader. 3126 * <p> 3127 * <strong>Note:</strong> Cannot be called from an 3128 * {@link android.accessibilityservice.AccessibilityService}. 3129 * This class is made immutable before being delivered to an AccessibilityService. 3130 * </p> 3131 * <p>This can be used to 3132 * <a href="{@docRoot}guide/topics/ui/accessibility/principles#content-groups">group related 3133 * content.</a> 3134 * </p> 3135 * 3136 * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers, 3137 * {@code false} otherwise. 3138 */ setScreenReaderFocusable(boolean screenReaderFocusable)3139 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 3140 setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 3141 } 3142 3143 /** 3144 * Returns whether the node's text represents a hint for the user to enter text. It should only 3145 * be {@code true} if the node has editable text. 3146 * 3147 * @return {@code true} if the text in the node represents a hint to the user, {@code false} 3148 * otherwise. 3149 */ isShowingHintText()3150 public boolean isShowingHintText() { 3151 return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT); 3152 } 3153 3154 /** 3155 * Sets whether the node's text represents a hint for the user to enter text. It should only 3156 * be {@code true} if the node has editable text. 3157 * <p> 3158 * <strong>Note:</strong> Cannot be called from an 3159 * {@link android.accessibilityservice.AccessibilityService}. 3160 * This class is made immutable before being delivered to an AccessibilityService. 3161 * </p> 3162 * 3163 * @param showingHintText {@code true} if the text in the node represents a hint to the user, 3164 * {@code false} otherwise. 3165 */ setShowingHintText(boolean showingHintText)3166 public void setShowingHintText(boolean showingHintText) { 3167 setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText); 3168 } 3169 3170 /** 3171 * Returns whether node represents a heading. 3172 * <p><strong>Note:</strong> Returns {@code true} if either {@link #setHeading(boolean)} 3173 * marks this node as a heading or if the node has a {@link CollectionItemInfo} that marks 3174 * it as such, to accomodate apps that use the now-deprecated API.</p> 3175 * 3176 * @return {@code true} if the node is a heading, {@code false} otherwise. 3177 */ isHeading()3178 public boolean isHeading() { 3179 if (getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING)) return true; 3180 CollectionItemInfo itemInfo = getCollectionItemInfo(); 3181 return ((itemInfo != null) && itemInfo.mHeading); 3182 } 3183 3184 /** 3185 * Sets whether the node represents a heading. 3186 * 3187 * <p> 3188 * <strong>Note:</strong> Cannot be called from an 3189 * {@link android.accessibilityservice.AccessibilityService}. 3190 * This class is made immutable before being delivered to an AccessibilityService. 3191 * </p> 3192 * 3193 * @param isHeading {@code true} if the node is a heading, {@code false} otherwise. 3194 */ setHeading(boolean isHeading)3195 public void setHeading(boolean isHeading) { 3196 setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading); 3197 } 3198 3199 /** 3200 * Returns whether node represents a text entry key that is part of a keyboard or keypad. 3201 * 3202 * @return {@code true} if the node is a text entry key., {@code false} otherwise. 3203 */ isTextEntryKey()3204 public boolean isTextEntryKey() { 3205 return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY); 3206 } 3207 3208 /** 3209 * Sets whether the node represents a text entry key that is part of a keyboard or keypad. 3210 * 3211 * <p> 3212 * <strong>Note:</strong> Cannot be called from an 3213 * {@link android.accessibilityservice.AccessibilityService}. 3214 * This class is made immutable before being delivered to an AccessibilityService. 3215 * </p> 3216 * 3217 * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise. 3218 */ setTextEntryKey(boolean isTextEntryKey)3219 public void setTextEntryKey(boolean isTextEntryKey) { 3220 setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey); 3221 } 3222 3223 /** 3224 * Gets the package this node comes from. 3225 * 3226 * @return The package name. 3227 */ getPackageName()3228 public CharSequence getPackageName() { 3229 return mPackageName; 3230 } 3231 3232 /** 3233 * Sets the package this node comes from. 3234 * <p> 3235 * <strong>Note:</strong> Cannot be called from an 3236 * {@link android.accessibilityservice.AccessibilityService}. 3237 * This class is made immutable before being delivered to an AccessibilityService. 3238 * </p> 3239 * 3240 * @param packageName The package name. 3241 * 3242 * @throws IllegalStateException If called from an AccessibilityService. 3243 */ setPackageName(CharSequence packageName)3244 public void setPackageName(CharSequence packageName) { 3245 enforceNotSealed(); 3246 mPackageName = packageName; 3247 } 3248 3249 /** 3250 * Gets the class this node comes from. 3251 * 3252 * @return The class name. 3253 */ getClassName()3254 public CharSequence getClassName() { 3255 return mClassName; 3256 } 3257 3258 /** 3259 * Sets the class this node comes from. 3260 * <p> 3261 * <strong>Note:</strong> Cannot be called from an 3262 * {@link android.accessibilityservice.AccessibilityService}. 3263 * This class is made immutable before being delivered to an AccessibilityService. 3264 * </p> 3265 * 3266 * @param className The class name. 3267 * 3268 * @throws IllegalStateException If called from an AccessibilityService. 3269 */ setClassName(CharSequence className)3270 public void setClassName(CharSequence className) { 3271 enforceNotSealed(); 3272 mClassName = className; 3273 } 3274 3275 /** 3276 * Gets the text of this node. 3277 * <p> 3278 * <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s, 3279 * these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)} 3280 * can be called from an {@link AccessibilityService}. When called from a service, the 3281 * {@link View} argument is ignored and the corresponding span will be found on the view that 3282 * this {@code AccessibilityNodeInfo} represents and called with that view as its argument. 3283 * <p> 3284 * This treatment of {@link ClickableSpan}s means that the text returned from this method may 3285 * different slightly one passed to {@link #setText(CharSequence)}, although they will be 3286 * equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The 3287 * {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside 3288 * of an accessibility service. 3289 * </p> 3290 * 3291 * @return The text. 3292 */ getText()3293 public CharSequence getText() { 3294 // Attach this node to any spans that need it 3295 if (mText instanceof Spanned) { 3296 Spanned spanned = (Spanned) mText; 3297 AccessibilityClickableSpan[] clickableSpans = 3298 spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class); 3299 for (int i = 0; i < clickableSpans.length; i++) { 3300 clickableSpans[i].copyConnectionDataFrom(this); 3301 } 3302 AccessibilityURLSpan[] urlSpans = 3303 spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class); 3304 for (int i = 0; i < urlSpans.length; i++) { 3305 urlSpans[i].copyConnectionDataFrom(this); 3306 } 3307 } 3308 return mText; 3309 } 3310 3311 /** 3312 * Get the text passed to setText before any changes to the spans. 3313 * @hide 3314 */ getOriginalText()3315 public CharSequence getOriginalText() { 3316 return mOriginalText; 3317 } 3318 3319 /** 3320 * Sets the text of this node. 3321 * <p> 3322 * <strong>Note:</strong> Cannot be called from an 3323 * {@link android.accessibilityservice.AccessibilityService}. 3324 * This class is made immutable before being delivered to an AccessibilityService. 3325 * </p> 3326 * 3327 * @param text The text. 3328 * 3329 * @throws IllegalStateException If called from an AccessibilityService. 3330 */ setText(CharSequence text)3331 public void setText(CharSequence text) { 3332 enforceNotSealed(); 3333 mOriginalText = text; 3334 if (text instanceof Spanned) { 3335 CharSequence tmpText = text; 3336 tmpText = replaceClickableSpan(tmpText); 3337 tmpText = replaceReplacementSpan(tmpText); 3338 mText = tmpText; 3339 return; 3340 } 3341 mText = (text == null) ? null : text.subSequence(0, text.length()); 3342 } 3343 3344 /** 3345 * Replaces any ClickableSpan in the given {@code text} with placeholders. 3346 * 3347 * @param text The text. 3348 * 3349 * @return The spannable with ClickableSpan replacement. 3350 */ replaceClickableSpan(CharSequence text)3351 private CharSequence replaceClickableSpan(CharSequence text) { 3352 ClickableSpan[] clickableSpans = 3353 ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class); 3354 Spannable spannable = new SpannableStringBuilder(text); 3355 if (clickableSpans.length == 0) { 3356 return text; 3357 } 3358 for (int i = 0; i < clickableSpans.length; i++) { 3359 ClickableSpan span = clickableSpans[i]; 3360 if ((span instanceof AccessibilityClickableSpan) 3361 || (span instanceof AccessibilityURLSpan)) { 3362 // We've already done enough 3363 break; 3364 } 3365 int spanToReplaceStart = spannable.getSpanStart(span); 3366 int spanToReplaceEnd = spannable.getSpanEnd(span); 3367 int spanToReplaceFlags = spannable.getSpanFlags(span); 3368 if (spanToReplaceStart < 0) { 3369 continue; 3370 } 3371 spannable.removeSpan(span); 3372 ClickableSpan replacementSpan = (span instanceof URLSpan) 3373 ? new AccessibilityURLSpan((URLSpan) span) 3374 : new AccessibilityClickableSpan(span.getId()); 3375 spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd, 3376 spanToReplaceFlags); 3377 } 3378 return spannable; 3379 } 3380 3381 /** 3382 * Replaces any ReplacementSpan in the given {@code text} if the object has content description. 3383 * 3384 * @param text The text. 3385 * 3386 * @return The spannable with ReplacementSpan replacement. 3387 */ replaceReplacementSpan(CharSequence text)3388 private CharSequence replaceReplacementSpan(CharSequence text) { 3389 ReplacementSpan[] replacementSpans = 3390 ((Spanned) text).getSpans(0, text.length(), ReplacementSpan.class); 3391 SpannableStringBuilder spannable = new SpannableStringBuilder(text); 3392 if (replacementSpans.length == 0) { 3393 return text; 3394 } 3395 for (int i = 0; i < replacementSpans.length; i++) { 3396 ReplacementSpan span = replacementSpans[i]; 3397 CharSequence replacementText = span.getContentDescription(); 3398 if (span instanceof AccessibilityReplacementSpan) { 3399 // We've already done enough 3400 break; 3401 } 3402 if (replacementText == null) { 3403 continue; 3404 } 3405 int spanToReplaceStart = spannable.getSpanStart(span); 3406 int spanToReplaceEnd = spannable.getSpanEnd(span); 3407 int spanToReplaceFlags = spannable.getSpanFlags(span); 3408 if (spanToReplaceStart < 0) { 3409 continue; 3410 } 3411 spannable.removeSpan(span); 3412 ReplacementSpan replacementSpan = new AccessibilityReplacementSpan(replacementText); 3413 spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd, 3414 spanToReplaceFlags); 3415 } 3416 return spannable; 3417 } 3418 3419 /** 3420 * Gets the hint text of this node. Only applies to nodes where text can be entered. 3421 * 3422 * @return The hint text. 3423 */ getHintText()3424 public CharSequence getHintText() { 3425 return mHintText; 3426 } 3427 3428 /** 3429 * Sets the hint text of this node. Only applies to nodes where text can be entered. 3430 * <p> 3431 * <strong>Note:</strong> Cannot be called from an 3432 * {@link android.accessibilityservice.AccessibilityService}. 3433 * This class is made immutable before being delivered to an AccessibilityService. 3434 * </p> 3435 * 3436 * @param hintText The hint text for this mode. 3437 * 3438 * @throws IllegalStateException If called from an AccessibilityService. 3439 */ setHintText(CharSequence hintText)3440 public void setHintText(CharSequence hintText) { 3441 enforceNotSealed(); 3442 mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length()); 3443 } 3444 3445 /** 3446 * Sets the error text of this node. 3447 * <p> 3448 * <strong>Note:</strong> Cannot be called from an 3449 * {@link android.accessibilityservice.AccessibilityService}. 3450 * This class is made immutable before being delivered to an AccessibilityService. 3451 * </p> 3452 * 3453 * @param error The error text. 3454 * 3455 * @throws IllegalStateException If called from an AccessibilityService. 3456 */ setError(CharSequence error)3457 public void setError(CharSequence error) { 3458 enforceNotSealed(); 3459 mError = (error == null) ? null : error.subSequence(0, error.length()); 3460 } 3461 3462 /** 3463 * Gets the error text of this node. 3464 * 3465 * @return The error text. 3466 */ getError()3467 public CharSequence getError() { 3468 return mError; 3469 } 3470 3471 /** 3472 * Get the state description of this node. 3473 * 3474 * @return the state description 3475 */ getStateDescription()3476 public @Nullable CharSequence getStateDescription() { 3477 return mStateDescription; 3478 } 3479 3480 /** 3481 * Gets the content description of this node. 3482 * 3483 * @return The content description. 3484 */ getContentDescription()3485 public CharSequence getContentDescription() { 3486 return mContentDescription; 3487 } 3488 3489 3490 /** 3491 * Sets the state description of this node. 3492 * <p> 3493 * <strong>Note:</strong> Cannot be called from an 3494 * {@link android.accessibilityservice.AccessibilityService}. 3495 * This class is made immutable before being delivered to an AccessibilityService. 3496 * </p> 3497 * 3498 * @param stateDescription the state description of this node. 3499 * 3500 * @throws IllegalStateException If called from an AccessibilityService. 3501 */ setStateDescription(@ullable CharSequence stateDescription)3502 public void setStateDescription(@Nullable CharSequence stateDescription) { 3503 enforceNotSealed(); 3504 mStateDescription = (stateDescription == null) ? null 3505 : stateDescription.subSequence(0, stateDescription.length()); 3506 } 3507 3508 /** 3509 * Sets the content description of this node. 3510 * <p> 3511 * <strong>Note:</strong> Cannot be called from an 3512 * {@link android.accessibilityservice.AccessibilityService}. 3513 * This class is made immutable before being delivered to an AccessibilityService. 3514 * </p> 3515 * 3516 * @param contentDescription The content description. 3517 * 3518 * @throws IllegalStateException If called from an AccessibilityService. 3519 */ setContentDescription(CharSequence contentDescription)3520 public void setContentDescription(CharSequence contentDescription) { 3521 enforceNotSealed(); 3522 mContentDescription = (contentDescription == null) ? null 3523 : contentDescription.subSequence(0, contentDescription.length()); 3524 } 3525 3526 /** 3527 * Gets the tooltip text of this node. 3528 * 3529 * @return The tooltip text. 3530 */ 3531 @Nullable getTooltipText()3532 public CharSequence getTooltipText() { 3533 return mTooltipText; 3534 } 3535 3536 /** 3537 * Sets the tooltip text of this node. 3538 * <p> 3539 * <strong>Note:</strong> Cannot be called from an 3540 * {@link android.accessibilityservice.AccessibilityService}. 3541 * This class is made immutable before being delivered to an AccessibilityService. 3542 * </p> 3543 * 3544 * @param tooltipText The tooltip text. 3545 * 3546 * @throws IllegalStateException If called from an AccessibilityService. 3547 */ setTooltipText(@ullable CharSequence tooltipText)3548 public void setTooltipText(@Nullable CharSequence tooltipText) { 3549 enforceNotSealed(); 3550 mTooltipText = (tooltipText == null) ? null 3551 : tooltipText.subSequence(0, tooltipText.length()); 3552 } 3553 3554 /** 3555 * Sets the view for which the view represented by this info serves as a 3556 * label for accessibility purposes. 3557 * 3558 * @param labeled The view for which this info serves as a label. 3559 */ setLabelFor(View labeled)3560 public void setLabelFor(View labeled) { 3561 setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID); 3562 } 3563 3564 /** 3565 * Sets the view for which the view represented by this info serves as a 3566 * label for accessibility purposes. If <code>virtualDescendantId</code> 3567 * is {@link View#NO_ID} the root is set as the labeled. 3568 * <p> 3569 * A virtual descendant is an imaginary View that is reported as a part of the view 3570 * hierarchy for accessibility purposes. This enables custom views that draw complex 3571 * content to report themselves as a tree of virtual views, thus conveying their 3572 * logical structure. 3573 * </p> 3574 * <p> 3575 * <strong>Note:</strong> Cannot be called from an 3576 * {@link android.accessibilityservice.AccessibilityService}. 3577 * This class is made immutable before being delivered to an AccessibilityService. 3578 * </p> 3579 * 3580 * @param root The root whose virtual descendant serves as a label. 3581 * @param virtualDescendantId The id of the virtual descendant. 3582 */ setLabelFor(View root, int virtualDescendantId)3583 public void setLabelFor(View root, int virtualDescendantId) { 3584 enforceNotSealed(); 3585 final int rootAccessibilityViewId = (root != null) 3586 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 3587 mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 3588 } 3589 3590 /** 3591 * Gets the node info for which the view represented by this info serves as 3592 * a label for accessibility purposes. 3593 * 3594 * @return The labeled info. 3595 */ getLabelFor()3596 public AccessibilityNodeInfo getLabelFor() { 3597 enforceSealed(); 3598 return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId); 3599 } 3600 3601 /** 3602 * Sets the view which serves as the label of the view represented by 3603 * this info for accessibility purposes. 3604 * 3605 * @param label The view that labels this node's source. 3606 */ setLabeledBy(View label)3607 public void setLabeledBy(View label) { 3608 setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID); 3609 } 3610 3611 /** 3612 * Sets the view which serves as the label of the view represented by 3613 * this info for accessibility purposes. If <code>virtualDescendantId</code> 3614 * is {@link View#NO_ID} the root is set as the label. 3615 * <p> 3616 * A virtual descendant is an imaginary View that is reported as a part of the view 3617 * hierarchy for accessibility purposes. This enables custom views that draw complex 3618 * content to report themselves as a tree of virtual views, thus conveying their 3619 * logical structure. 3620 * </p> 3621 * <p> 3622 * <strong>Note:</strong> Cannot be called from an 3623 * {@link android.accessibilityservice.AccessibilityService}. 3624 * This class is made immutable before being delivered to an AccessibilityService. 3625 * </p> 3626 * 3627 * @param root The root whose virtual descendant labels this node's source. 3628 * @param virtualDescendantId The id of the virtual descendant. 3629 */ setLabeledBy(View root, int virtualDescendantId)3630 public void setLabeledBy(View root, int virtualDescendantId) { 3631 enforceNotSealed(); 3632 final int rootAccessibilityViewId = (root != null) 3633 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 3634 mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 3635 } 3636 3637 /** 3638 * Gets the node info which serves as the label of the view represented by 3639 * this info for accessibility purposes. 3640 * 3641 * @return The label. 3642 */ getLabeledBy()3643 public AccessibilityNodeInfo getLabeledBy() { 3644 enforceSealed(); 3645 return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById); 3646 } 3647 3648 /** 3649 * Sets the fully qualified resource name of the source view's id. 3650 * 3651 * <p> 3652 * <strong>Note:</strong> Cannot be called from an 3653 * {@link android.accessibilityservice.AccessibilityService}. 3654 * This class is made immutable before being delivered to an AccessibilityService. 3655 * </p> 3656 * 3657 * @param viewIdResName The id resource name. 3658 */ setViewIdResourceName(String viewIdResName)3659 public void setViewIdResourceName(String viewIdResName) { 3660 enforceNotSealed(); 3661 mViewIdResourceName = viewIdResName; 3662 } 3663 3664 /** 3665 * Gets the fully qualified resource name of the source view's id. 3666 * 3667 * <p> 3668 * <strong>Note:</strong> The primary usage of this API is for UI test automation 3669 * and in order to report the source view id of an {@link AccessibilityNodeInfo} the 3670 * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} 3671 * flag when configuring the {@link android.accessibilityservice.AccessibilityService}. 3672 * </p> 3673 3674 * @return The id resource name. 3675 */ getViewIdResourceName()3676 public String getViewIdResourceName() { 3677 return mViewIdResourceName; 3678 } 3679 3680 /** 3681 * Gets the text selection start or the cursor position. 3682 * <p> 3683 * If no text is selected, both this method and 3684 * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value: 3685 * the current location of the cursor. 3686 * </p> 3687 * 3688 * @return The text selection start, the cursor location if there is no selection, or -1 if 3689 * there is no text selection and no cursor. 3690 */ getTextSelectionStart()3691 public int getTextSelectionStart() { 3692 return mTextSelectionStart; 3693 } 3694 3695 /** 3696 * Gets the text selection end if text is selected. 3697 * <p> 3698 * If no text is selected, both this method and 3699 * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value: 3700 * the current location of the cursor. 3701 * </p> 3702 * 3703 * @return The text selection end, the cursor location if there is no selection, or -1 if 3704 * there is no text selection and no cursor. 3705 */ getTextSelectionEnd()3706 public int getTextSelectionEnd() { 3707 return mTextSelectionEnd; 3708 } 3709 3710 /** 3711 * Sets the text selection start and end. 3712 * <p> 3713 * <strong>Note:</strong> Cannot be called from an 3714 * {@link android.accessibilityservice.AccessibilityService}. 3715 * This class is made immutable before being delivered to an AccessibilityService. 3716 * </p> 3717 * 3718 * @param start The text selection start. 3719 * @param end The text selection end. 3720 * 3721 * @throws IllegalStateException If called from an AccessibilityService. 3722 */ setTextSelection(int start, int end)3723 public void setTextSelection(int start, int end) { 3724 enforceNotSealed(); 3725 mTextSelectionStart = start; 3726 mTextSelectionEnd = end; 3727 } 3728 3729 /** 3730 * Gets the input type of the source as defined by {@link InputType}. 3731 * 3732 * @return The input type. 3733 */ getInputType()3734 public int getInputType() { 3735 return mInputType; 3736 } 3737 3738 /** 3739 * Sets the input type of the source as defined by {@link InputType}. 3740 * <p> 3741 * <strong>Note:</strong> Cannot be called from an 3742 * {@link android.accessibilityservice.AccessibilityService}. 3743 * This class is made immutable before being delivered to an 3744 * AccessibilityService. 3745 * </p> 3746 * 3747 * @param inputType The input type. 3748 * 3749 * @throws IllegalStateException If called from an AccessibilityService. 3750 */ setInputType(int inputType)3751 public void setInputType(int inputType) { 3752 enforceNotSealed(); 3753 mInputType = inputType; 3754 } 3755 3756 /** 3757 * Gets an optional bundle with extra data. The bundle 3758 * is lazily created and never <code>null</code>. 3759 * <p> 3760 * <strong>Note:</strong> It is recommended to use the package 3761 * name of your application as a prefix for the keys to avoid 3762 * collisions which may confuse an accessibility service if the 3763 * same key has different meaning when emitted from different 3764 * applications. 3765 * </p> 3766 * 3767 * @return The bundle. 3768 */ getExtras()3769 public Bundle getExtras() { 3770 if (mExtras == null) { 3771 mExtras = new Bundle(); 3772 } 3773 return mExtras; 3774 } 3775 3776 /** 3777 * Check if a node has an extras bundle 3778 * @hide 3779 */ hasExtras()3780 public boolean hasExtras() { 3781 return mExtras != null; 3782 } 3783 3784 /** 3785 * Get the {@link TouchDelegateInfo} for touch delegate behavior with the represented view. 3786 * It is possible for the same node to be pointed to by several regions. Use 3787 * {@link TouchDelegateInfo#getRegionAt(int)} to get touch delegate target {@link Region}, and 3788 * {@link TouchDelegateInfo#getTargetForRegion(Region)} for {@link AccessibilityNodeInfo} from 3789 * the given region. 3790 * 3791 * @return {@link TouchDelegateInfo} or {@code null} if there are no touch delegates. 3792 */ 3793 @Nullable getTouchDelegateInfo()3794 public TouchDelegateInfo getTouchDelegateInfo() { 3795 if (mTouchDelegateInfo != null) { 3796 mTouchDelegateInfo.setConnectionId(mConnectionId); 3797 mTouchDelegateInfo.setWindowId(mWindowId); 3798 } 3799 return mTouchDelegateInfo; 3800 } 3801 3802 /** 3803 * Set touch delegate info if the represented view has a {@link TouchDelegate}. 3804 * <p> 3805 * <strong>Note:</strong> Cannot be called from an 3806 * {@link android.accessibilityservice.AccessibilityService}. 3807 * This class is made immutable before being delivered to an 3808 * AccessibilityService. 3809 * </p> 3810 * 3811 * @param delegatedInfo {@link TouchDelegateInfo} returned from 3812 * {@link TouchDelegate#getTouchDelegateInfo()}. 3813 * 3814 * @throws IllegalStateException If called from an AccessibilityService. 3815 */ setTouchDelegateInfo(@onNull TouchDelegateInfo delegatedInfo)3816 public void setTouchDelegateInfo(@NonNull TouchDelegateInfo delegatedInfo) { 3817 enforceNotSealed(); 3818 mTouchDelegateInfo = delegatedInfo; 3819 } 3820 3821 /** 3822 * Gets the value of a boolean property. 3823 * 3824 * @param property The property. 3825 * @return The value. 3826 */ getBooleanProperty(int property)3827 private boolean getBooleanProperty(int property) { 3828 return (mBooleanProperties & property) != 0; 3829 } 3830 3831 /** 3832 * Sets a boolean property. 3833 * 3834 * @param property The property. 3835 * @param value The value. 3836 * 3837 * @throws IllegalStateException If called from an AccessibilityService. 3838 */ setBooleanProperty(int property, boolean value)3839 private void setBooleanProperty(int property, boolean value) { 3840 enforceNotSealed(); 3841 if (value) { 3842 mBooleanProperties |= property; 3843 } else { 3844 mBooleanProperties &= ~property; 3845 } 3846 } 3847 3848 /** 3849 * Sets the unique id of the IAccessibilityServiceConnection over which 3850 * this instance can send requests to the system. 3851 * 3852 * @param connectionId The connection id. 3853 * 3854 * @hide 3855 */ setConnectionId(int connectionId)3856 public void setConnectionId(int connectionId) { 3857 enforceNotSealed(); 3858 mConnectionId = connectionId; 3859 } 3860 3861 /** 3862 * Get the connection ID. 3863 * 3864 * @return The connection id 3865 * 3866 * @hide 3867 */ getConnectionId()3868 public int getConnectionId() { 3869 return mConnectionId; 3870 } 3871 3872 /** 3873 * {@inheritDoc} 3874 */ 3875 @Override describeContents()3876 public int describeContents() { 3877 return 0; 3878 } 3879 3880 /** 3881 * Sets the id of the source node. 3882 * 3883 * @param sourceId The id. 3884 * @param windowId The window id. 3885 * 3886 * @hide 3887 */ setSourceNodeId(long sourceId, int windowId)3888 public void setSourceNodeId(long sourceId, int windowId) { 3889 enforceNotSealed(); 3890 mSourceNodeId = sourceId; 3891 mWindowId = windowId; 3892 } 3893 3894 /** 3895 * Gets the id of the source node. 3896 * 3897 * @return The id. 3898 * 3899 * @hide 3900 */ 3901 @UnsupportedAppUsage 3902 @TestApi getSourceNodeId()3903 public long getSourceNodeId() { 3904 return mSourceNodeId; 3905 } 3906 3907 /** 3908 * Sets the unique id to act as a key to identify the node. If the node instance is replaced 3909 * after refreshing the layout, calling this API to assign the same unique id to the new 3910 * alike node can help accessibility service to identify it. 3911 * 3912 * @param uniqueId The unique id that is associated with a visible node on the screen 3913 */ setUniqueId(@ullable String uniqueId)3914 public void setUniqueId(@Nullable String uniqueId) { 3915 enforceNotSealed(); 3916 mUniqueId = uniqueId; 3917 } 3918 3919 /** 3920 * Gets the unique id of the node. 3921 * 3922 * @return The unique id 3923 */ 3924 @Nullable getUniqueId()3925 public String getUniqueId() { 3926 return mUniqueId; 3927 } 3928 3929 /** 3930 * Sets the container title for app-developer-defined container which can be any type of 3931 * ViewGroup or layout. 3932 * Container title will be used to group together related controls, similar to HTML fieldset. 3933 * Or container title may identify a large piece of the UI that is visibly grouped together, 3934 * such as a toolbar or a card, etc. 3935 * <p> 3936 * Container title helps to assist in navigation across containers and other groups. 3937 * For example, a screen reader may use this to determine where to put accessibility focus. 3938 * </p> 3939 * <p> 3940 * Container title is different from pane title{@link #setPaneTitle} which indicates that the 3941 * node represents a window or activity. 3942 * </p> 3943 * 3944 * <p> 3945 * Example: An app can set container titles on several non-modal menus, containing TextViews 3946 * or ImageButtons that have content descriptions, text, etc. Screen readers can quickly 3947 * switch accessibility focus among menus instead of child views. Other accessibility-services 3948 * can easily find the menu. 3949 * </p> 3950 * 3951 * @param containerTitle The container title that is associated with a ViewGroup/Layout on the 3952 * screen. 3953 */ setContainerTitle(@ullable CharSequence containerTitle)3954 public void setContainerTitle(@Nullable CharSequence containerTitle) { 3955 enforceNotSealed(); 3956 mContainerTitle = (containerTitle == null) ? null 3957 : containerTitle.subSequence(0, containerTitle.length()); 3958 } 3959 3960 /** 3961 * Returns the container title. 3962 * 3963 * @see #setContainerTitle 3964 */ 3965 @Nullable getContainerTitle()3966 public CharSequence getContainerTitle() { 3967 return mContainerTitle; 3968 } 3969 3970 /** 3971 * Sets the token and node id of the leashed parent. 3972 * 3973 * @param token The token. 3974 * @param viewId The accessibility view id. 3975 * @hide 3976 */ 3977 @TestApi setLeashedParent(@ullable IBinder token, int viewId)3978 public void setLeashedParent(@Nullable IBinder token, int viewId) { 3979 enforceNotSealed(); 3980 mLeashedParent = token; 3981 mLeashedParentNodeId = makeNodeId(viewId, AccessibilityNodeProvider.HOST_VIEW_ID); 3982 } 3983 3984 /** 3985 * Gets the token of the leashed parent. 3986 * 3987 * @return The token. 3988 * @hide 3989 */ getLeashedParent()3990 public @Nullable IBinder getLeashedParent() { 3991 return mLeashedParent; 3992 } 3993 3994 /** 3995 * Gets the node id of the leashed parent. 3996 * 3997 * @return The accessibility node id. 3998 * @hide 3999 */ getLeashedParentNodeId()4000 public long getLeashedParentNodeId() { 4001 return mLeashedParentNodeId; 4002 } 4003 4004 /** 4005 * Connects this node to the View's root so that operations on this node can query the entire 4006 * {@link AccessibilityNodeInfo} tree and perform accessibility actions on nodes. 4007 * 4008 * <p> 4009 * Testing or debugging tools should create this {@link AccessibilityNodeInfo} node using 4010 * {@link View#createAccessibilityNodeInfo()} or {@link AccessibilityNodeProvider} and call this 4011 * method, then navigate and interact with the node tree by calling methods on the node. 4012 * Calling this method more than once on the same node is a no-op. After calling this method, 4013 * all nodes linked to this node (children, ancestors, etc.) are also queryable. 4014 * </p> 4015 * 4016 * <p> 4017 * Here "query" refers to the following node operations: 4018 * <li>check properties of this node (example: {@link #isScrollable()})</li> 4019 * <li>find and query children (example: {@link #getChild(int)})</li> 4020 * <li>find and query the parent (example: {@link #getParent()})</li> 4021 * <li>find focus (examples: {@link #findFocus(int)}, {@link #focusSearch(int)})</li> 4022 * <li>find and query other nodes (example: {@link #findAccessibilityNodeInfosByText(String)}, 4023 * {@link #findAccessibilityNodeInfosByViewId(String)})</li> 4024 * <li>perform actions (example: {@link #performAction(int)})</li> 4025 * </p> 4026 * 4027 * <p> 4028 * This is intended for short-lived inspections from testing or debugging tools in the app 4029 * process, as operations on this node tree will only succeed as long as the associated 4030 * view hierarchy remains attached to a window. {@link AccessibilityNodeInfo} objects can 4031 * quickly become out of sync with their corresponding {@link View} objects; if you wish to 4032 * inspect a changed or different view hierarchy then create a new node from any view in that 4033 * hierarchy and call this method on that new node, instead of disabling & re-enabling the 4034 * connection on the previous node. 4035 * </p> 4036 * 4037 * @param view The view that generated this node, or any view in the same view-root hierarchy. 4038 * @param enabled Whether to enable (true) or disable (false) querying from the app process. 4039 * @throws IllegalStateException If called from an {@link AccessibilityService}, or if provided 4040 * a {@link View} that is not attached to a window. 4041 */ setQueryFromAppProcessEnabled(@onNull View view, boolean enabled)4042 public void setQueryFromAppProcessEnabled(@NonNull View view, boolean enabled) { 4043 enforceNotSealed(); 4044 4045 if (!enabled) { 4046 setConnectionId(UNDEFINED_CONNECTION_ID); 4047 return; 4048 } 4049 4050 if (mConnectionId != UNDEFINED_CONNECTION_ID) { 4051 return; 4052 } 4053 4054 ViewRootImpl viewRootImpl = view.getViewRootImpl(); 4055 if (viewRootImpl == null) { 4056 throw new IllegalStateException( 4057 "Cannot link a node to a view that is not attached to a window."); 4058 } 4059 setConnectionId(viewRootImpl.getDirectAccessibilityConnectionId()); 4060 } 4061 4062 /** 4063 * Sets if this instance is sealed. 4064 * 4065 * @param sealed Whether is sealed. 4066 * 4067 * @hide 4068 */ 4069 @UnsupportedAppUsage setSealed(boolean sealed)4070 public void setSealed(boolean sealed) { 4071 mSealed = sealed; 4072 } 4073 4074 /** 4075 * Gets if this instance is sealed. 4076 * 4077 * @return Whether is sealed. 4078 * 4079 * @hide 4080 */ 4081 @UnsupportedAppUsage isSealed()4082 public boolean isSealed() { 4083 return mSealed; 4084 } 4085 usingDirectConnection(int connectionId)4086 private static boolean usingDirectConnection(int connectionId) { 4087 return AccessibilityInteractionClient.getConnection( 4088 connectionId) instanceof DirectAccessibilityConnection; 4089 } 4090 4091 /** 4092 * Enforces that this instance is sealed, unless using a {@link DirectAccessibilityConnection} 4093 * which allows queries while the node is not sealed. 4094 * 4095 * @throws IllegalStateException If this instance is not sealed. 4096 * 4097 * @hide 4098 */ enforceSealed()4099 protected void enforceSealed() { 4100 if (!usingDirectConnection(mConnectionId) && !isSealed()) { 4101 throw new IllegalStateException("Cannot perform this " 4102 + "action on a not sealed instance."); 4103 } 4104 } 4105 enforceValidFocusDirection(int direction)4106 private void enforceValidFocusDirection(int direction) { 4107 switch (direction) { 4108 case View.FOCUS_DOWN: 4109 case View.FOCUS_UP: 4110 case View.FOCUS_LEFT: 4111 case View.FOCUS_RIGHT: 4112 case View.FOCUS_FORWARD: 4113 case View.FOCUS_BACKWARD: 4114 return; 4115 default: 4116 throw new IllegalArgumentException("Unknown direction: " + direction); 4117 } 4118 } 4119 enforceValidFocusType(int focusType)4120 private void enforceValidFocusType(int focusType) { 4121 switch (focusType) { 4122 case FOCUS_INPUT: 4123 case FOCUS_ACCESSIBILITY: 4124 return; 4125 default: 4126 throw new IllegalArgumentException("Unknown focus type: " + focusType); 4127 } 4128 } 4129 4130 /** 4131 * Enforces that this instance is not sealed. 4132 * 4133 * @throws IllegalStateException If this instance is sealed. 4134 * 4135 * @hide 4136 */ enforceNotSealed()4137 protected void enforceNotSealed() { 4138 if (isSealed()) { 4139 throw new IllegalStateException("Cannot perform this " 4140 + "action on a sealed instance."); 4141 } 4142 } 4143 4144 /** 4145 * Returns a cached instance if such is available otherwise a new one 4146 * and sets the source. 4147 * 4148 * @deprecated Object pooling has been discontinued. Create a new instance using the 4149 * constructor {@link #AccessibilityNodeInfo(View)} instead. 4150 * @param source The source view. 4151 * @return An instance. 4152 * 4153 * @see #setSource(View) 4154 */ 4155 @Deprecated obtain(View source)4156 public static AccessibilityNodeInfo obtain(View source) { 4157 return new AccessibilityNodeInfo(source); 4158 } 4159 4160 /** 4161 * Returns a cached instance if such is available otherwise a new one 4162 * and sets the source. 4163 * 4164 * @deprecated Object pooling has been discontinued. Create a new instance using the 4165 * constructor {@link #AccessibilityNodeInfo(View, int)} instead. 4166 * 4167 * @param root The root of the virtual subtree. 4168 * @param virtualDescendantId The id of the virtual descendant. 4169 * @return An instance. 4170 * 4171 * @see #setSource(View, int) 4172 */ 4173 @Deprecated obtain(View root, int virtualDescendantId)4174 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) { 4175 return new AccessibilityNodeInfo(root, virtualDescendantId); 4176 } 4177 4178 /** 4179 * Instantiates a new AccessibilityNodeInfo. 4180 * 4181 * @deprecated Object pooling has been discontinued. Create a new instance using the 4182 * constructor {@link #AccessibilityNodeInfo()} instead. 4183 * @return An instance. 4184 */ 4185 @Deprecated obtain()4186 public static AccessibilityNodeInfo obtain() { 4187 return new AccessibilityNodeInfo(); 4188 } 4189 4190 /** 4191 * Instantiates a new AccessibilityNodeInfo initialized from the given 4192 * <code>info</code>. 4193 * 4194 * @deprecated Object pooling has been discontinued. Create a new instance using the 4195 * constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead. 4196 * @param info The other info. 4197 * @return An instance. 4198 */ 4199 @Deprecated obtain(AccessibilityNodeInfo info)4200 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { 4201 return new AccessibilityNodeInfo(info); 4202 } 4203 4204 /** 4205 * Would previously return an instance back to be reused. 4206 * 4207 * @deprecated Object pooling has been discontinued. Calling this function now will have 4208 * no effect. 4209 */ 4210 @Deprecated recycle()4211 public void recycle() {} 4212 4213 /** 4214 * {@inheritDoc} 4215 * <p> 4216 * <strong>Note:</strong> After the instance is written to a parcel it 4217 * is recycled. You must not touch the object after calling this function. 4218 * </p> 4219 */ 4220 @Override writeToParcel(Parcel parcel, int flags)4221 public void writeToParcel(Parcel parcel, int flags) { 4222 writeToParcelNoRecycle(parcel, flags); 4223 // Since instances of this class are fetched via synchronous i.e. blocking 4224 // calls in IPCs we always recycle as soon as the instance is marshaled. 4225 } 4226 4227 /** @hide */ 4228 @TestApi writeToParcelNoRecycle(Parcel parcel, int flags)4229 public void writeToParcelNoRecycle(Parcel parcel, int flags) { 4230 // Write bit set of indices of fields with values differing from default 4231 long nonDefaultFields = 0; 4232 int fieldIndex = 0; // index of the current field 4233 if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex); 4234 fieldIndex++; 4235 if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex); 4236 fieldIndex++; 4237 if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex); 4238 fieldIndex++; 4239 if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex); 4240 fieldIndex++; 4241 if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex); 4242 fieldIndex++; 4243 if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex); 4244 fieldIndex++; 4245 if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex); 4246 fieldIndex++; 4247 if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex); 4248 fieldIndex++; 4249 if (mMinDurationBetweenContentChanges 4250 != DEFAULT.mMinDurationBetweenContentChanges) { 4251 nonDefaultFields |= bitAt(fieldIndex); 4252 } 4253 fieldIndex++; 4254 if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex); 4255 fieldIndex++; 4256 if (!LongArray.elementsEqual(mChildNodeIds, DEFAULT.mChildNodeIds)) { 4257 nonDefaultFields |= bitAt(fieldIndex); 4258 } 4259 fieldIndex++; 4260 if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) { 4261 nonDefaultFields |= bitAt(fieldIndex); 4262 } 4263 fieldIndex++; 4264 if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) { 4265 nonDefaultFields |= bitAt(fieldIndex); 4266 } 4267 fieldIndex++; 4268 if (!Objects.equals(mBoundsInWindow, DEFAULT.mBoundsInWindow)) { 4269 nonDefaultFields |= bitAt(fieldIndex); 4270 } 4271 fieldIndex++; 4272 4273 if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex); 4274 fieldIndex++; 4275 if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex); 4276 fieldIndex++; 4277 if (mMovementGranularities != DEFAULT.mMovementGranularities) { 4278 nonDefaultFields |= bitAt(fieldIndex); 4279 } 4280 fieldIndex++; 4281 if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex); 4282 fieldIndex++; 4283 if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) { 4284 nonDefaultFields |= bitAt(fieldIndex); 4285 } 4286 fieldIndex++; 4287 if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex); 4288 fieldIndex++; 4289 if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex); 4290 fieldIndex++; 4291 if (!Objects.equals(mHintText, DEFAULT.mHintText)) { 4292 nonDefaultFields |= bitAt(fieldIndex); 4293 } 4294 fieldIndex++; 4295 if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex); 4296 fieldIndex++; 4297 if (!Objects.equals(mStateDescription, DEFAULT.mStateDescription)) { 4298 nonDefaultFields |= bitAt(fieldIndex); 4299 } 4300 fieldIndex++; 4301 if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) { 4302 nonDefaultFields |= bitAt(fieldIndex); 4303 } 4304 fieldIndex++; 4305 if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) { 4306 nonDefaultFields |= bitAt(fieldIndex); 4307 } 4308 fieldIndex++; 4309 if (!Objects.equals(mTooltipText, DEFAULT.mTooltipText)) { 4310 nonDefaultFields |= bitAt(fieldIndex); 4311 } 4312 fieldIndex++; 4313 if (!Objects.equals(mContainerTitle, DEFAULT.mContainerTitle)) { 4314 nonDefaultFields |= bitAt(fieldIndex); 4315 } 4316 fieldIndex++; 4317 if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) { 4318 nonDefaultFields |= bitAt(fieldIndex); 4319 } 4320 fieldIndex++; 4321 if (!Objects.equals(mUniqueId, DEFAULT.mUniqueId)) { 4322 nonDefaultFields |= bitAt(fieldIndex); 4323 } 4324 fieldIndex++; 4325 if (mTextSelectionStart != DEFAULT.mTextSelectionStart) { 4326 nonDefaultFields |= bitAt(fieldIndex); 4327 } 4328 fieldIndex++; 4329 if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) { 4330 nonDefaultFields |= bitAt(fieldIndex); 4331 } 4332 fieldIndex++; 4333 if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex); 4334 fieldIndex++; 4335 if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex); 4336 fieldIndex++; 4337 if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) { 4338 nonDefaultFields |= bitAt(fieldIndex); 4339 } 4340 fieldIndex++; 4341 if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) { 4342 nonDefaultFields |= bitAt(fieldIndex); 4343 } 4344 fieldIndex++; 4345 if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex); 4346 fieldIndex++; 4347 if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex); 4348 fieldIndex++; 4349 if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) { 4350 nonDefaultFields |= bitAt(fieldIndex); 4351 } 4352 fieldIndex++; 4353 if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) { 4354 nonDefaultFields |= bitAt(fieldIndex); 4355 } 4356 fieldIndex++; 4357 if (!Objects.equals(mTouchDelegateInfo, DEFAULT.mTouchDelegateInfo)) { 4358 nonDefaultFields |= bitAt(fieldIndex); 4359 } 4360 fieldIndex++; 4361 if (!Objects.equals(mExtraRenderingInfo, DEFAULT.mExtraRenderingInfo)) { 4362 nonDefaultFields |= bitAt(fieldIndex); 4363 } 4364 fieldIndex++; 4365 if (mLeashedChild != DEFAULT.mLeashedChild) { 4366 nonDefaultFields |= bitAt(fieldIndex); 4367 } 4368 fieldIndex++; 4369 if (mLeashedParent != DEFAULT.mLeashedParent) { 4370 nonDefaultFields |= bitAt(fieldIndex); 4371 } 4372 fieldIndex++; 4373 if (mLeashedParentNodeId != DEFAULT.mLeashedParentNodeId) { 4374 nonDefaultFields |= bitAt(fieldIndex); 4375 } 4376 int totalFields = fieldIndex; 4377 parcel.writeLong(nonDefaultFields); 4378 4379 fieldIndex = 0; 4380 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0); 4381 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId); 4382 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId); 4383 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId); 4384 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId); 4385 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById); 4386 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore); 4387 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter); 4388 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4389 parcel.writeLong(mMinDurationBetweenContentChanges); 4390 } 4391 4392 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId); 4393 4394 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4395 final LongArray childIds = mChildNodeIds; 4396 if (childIds == null) { 4397 parcel.writeInt(0); 4398 } else { 4399 final int childIdsSize = childIds.size(); 4400 parcel.writeInt(childIdsSize); 4401 for (int i = 0; i < childIdsSize; i++) { 4402 parcel.writeLong(childIds.get(i)); 4403 } 4404 } 4405 } 4406 4407 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4408 parcel.writeInt(mBoundsInParent.top); 4409 parcel.writeInt(mBoundsInParent.bottom); 4410 parcel.writeInt(mBoundsInParent.left); 4411 parcel.writeInt(mBoundsInParent.right); 4412 } 4413 4414 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4415 parcel.writeInt(mBoundsInScreen.top); 4416 parcel.writeInt(mBoundsInScreen.bottom); 4417 parcel.writeInt(mBoundsInScreen.left); 4418 parcel.writeInt(mBoundsInScreen.right); 4419 } 4420 4421 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4422 parcel.writeInt(mBoundsInWindow.top); 4423 parcel.writeInt(mBoundsInWindow.bottom); 4424 parcel.writeInt(mBoundsInWindow.left); 4425 parcel.writeInt(mBoundsInWindow.right); 4426 } 4427 4428 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4429 if (mActions != null && !mActions.isEmpty()) { 4430 final int actionCount = mActions.size(); 4431 4432 int nonStandardActionCount = 0; 4433 long defaultStandardActions = 0; 4434 for (int i = 0; i < actionCount; i++) { 4435 AccessibilityAction action = mActions.get(i); 4436 if (isDefaultStandardAction(action)) { 4437 defaultStandardActions |= action.mSerializationFlag; 4438 } else { 4439 nonStandardActionCount++; 4440 } 4441 } 4442 parcel.writeLong(defaultStandardActions); 4443 4444 parcel.writeInt(nonStandardActionCount); 4445 for (int i = 0; i < actionCount; i++) { 4446 AccessibilityAction action = mActions.get(i); 4447 if (!isDefaultStandardAction(action)) { 4448 action.writeToParcel(parcel, flags); 4449 } 4450 } 4451 } else { 4452 parcel.writeLong(0); 4453 parcel.writeInt(0); 4454 } 4455 } 4456 4457 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength); 4458 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities); 4459 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties); 4460 4461 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName); 4462 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName); 4463 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText); 4464 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText); 4465 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError); 4466 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mStateDescription); 4467 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4468 parcel.writeCharSequence(mContentDescription); 4469 } 4470 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle); 4471 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mTooltipText); 4472 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mContainerTitle); 4473 4474 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName); 4475 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mUniqueId); 4476 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart); 4477 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd); 4478 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType); 4479 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion); 4480 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent); 4481 4482 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys); 4483 4484 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras); 4485 4486 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4487 parcel.writeInt(mRangeInfo.getType()); 4488 parcel.writeFloat(mRangeInfo.getMin()); 4489 parcel.writeFloat(mRangeInfo.getMax()); 4490 parcel.writeFloat(mRangeInfo.getCurrent()); 4491 } 4492 4493 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4494 parcel.writeInt(mCollectionInfo.getRowCount()); 4495 parcel.writeInt(mCollectionInfo.getColumnCount()); 4496 parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0); 4497 parcel.writeInt(mCollectionInfo.getSelectionMode()); 4498 parcel.writeInt(mCollectionInfo.getItemCount()); 4499 parcel.writeInt(mCollectionInfo.getImportantForAccessibilityItemCount()); 4500 } 4501 4502 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4503 parcel.writeString(mCollectionItemInfo.getRowTitle()); 4504 parcel.writeInt(mCollectionItemInfo.getRowIndex()); 4505 parcel.writeInt(mCollectionItemInfo.getRowSpan()); 4506 parcel.writeString(mCollectionItemInfo.getColumnTitle()); 4507 parcel.writeInt(mCollectionItemInfo.getColumnIndex()); 4508 parcel.writeInt(mCollectionItemInfo.getColumnSpan()); 4509 parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0); 4510 parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0); 4511 } 4512 4513 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4514 mTouchDelegateInfo.writeToParcel(parcel, flags); 4515 } 4516 4517 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4518 parcel.writeValue(mExtraRenderingInfo.getLayoutSize()); 4519 parcel.writeFloat(mExtraRenderingInfo.getTextSizeInPx()); 4520 parcel.writeInt(mExtraRenderingInfo.getTextSizeUnit()); 4521 } 4522 4523 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4524 parcel.writeStrongBinder(mLeashedChild); 4525 } 4526 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4527 parcel.writeStrongBinder(mLeashedParent); 4528 } 4529 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4530 parcel.writeLong(mLeashedParentNodeId); 4531 } 4532 4533 if (DEBUG) { 4534 fieldIndex--; 4535 if (totalFields != fieldIndex) { 4536 throw new IllegalStateException("Number of fields mismatch: " + totalFields 4537 + " vs " + fieldIndex); 4538 } 4539 } 4540 } 4541 4542 /** 4543 * Initializes this instance from another one. 4544 * 4545 * @param other The other instance. 4546 */ init(AccessibilityNodeInfo other)4547 private void init(AccessibilityNodeInfo other) { 4548 mSealed = other.mSealed; 4549 mSourceNodeId = other.mSourceNodeId; 4550 mParentNodeId = other.mParentNodeId; 4551 mLabelForId = other.mLabelForId; 4552 mLabeledById = other.mLabeledById; 4553 mTraversalBefore = other.mTraversalBefore; 4554 mTraversalAfter = other.mTraversalAfter; 4555 mMinDurationBetweenContentChanges = other.mMinDurationBetweenContentChanges; 4556 mWindowId = other.mWindowId; 4557 mConnectionId = other.mConnectionId; 4558 mUniqueId = other.mUniqueId; 4559 mBoundsInParent.set(other.mBoundsInParent); 4560 mBoundsInScreen.set(other.mBoundsInScreen); 4561 mBoundsInWindow.set(other.mBoundsInWindow); 4562 mPackageName = other.mPackageName; 4563 mClassName = other.mClassName; 4564 mText = other.mText; 4565 mOriginalText = other.mOriginalText; 4566 mHintText = other.mHintText; 4567 mError = other.mError; 4568 mStateDescription = other.mStateDescription; 4569 mContentDescription = other.mContentDescription; 4570 mPaneTitle = other.mPaneTitle; 4571 mTooltipText = other.mTooltipText; 4572 mContainerTitle = other.mContainerTitle; 4573 mViewIdResourceName = other.mViewIdResourceName; 4574 4575 if (mActions != null) mActions.clear(); 4576 final ArrayList<AccessibilityAction> otherActions = other.mActions; 4577 if (otherActions != null && otherActions.size() > 0) { 4578 if (mActions == null) { 4579 mActions = new ArrayList(otherActions); 4580 } else { 4581 mActions.addAll(other.mActions); 4582 } 4583 } 4584 4585 mBooleanProperties = other.mBooleanProperties; 4586 mMaxTextLength = other.mMaxTextLength; 4587 mMovementGranularities = other.mMovementGranularities; 4588 4589 4590 if (mChildNodeIds != null) mChildNodeIds.clear(); 4591 final LongArray otherChildNodeIds = other.mChildNodeIds; 4592 if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) { 4593 if (mChildNodeIds == null) { 4594 mChildNodeIds = otherChildNodeIds.clone(); 4595 } else { 4596 mChildNodeIds.addAll(otherChildNodeIds); 4597 } 4598 } 4599 4600 mTextSelectionStart = other.mTextSelectionStart; 4601 mTextSelectionEnd = other.mTextSelectionEnd; 4602 mInputType = other.mInputType; 4603 mLiveRegion = other.mLiveRegion; 4604 mDrawingOrderInParent = other.mDrawingOrderInParent; 4605 4606 mExtraDataKeys = other.mExtraDataKeys; 4607 4608 mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null; 4609 4610 initCopyInfos(other); 4611 4612 final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo; 4613 mTouchDelegateInfo = (otherInfo != null) 4614 ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null; 4615 4616 mLeashedChild = other.mLeashedChild; 4617 mLeashedParent = other.mLeashedParent; 4618 mLeashedParentNodeId = other.mLeashedParentNodeId; 4619 } 4620 initCopyInfos(AccessibilityNodeInfo other)4621 private void initCopyInfos(AccessibilityNodeInfo other) { 4622 RangeInfo ri = other.mRangeInfo; 4623 mRangeInfo = (ri == null) ? null 4624 : new RangeInfo(ri.mType, ri.mMin, ri.mMax, ri.mCurrent); 4625 CollectionInfo ci = other.mCollectionInfo; 4626 mCollectionInfo = (ci == null) ? null 4627 : new CollectionInfo(ci.mRowCount, ci.mColumnCount, 4628 ci.mHierarchical, ci.mSelectionMode, ci.mItemCount, 4629 ci.mImportantForAccessibilityItemCount); 4630 CollectionItemInfo cii = other.mCollectionItemInfo; 4631 CollectionItemInfo.Builder builder = new CollectionItemInfo.Builder(); 4632 mCollectionItemInfo = (cii == null) ? null 4633 : builder.setRowTitle(cii.mRowTitle).setRowIndex(cii.mRowIndex).setRowSpan( 4634 cii.mRowSpan).setColumnTitle(cii.mColumnTitle).setColumnIndex( 4635 cii.mColumnIndex).setColumnSpan(cii.mColumnSpan).setHeading( 4636 cii.mHeading).setSelected(cii.mSelected).build(); 4637 ExtraRenderingInfo ti = other.mExtraRenderingInfo; 4638 mExtraRenderingInfo = (ti == null) ? null 4639 : new ExtraRenderingInfo(ti); 4640 } 4641 4642 /** 4643 * Creates a new instance from a {@link Parcel}. 4644 * 4645 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. 4646 */ initFromParcel(Parcel parcel)4647 private void initFromParcel(Parcel parcel) { 4648 // Bit mask of non-default-valued field indices 4649 long nonDefaultFields = parcel.readLong(); 4650 int fieldIndex = 0; 4651 final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++) 4652 ? (parcel.readInt() == 1) 4653 : DEFAULT.mSealed; 4654 if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong(); 4655 if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt(); 4656 if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong(); 4657 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong(); 4658 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong(); 4659 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong(); 4660 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong(); 4661 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4662 mMinDurationBetweenContentChanges = parcel.readLong(); 4663 } 4664 4665 if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt(); 4666 4667 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4668 final int childrenSize = parcel.readInt(); 4669 if (childrenSize <= 0) { 4670 mChildNodeIds = null; 4671 } else { 4672 mChildNodeIds = new LongArray(childrenSize); 4673 for (int i = 0; i < childrenSize; i++) { 4674 final long childId = parcel.readLong(); 4675 mChildNodeIds.add(childId); 4676 } 4677 } 4678 } 4679 4680 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4681 mBoundsInParent.top = parcel.readInt(); 4682 mBoundsInParent.bottom = parcel.readInt(); 4683 mBoundsInParent.left = parcel.readInt(); 4684 mBoundsInParent.right = parcel.readInt(); 4685 } 4686 4687 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4688 mBoundsInScreen.top = parcel.readInt(); 4689 mBoundsInScreen.bottom = parcel.readInt(); 4690 mBoundsInScreen.left = parcel.readInt(); 4691 mBoundsInScreen.right = parcel.readInt(); 4692 } 4693 4694 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4695 mBoundsInWindow.top = parcel.readInt(); 4696 mBoundsInWindow.bottom = parcel.readInt(); 4697 mBoundsInWindow.left = parcel.readInt(); 4698 mBoundsInWindow.right = parcel.readInt(); 4699 } 4700 4701 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4702 final long standardActions = parcel.readLong(); 4703 addStandardActions(standardActions); 4704 final int nonStandardActionCount = parcel.readInt(); 4705 for (int i = 0; i < nonStandardActionCount; i++) { 4706 final AccessibilityAction action = 4707 AccessibilityAction.CREATOR.createFromParcel(parcel); 4708 addActionUnchecked(action); 4709 } 4710 } 4711 4712 if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt(); 4713 if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt(); 4714 if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt(); 4715 4716 if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence(); 4717 if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence(); 4718 if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence(); 4719 if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence(); 4720 if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence(); 4721 if (isBitSet(nonDefaultFields, fieldIndex++)) mStateDescription = parcel.readCharSequence(); 4722 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4723 mContentDescription = parcel.readCharSequence(); 4724 } 4725 if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readCharSequence(); 4726 if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence(); 4727 if (isBitSet(nonDefaultFields, fieldIndex++)) mContainerTitle = parcel.readCharSequence(); 4728 if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString(); 4729 if (isBitSet(nonDefaultFields, fieldIndex++)) mUniqueId = parcel.readString(); 4730 4731 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt(); 4732 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt(); 4733 4734 if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt(); 4735 if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt(); 4736 if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt(); 4737 4738 mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++) 4739 ? parcel.createStringArrayList() 4740 : null; 4741 4742 mExtras = isBitSet(nonDefaultFields, fieldIndex++) 4743 ? parcel.readBundle() 4744 : null; 4745 4746 mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++) 4747 ? new RangeInfo( 4748 parcel.readInt(), 4749 parcel.readFloat(), 4750 parcel.readFloat(), 4751 parcel.readFloat()) 4752 : null; 4753 4754 mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++) 4755 ? new CollectionInfo( 4756 parcel.readInt(), 4757 parcel.readInt(), 4758 parcel.readInt() == 1, 4759 parcel.readInt(), 4760 parcel.readInt(), 4761 parcel.readInt()) 4762 : null; 4763 4764 mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++) 4765 ? new CollectionItemInfo( 4766 parcel.readString(), 4767 parcel.readInt(), 4768 parcel.readInt(), 4769 parcel.readString(), 4770 parcel.readInt(), 4771 parcel.readInt(), 4772 parcel.readInt() == 1, 4773 parcel.readInt() == 1) 4774 : null; 4775 4776 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4777 mTouchDelegateInfo = TouchDelegateInfo.CREATOR.createFromParcel(parcel); 4778 } 4779 4780 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4781 mExtraRenderingInfo = new ExtraRenderingInfo(null); 4782 mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null); 4783 mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat(); 4784 mExtraRenderingInfo.mTextSizeUnit = parcel.readInt(); 4785 } 4786 4787 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4788 mLeashedChild = parcel.readStrongBinder(); 4789 } 4790 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4791 mLeashedParent = parcel.readStrongBinder(); 4792 } 4793 if (isBitSet(nonDefaultFields, fieldIndex++)) { 4794 mLeashedParentNodeId = parcel.readLong(); 4795 } 4796 4797 mSealed = sealed; 4798 } 4799 4800 /** 4801 * Clears the state of this instance. 4802 */ clear()4803 private void clear() { 4804 init(DEFAULT); 4805 } 4806 isDefaultStandardAction(AccessibilityAction action)4807 private static boolean isDefaultStandardAction(AccessibilityAction action) { 4808 return (action.mSerializationFlag != -1L) && TextUtils.isEmpty(action.getLabel()); 4809 } 4810 getActionSingleton(int actionId)4811 private static AccessibilityAction getActionSingleton(int actionId) { 4812 final int actions = AccessibilityAction.sStandardActions.size(); 4813 for (int i = 0; i < actions; i++) { 4814 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i); 4815 if (actionId == currentAction.getId()) { 4816 return currentAction; 4817 } 4818 } 4819 4820 return null; 4821 } 4822 getActionSingletonBySerializationFlag(long flag)4823 private static AccessibilityAction getActionSingletonBySerializationFlag(long flag) { 4824 final int actions = AccessibilityAction.sStandardActions.size(); 4825 for (int i = 0; i < actions; i++) { 4826 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i); 4827 if (flag == currentAction.mSerializationFlag) { 4828 return currentAction; 4829 } 4830 } 4831 4832 return null; 4833 } 4834 addStandardActions(long serializationIdMask)4835 private void addStandardActions(long serializationIdMask) { 4836 long remainingIds = serializationIdMask; 4837 while (remainingIds > 0) { 4838 final long id = 1L << Long.numberOfTrailingZeros(remainingIds); 4839 remainingIds &= ~id; 4840 AccessibilityAction action = getActionSingletonBySerializationFlag(id); 4841 addAction(action); 4842 } 4843 } 4844 4845 /** 4846 * Gets the human readable action symbolic name. 4847 * 4848 * @param action The action. 4849 * @return The symbolic name. 4850 */ getActionSymbolicName(int action)4851 private static String getActionSymbolicName(int action) { 4852 switch (action) { 4853 case ACTION_FOCUS: 4854 return "ACTION_FOCUS"; 4855 case ACTION_CLEAR_FOCUS: 4856 return "ACTION_CLEAR_FOCUS"; 4857 case ACTION_SELECT: 4858 return "ACTION_SELECT"; 4859 case ACTION_CLEAR_SELECTION: 4860 return "ACTION_CLEAR_SELECTION"; 4861 case ACTION_CLICK: 4862 return "ACTION_CLICK"; 4863 case ACTION_LONG_CLICK: 4864 return "ACTION_LONG_CLICK"; 4865 case ACTION_ACCESSIBILITY_FOCUS: 4866 return "ACTION_ACCESSIBILITY_FOCUS"; 4867 case ACTION_CLEAR_ACCESSIBILITY_FOCUS: 4868 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS"; 4869 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY: 4870 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY"; 4871 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: 4872 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY"; 4873 case ACTION_NEXT_HTML_ELEMENT: 4874 return "ACTION_NEXT_HTML_ELEMENT"; 4875 case ACTION_PREVIOUS_HTML_ELEMENT: 4876 return "ACTION_PREVIOUS_HTML_ELEMENT"; 4877 case ACTION_SCROLL_FORWARD: 4878 return "ACTION_SCROLL_FORWARD"; 4879 case ACTION_SCROLL_BACKWARD: 4880 return "ACTION_SCROLL_BACKWARD"; 4881 case ACTION_CUT: 4882 return "ACTION_CUT"; 4883 case ACTION_COPY: 4884 return "ACTION_COPY"; 4885 case ACTION_PASTE: 4886 return "ACTION_PASTE"; 4887 case ACTION_SET_SELECTION: 4888 return "ACTION_SET_SELECTION"; 4889 case ACTION_EXPAND: 4890 return "ACTION_EXPAND"; 4891 case ACTION_COLLAPSE: 4892 return "ACTION_COLLAPSE"; 4893 case ACTION_DISMISS: 4894 return "ACTION_DISMISS"; 4895 case ACTION_SET_TEXT: 4896 return "ACTION_SET_TEXT"; 4897 case R.id.accessibilityActionShowOnScreen: 4898 return "ACTION_SHOW_ON_SCREEN"; 4899 case R.id.accessibilityActionScrollToPosition: 4900 return "ACTION_SCROLL_TO_POSITION"; 4901 case R.id.accessibilityActionScrollUp: 4902 return "ACTION_SCROLL_UP"; 4903 case R.id.accessibilityActionScrollLeft: 4904 return "ACTION_SCROLL_LEFT"; 4905 case R.id.accessibilityActionScrollDown: 4906 return "ACTION_SCROLL_DOWN"; 4907 case R.id.accessibilityActionScrollRight: 4908 return "ACTION_SCROLL_RIGHT"; 4909 case R.id.accessibilityActionPageDown: 4910 return "ACTION_PAGE_DOWN"; 4911 case R.id.accessibilityActionPageUp: 4912 return "ACTION_PAGE_UP"; 4913 case R.id.accessibilityActionPageLeft: 4914 return "ACTION_PAGE_LEFT"; 4915 case R.id.accessibilityActionPageRight: 4916 return "ACTION_PAGE_RIGHT"; 4917 case R.id.accessibilityActionSetProgress: 4918 return "ACTION_SET_PROGRESS"; 4919 case R.id.accessibilityActionContextClick: 4920 return "ACTION_CONTEXT_CLICK"; 4921 case R.id.accessibilityActionShowTooltip: 4922 return "ACTION_SHOW_TOOLTIP"; 4923 case R.id.accessibilityActionHideTooltip: 4924 return "ACTION_HIDE_TOOLTIP"; 4925 case R.id.accessibilityActionPressAndHold: 4926 return "ACTION_PRESS_AND_HOLD"; 4927 case R.id.accessibilityActionImeEnter: 4928 return "ACTION_IME_ENTER"; 4929 case R.id.accessibilityActionDragStart: 4930 return "ACTION_DRAG"; 4931 case R.id.accessibilityActionDragCancel: 4932 return "ACTION_CANCEL_DRAG"; 4933 case R.id.accessibilityActionDragDrop: 4934 return "ACTION_DROP"; 4935 default: { 4936 if (action == R.id.accessibilityActionShowTextSuggestions) { 4937 return "ACTION_SHOW_TEXT_SUGGESTIONS"; 4938 } 4939 if (action == R.id.accessibilityActionScrollInDirection) { 4940 return "ACTION_SCROLL_IN_DIRECTION"; 4941 } 4942 return "ACTION_UNKNOWN"; 4943 } 4944 } 4945 } 4946 4947 /** 4948 * Gets the human readable movement granularity symbolic name. 4949 * 4950 * @param granularity The granularity. 4951 * @return The symbolic name. 4952 */ getMovementGranularitySymbolicName(int granularity)4953 private static String getMovementGranularitySymbolicName(int granularity) { 4954 switch (granularity) { 4955 case MOVEMENT_GRANULARITY_CHARACTER: 4956 return "MOVEMENT_GRANULARITY_CHARACTER"; 4957 case MOVEMENT_GRANULARITY_WORD: 4958 return "MOVEMENT_GRANULARITY_WORD"; 4959 case MOVEMENT_GRANULARITY_LINE: 4960 return "MOVEMENT_GRANULARITY_LINE"; 4961 case MOVEMENT_GRANULARITY_PARAGRAPH: 4962 return "MOVEMENT_GRANULARITY_PARAGRAPH"; 4963 case MOVEMENT_GRANULARITY_PAGE: 4964 return "MOVEMENT_GRANULARITY_PAGE"; 4965 default: 4966 throw new IllegalArgumentException("Unknown movement granularity: " + granularity); 4967 } 4968 } 4969 canPerformRequestOverConnection(int connectionId, int windowId, long accessibilityNodeId)4970 private static boolean canPerformRequestOverConnection(int connectionId, 4971 int windowId, long accessibilityNodeId) { 4972 final boolean hasWindowId = windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 4973 return ((usingDirectConnection(connectionId) || hasWindowId) 4974 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID) 4975 && (connectionId != UNDEFINED_CONNECTION_ID)); 4976 } 4977 4978 @Override equals(@ullable Object object)4979 public boolean equals(@Nullable Object object) { 4980 if (this == object) { 4981 return true; 4982 } 4983 if (object == null) { 4984 return false; 4985 } 4986 if (getClass() != object.getClass()) { 4987 return false; 4988 } 4989 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object; 4990 if (mSourceNodeId != other.mSourceNodeId) { 4991 return false; 4992 } 4993 if (mWindowId != other.mWindowId) { 4994 return false; 4995 } 4996 return true; 4997 } 4998 4999 @Override hashCode()5000 public int hashCode() { 5001 final int prime = 31; 5002 int result = 1; 5003 result = prime * result + getAccessibilityViewId(mSourceNodeId); 5004 result = prime * result + getVirtualDescendantId(mSourceNodeId); 5005 result = prime * result + mWindowId; 5006 return result; 5007 } 5008 5009 @Override toString()5010 public String toString() { 5011 StringBuilder builder = new StringBuilder(); 5012 builder.append(super.toString()); 5013 5014 if (DEBUG) { 5015 builder.append("; sourceNodeId: 0x").append(Long.toHexString(mSourceNodeId)); 5016 builder.append("; windowId: 0x").append(Long.toHexString(mWindowId)); 5017 builder.append("; accessibilityViewId: 0x") 5018 .append(Long.toHexString(getAccessibilityViewId(mSourceNodeId))); 5019 builder.append("; virtualDescendantId: 0x") 5020 .append(Long.toHexString(getVirtualDescendantId(mSourceNodeId))); 5021 builder.append("; mParentNodeId: 0x").append(Long.toHexString(mParentNodeId)); 5022 builder.append("; traversalBefore: 0x").append(Long.toHexString(mTraversalBefore)); 5023 builder.append("; traversalAfter: 0x").append(Long.toHexString(mTraversalAfter)); 5024 builder.append("; minDurationBetweenContentChanges: ") 5025 .append(mMinDurationBetweenContentChanges); 5026 5027 int granularities = mMovementGranularities; 5028 builder.append("; MovementGranularities: ["); 5029 while (granularities != 0) { 5030 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities); 5031 granularities &= ~granularity; 5032 builder.append(getMovementGranularitySymbolicName(granularity)); 5033 if (granularities != 0) { 5034 builder.append(", "); 5035 } 5036 } 5037 builder.append("]"); 5038 5039 builder.append("; childAccessibilityIds: ["); 5040 final LongArray childIds = mChildNodeIds; 5041 if (childIds != null) { 5042 for (int i = 0, count = childIds.size(); i < count; i++) { 5043 builder.append("0x").append(Long.toHexString(childIds.get(i))); 5044 if (i < count - 1) { 5045 builder.append(", "); 5046 } 5047 } 5048 } 5049 builder.append("]"); 5050 } 5051 5052 builder.append("; boundsInParent: ").append(mBoundsInParent); 5053 builder.append("; boundsInScreen: ").append(mBoundsInScreen); 5054 builder.append("; boundsInWindow: ").append(mBoundsInScreen); 5055 5056 builder.append("; packageName: ").append(mPackageName); 5057 builder.append("; className: ").append(mClassName); 5058 builder.append("; text: ").append(mText); 5059 builder.append("; error: ").append(mError); 5060 builder.append("; maxTextLength: ").append(mMaxTextLength); 5061 builder.append("; stateDescription: ").append(mStateDescription); 5062 builder.append("; contentDescription: ").append(mContentDescription); 5063 builder.append("; tooltipText: ").append(mTooltipText); 5064 builder.append("; containerTitle: ").append(mContainerTitle); 5065 builder.append("; viewIdResName: ").append(mViewIdResourceName); 5066 builder.append("; uniqueId: ").append(mUniqueId); 5067 5068 builder.append("; checkable: ").append(isCheckable()); 5069 builder.append("; checked: ").append(isChecked()); 5070 builder.append("; focusable: ").append(isFocusable()); 5071 builder.append("; focused: ").append(isFocused()); 5072 builder.append("; selected: ").append(isSelected()); 5073 builder.append("; clickable: ").append(isClickable()); 5074 builder.append("; longClickable: ").append(isLongClickable()); 5075 builder.append("; contextClickable: ").append(isContextClickable()); 5076 builder.append("; enabled: ").append(isEnabled()); 5077 builder.append("; password: ").append(isPassword()); 5078 builder.append("; scrollable: ").append(isScrollable()); 5079 builder.append("; granularScrollingSupported: ").append(isGranularScrollingSupported()); 5080 builder.append("; importantForAccessibility: ").append(isImportantForAccessibility()); 5081 builder.append("; visible: ").append(isVisibleToUser()); 5082 builder.append("; actions: ").append(mActions); 5083 builder.append("; isTextSelectable: ").append(isTextSelectable()); 5084 5085 return builder.toString(); 5086 } 5087 getNodeForAccessibilityId(int connectionId, int windowId, long accessibilityId)5088 private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId, 5089 int windowId, long accessibilityId) { 5090 return getNodeForAccessibilityId(connectionId, windowId, accessibilityId, 5091 FLAG_PREFETCH_ANCESTORS 5092 | FLAG_PREFETCH_DESCENDANTS_HYBRID | FLAG_PREFETCH_SIBLINGS); 5093 } 5094 getNodeForAccessibilityId(int connectionId, int windowId, long accessibilityId, @PrefetchingStrategy int prefetchingStrategy)5095 private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId, 5096 int windowId, long accessibilityId, @PrefetchingStrategy int prefetchingStrategy) { 5097 if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) { 5098 return null; 5099 } 5100 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 5101 return client.findAccessibilityNodeInfoByAccessibilityId(connectionId, 5102 windowId, accessibilityId, false, prefetchingStrategy, null); 5103 } 5104 getNodeForAccessibilityId(int connectionId, IBinder leashToken, long accessibilityId)5105 private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId, 5106 IBinder leashToken, long accessibilityId) { 5107 return getNodeForAccessibilityId(connectionId, leashToken, accessibilityId, 5108 FLAG_PREFETCH_ANCESTORS 5109 | FLAG_PREFETCH_DESCENDANTS_HYBRID | FLAG_PREFETCH_SIBLINGS); 5110 } 5111 getNodeForAccessibilityId(int connectionId, IBinder leashToken, long accessibilityId, @PrefetchingStrategy int prefetchingStrategy)5112 private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId, 5113 IBinder leashToken, long accessibilityId, 5114 @PrefetchingStrategy int prefetchingStrategy) { 5115 if (!((leashToken != null) 5116 && (getAccessibilityViewId(accessibilityId) != UNDEFINED_ITEM_ID) 5117 && (connectionId != UNDEFINED_CONNECTION_ID))) { 5118 return null; 5119 } 5120 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 5121 return client.findAccessibilityNodeInfoByAccessibilityId(connectionId, 5122 leashToken, accessibilityId, false, prefetchingStrategy, null); 5123 } 5124 5125 /** @hide */ idToString(long accessibilityId)5126 public static String idToString(long accessibilityId) { 5127 int accessibilityViewId = getAccessibilityViewId(accessibilityId); 5128 int virtualDescendantId = getVirtualDescendantId(accessibilityId); 5129 return virtualDescendantId == AccessibilityNodeProvider.HOST_VIEW_ID 5130 ? idItemToString(accessibilityViewId) 5131 : idItemToString(accessibilityViewId) + ":" + idItemToString(virtualDescendantId); 5132 } 5133 idItemToString(int item)5134 private static String idItemToString(int item) { 5135 switch (item) { 5136 case ROOT_ITEM_ID: return "ROOT"; 5137 case UNDEFINED_ITEM_ID: return "UNDEFINED"; 5138 case AccessibilityNodeProvider.HOST_VIEW_ID: return "HOST"; 5139 default: return "" + item; 5140 } 5141 } 5142 5143 /** 5144 * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}. 5145 * Each action has a unique id that is mandatory and optional data. 5146 * <p> 5147 * There are three categories of actions: 5148 * <ul> 5149 * <li><strong>Standard actions</strong> - These are actions that are reported and 5150 * handled by the standard UI widgets in the platform. For each standard action 5151 * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}. 5152 * These actions will have {@code null} labels. 5153 * </li> 5154 * <li><strong>Custom actions action</strong> - These are actions that are reported 5155 * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For 5156 * example, an application may define a custom action for clearing the user history. 5157 * </li> 5158 * <li><strong>Overridden standard actions</strong> - These are actions that override 5159 * standard actions to customize them. For example, an app may add a label to the 5160 * standard {@link #ACTION_CLICK} action to indicate to the user that this action clears 5161 * browsing history. 5162 * </ul> 5163 * </p> 5164 * <p> 5165 * Actions are typically added to an {@link AccessibilityNodeInfo} by using 5166 * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within 5167 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed 5168 * within {@link View#performAccessibilityAction(int, Bundle)}. 5169 * </p> 5170 * <p> 5171 * <aside class="note"> 5172 * <b>Note:</b> Views which support these actions should invoke 5173 * {@link View#setImportantForAccessibility(int)} with 5174 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService} 5175 * can discover the set of supported actions. </aside> 5176 * </p> 5177 * <p> 5178 * <aside class="note"> 5179 * <b>Note:</b> Use {@link androidx.core.view.ViewCompat#addAccessibilityAction(View, 5180 * CharSequence, AccessibilityViewCommand)} to register an action directly on the view. </aside> 5181 * </p> 5182 */ 5183 public static final class AccessibilityAction implements Parcelable { 5184 5185 /** @hide */ 5186 public static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>(); 5187 5188 /** 5189 * Action that gives input focus to the node. 5190 * <p>The focus request send an event of {@link AccessibilityEvent#TYPE_VIEW_FOCUSED} 5191 * if successful. In the View system, this is handled by {@link View#requestFocus}. 5192 * 5193 * <p>The node that is focused should return {@code true} for 5194 * {@link AccessibilityNodeInfo#isFocused()}. 5195 * 5196 * See {@link #ACTION_ACCESSIBILITY_FOCUS} for the difference between system and 5197 * accessibility focus. 5198 */ 5199 public static final AccessibilityAction ACTION_FOCUS = 5200 new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS); 5201 5202 /** 5203 * Action that clears input focus of the node. 5204 * <p>The node that is cleared should return {@code false} for 5205 * {@link AccessibilityNodeInfo#isFocused)}. 5206 */ 5207 public static final AccessibilityAction ACTION_CLEAR_FOCUS = 5208 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 5209 5210 /** 5211 * Action that selects the node. 5212 * The view the implements this should send a 5213 * {@link AccessibilityEvent#TYPE_VIEW_SELECTED} event. 5214 * @see AccessibilityAction#ACTION_CLEAR_SELECTION 5215 */ 5216 public static final AccessibilityAction ACTION_SELECT = 5217 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SELECT); 5218 5219 /** 5220 * Action that deselects the node. 5221 * @see AccessibilityAction#ACTION_SELECT 5222 */ 5223 public static final AccessibilityAction ACTION_CLEAR_SELECTION = 5224 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 5225 5226 /** 5227 * Action that clicks on the node info. 5228 * 5229 * <p>The UI element that implements this should send a 5230 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} event. In the View system, 5231 * the default handling of this action when performed by a service is to call 5232 * {@link View#performClick()}, and setting a 5233 * {@link View#setOnClickListener(View.OnClickListener)} automatically adds this action. 5234 * 5235 * <p>{@link #isClickable()} should return true if this action is available. 5236 */ 5237 public static final AccessibilityAction ACTION_CLICK = 5238 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK); 5239 5240 /** 5241 * Action that long clicks on the node. 5242 * 5243 * <p>The UI element that implements this should send a 5244 * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED} event. In the View system, 5245 * the default handling of this action when performed by a service is to call 5246 * {@link View#performLongClick()}, and setting a 5247 * {@link View#setOnLongClickListener(View.OnLongClickListener)} automatically adds this 5248 * action. 5249 * 5250 * <p>{@link #isLongClickable()} should return true if this action is available. 5251 */ 5252 public static final AccessibilityAction ACTION_LONG_CLICK = 5253 new AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 5254 5255 /** 5256 * Action that gives accessibility focus to the node. 5257 * 5258 * <p>The UI element that implements this should send a 5259 * {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED} event 5260 * if successful. The node that is focused should return {@code true} for 5261 * {@link AccessibilityNodeInfo#isAccessibilityFocused()}. 5262 * 5263 * <p>This is intended to be used by screen readers to assist with user navigation. Apps 5264 * changing focus can confuse screen readers, so the resulting behavior can vary by device 5265 * and screen reader version. 5266 * <p>This is distinct from {@link #ACTION_FOCUS}, which refers to system focus. System 5267 * focus is typically used to convey targets for keyboard navigation. 5268 */ 5269 public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS = 5270 new AccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 5271 5272 /** 5273 * Action that clears accessibility focus of the node. 5274 * <p>The UI element that implements this should send a 5275 * {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED} event if successful. The 5276 * node that is cleared should return {@code false} for 5277 * {@link AccessibilityNodeInfo#isAccessibilityFocused()}. 5278 */ 5279 public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS = 5280 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 5281 5282 /** 5283 * Action that requests to go to the next entity in this node's text 5284 * at a given movement granularity. For example, move to the next character, 5285 * word, etc. 5286 * <p> 5287 * <strong>Arguments:</strong> 5288 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5289 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 5290 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5291 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 5292 * <strong>Example:</strong> Move to the previous character and do not extend selection. 5293 * <code><pre><p> 5294 * Bundle arguments = new Bundle(); 5295 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 5296 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 5297 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 5298 * false); 5299 * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(), 5300 * arguments); 5301 * </code></pre></p> 5302 * </p> 5303 * 5304 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5305 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5306 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5307 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5308 * 5309 * @see AccessibilityNodeInfo#setMovementGranularities(int) 5310 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5311 * @see AccessibilityNodeInfo#getMovementGranularities() 5312 * AccessibilityNodeInfo.getMovementGranularities() 5313 * 5314 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER 5315 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 5316 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD 5317 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 5318 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE 5319 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE 5320 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH 5321 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH 5322 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE 5323 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE 5324 */ 5325 public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 5326 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 5327 5328 /** 5329 * Action that requests to go to the previous entity in this node's text 5330 * at a given movement granularity. For example, move to the next character, 5331 * word, etc. 5332 * <p> 5333 * <strong>Arguments:</strong> 5334 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5335 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 5336 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5337 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 5338 * <strong>Example:</strong> Move to the next character and do not extend selection. 5339 * <code><pre><p> 5340 * Bundle arguments = new Bundle(); 5341 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 5342 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 5343 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 5344 * false); 5345 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(), 5346 * arguments); 5347 * </code></pre></p> 5348 * </p> 5349 * 5350 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5351 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 5352 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5353 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 5354 * 5355 * @see AccessibilityNodeInfo#setMovementGranularities(int) 5356 * AccessibilityNodeInfo.setMovementGranularities(int) 5357 * @see AccessibilityNodeInfo#getMovementGranularities() 5358 * AccessibilityNodeInfo.getMovementGranularities() 5359 * 5360 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER 5361 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 5362 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD 5363 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 5364 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE 5365 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE 5366 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH 5367 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH 5368 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE 5369 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE 5370 */ 5371 public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 5372 new AccessibilityAction( 5373 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 5374 5375 /** 5376 * Action to move to the next HTML element of a given type. For example, move 5377 * to the BUTTON, INPUT, TABLE, etc. 5378 * <p> 5379 * <strong>Arguments:</strong> 5380 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING 5381 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 5382 * <strong>Example:</strong> 5383 * <code><pre><p> 5384 * Bundle arguments = new Bundle(); 5385 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 5386 * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments); 5387 * </code></pre></p> 5388 * </p> 5389 */ 5390 public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT = 5391 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT); 5392 5393 /** 5394 * Action to move to the previous HTML element of a given type. For example, move 5395 * to the BUTTON, INPUT, TABLE, etc. 5396 * <p> 5397 * <strong>Arguments:</strong> 5398 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING 5399 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 5400 * <strong>Example:</strong> 5401 * <code><pre><p> 5402 * Bundle arguments = new Bundle(); 5403 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 5404 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments); 5405 * </code></pre></p> 5406 * </p> 5407 */ 5408 public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT = 5409 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT); 5410 5411 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5412 /** 5413 * Action to scroll the node content forward. 5414 * 5415 * <p>The UI element that implements this should send a 5416 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. Depending on the orientation, 5417 * this element should also add the relevant directional scroll actions of 5418 * {@link #ACTION_SCROLL_LEFT}, {@link #ACTION_SCROLL_RIGHT}, 5419 * {@link #ACTION_SCROLL_UP}, and {@link #ACTION_SCROLL_DOWN}. If the scrolling brings 5420 * the next or previous element into view as the center element, such as in a ViewPager2, 5421 * use {@link #ACTION_PAGE_DOWN} and the other page actions instead of the directional 5422 * actions. 5423 * <p>Example: a scrolling UI of vertical orientation with a forward 5424 * scroll action should also add the scroll down action: 5425 * <pre class="prettyprint"><code> 5426 * onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 5427 * super.onInitializeAccessibilityNodeInfo(info); 5428 * if (canScrollForward) { 5429 * info.addAction(ACTION_SCROLL_FORWARD); 5430 * info.addAction(ACTION_SCROLL_DOWN); 5431 * } 5432 * } 5433 * performAccessibilityAction(int action, Bundle bundle) { 5434 * if (action == ACTION_SCROLL_FORWARD || action == ACTION_SCROLL_DOWN) { 5435 * scrollForward(); 5436 * } 5437 * } 5438 * scrollForward() { 5439 * ... 5440 * if (mAccessibilityManager.isEnabled()) { 5441 * event = new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 5442 * event.setScrollDeltaX(dx); 5443 * event.setScrollDeltaY(dy); 5444 * event.setMaxScrollX(maxDx); 5445 * event.setMaxScrollY(maxDY); 5446 * sendAccessibilityEventUnchecked(event); 5447 * } 5448 * } 5449 * </code> 5450 * </pre></p> 5451 */ 5452 public static final AccessibilityAction ACTION_SCROLL_FORWARD = 5453 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 5454 5455 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5456 /** 5457 * Action to scroll the node content backward. 5458 * 5459 * <p>The UI element that implements this should send a 5460 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. Depending on the orientation, 5461 * this element should also add the relevant directional scroll actions of 5462 * {@link #ACTION_SCROLL_LEFT}, {@link #ACTION_SCROLL_RIGHT}, 5463 * {@link #ACTION_SCROLL_UP}, and {@link #ACTION_SCROLL_DOWN}. If the scrolling brings 5464 * the next or previous element into view as the center element, such as in a ViewPager2, 5465 * use {@link #ACTION_PAGE_DOWN} and the other page actions instead of the directional 5466 * actions. 5467 * <p> Example: a scrolling UI of horizontal orientation with a backward 5468 * scroll action should also add the scroll left/right action (LTR/RTL): 5469 * <pre class="prettyprint"><code> 5470 * onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 5471 * super.onInitializeAccessibilityNodeInfo(info); 5472 * if (canScrollBackward) { 5473 * info.addAction(ACTION_SCROLL_FORWARD); 5474 * if (leftToRight) { 5475 * info.addAction(ACTION_SCROLL_LEFT); 5476 * } else { 5477 * info.addAction(ACTION_SCROLL_RIGHT); 5478 * } 5479 * } 5480 * } 5481 * performAccessibilityAction(int action, Bundle bundle) { 5482 * if (action == ACTION_SCROLL_BACKWARD) { 5483 * scrollBackward(); 5484 * } else if (action == ACTION_SCROLL_LEFT) { 5485 * if (!isRTL()){ 5486 * scrollBackward(); 5487 * } 5488 * } else if (action == ACTION_SCROLL_RIGHT) { 5489 * if (isRTL()){ 5490 * scrollBackward(); 5491 * } 5492 * } 5493 * } 5494 * scrollBackward() { 5495 * ... 5496 * if (mAccessibilityManager.isEnabled()) { 5497 * event = new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 5498 * event.setScrollDeltaX(dx); 5499 * event.setScrollDeltaY(dy); 5500 * event.setMaxScrollX(maxDx); 5501 * event.setMaxScrollY(maxDY); 5502 * sendAccessibilityEventUnchecked(event); 5503 * } 5504 * } 5505 * </code> 5506 * </pre></p> 5507 */ 5508 public static final AccessibilityAction ACTION_SCROLL_BACKWARD = 5509 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 5510 5511 /** 5512 * Action to copy the current selection to the clipboard. 5513 */ 5514 public static final AccessibilityAction ACTION_COPY = 5515 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COPY); 5516 5517 /** 5518 * Action to paste the current clipboard content. 5519 */ 5520 public static final AccessibilityAction ACTION_PASTE = 5521 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PASTE); 5522 5523 /** 5524 * Action to cut the current selection and place it to the clipboard. 5525 */ 5526 public static final AccessibilityAction ACTION_CUT = 5527 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CUT); 5528 5529 /** 5530 * Action to set the selection. Performing this action with no arguments 5531 * clears the selection. 5532 * <p> 5533 * <strong>Arguments:</strong> 5534 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT 5535 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT}, 5536 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT 5537 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br> 5538 * <strong>Example:</strong> 5539 * <code><pre><p> 5540 * Bundle arguments = new Bundle(); 5541 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1); 5542 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2); 5543 * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments); 5544 * </code></pre></p> 5545 * </p> 5546 * <p> If this is a text selection, the UI element that implements this should send a 5547 * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED} event if its selection is 5548 * updated. This element should also return {@code true} for 5549 * {@link AccessibilityNodeInfo#isTextSelectable()}. 5550 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT 5551 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT 5552 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT 5553 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT 5554 */ 5555 public static final AccessibilityAction ACTION_SET_SELECTION = 5556 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 5557 5558 /** 5559 * Action to expand an expandable node. 5560 */ 5561 public static final AccessibilityAction ACTION_EXPAND = 5562 new AccessibilityAction(AccessibilityNodeInfo.ACTION_EXPAND); 5563 5564 /** 5565 * Action to collapse an expandable node. 5566 */ 5567 public static final AccessibilityAction ACTION_COLLAPSE = 5568 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE); 5569 5570 /** 5571 * Action to dismiss a dismissable node. 5572 */ 5573 public static final AccessibilityAction ACTION_DISMISS = 5574 new AccessibilityAction(AccessibilityNodeInfo.ACTION_DISMISS); 5575 5576 /** 5577 * Action that sets the text of the node. Performing the action without argument, 5578 * using <code> null</code> or empty {@link CharSequence} will clear the text. This 5579 * action will also put the cursor at the end of text. 5580 * <p> 5581 * <strong>Arguments:</strong> 5582 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE 5583 * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> 5584 * <strong>Example:</strong> 5585 * <code><pre><p> 5586 * Bundle arguments = new Bundle(); 5587 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, 5588 * "android"); 5589 * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments); 5590 * </code></pre></p> 5591 * <p> The UI element that implements this should send a 5592 * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} event if its text is updated. 5593 * This element should also return {@code true} for 5594 * {@link AccessibilityNodeInfo#isEditable()}. 5595 */ 5596 public static final AccessibilityAction ACTION_SET_TEXT = 5597 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT); 5598 5599 /** 5600 * Action that requests the node make its bounding rectangle visible 5601 * on the screen, scrolling if necessary just enough. 5602 * <p>The UI element that implements this should send a 5603 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5604 * 5605 * @see View#requestRectangleOnScreen(Rect) 5606 */ 5607 public static final AccessibilityAction ACTION_SHOW_ON_SCREEN = 5608 new AccessibilityAction(R.id.accessibilityActionShowOnScreen); 5609 5610 /** 5611 * Action that scrolls the node to make the specified collection 5612 * position visible on screen. 5613 * <p> 5614 * <strong>Arguments:</strong> 5615 * <ul> 5616 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li> 5617 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li> 5618 * <ul> 5619 * <p>The UI element that implements this should send a 5620 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5621 * 5622 * @see AccessibilityNodeInfo#getCollectionInfo() 5623 */ 5624 public static final AccessibilityAction ACTION_SCROLL_TO_POSITION = 5625 new AccessibilityAction(R.id.accessibilityActionScrollToPosition); 5626 5627 /** 5628 * Action that brings fully on screen the next node in the specified direction. 5629 * 5630 * <p> 5631 * This should include wrapping around to the next/previous row, column, etc. in a 5632 * collection if one is available. If there is no node in that direction, the action 5633 * should fail and return false. 5634 * </p> 5635 * <p> 5636 * This action should be used instead of 5637 * {@link AccessibilityAction#ACTION_SCROLL_TO_POSITION} when a widget does not have 5638 * clear row and column semantics or if a directional search is needed to find a node in 5639 * a complex ViewGroup where individual nodes may span multiple rows or columns. The 5640 * implementing widget must send a 5641 * {@link AccessibilityEvent#TYPE_VIEW_TARGETED_BY_SCROLL} accessibility event with the 5642 * scroll target as the source. An accessibility service can listen for this event, 5643 * inspect its source, and use the result when determining where to place accessibility 5644 * focus. 5645 * <p> 5646 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_DIRECTION_INT}. This is a 5647 * required argument.<br> 5648 * </p> 5649 */ 5650 @NonNull public static final AccessibilityAction ACTION_SCROLL_IN_DIRECTION = 5651 new AccessibilityAction(R.id.accessibilityActionScrollInDirection); 5652 5653 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5654 /** 5655 * Action to scroll the node content up. 5656 * 5657 * <p>The UI element that implements this should send a 5658 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5659 */ 5660 public static final AccessibilityAction ACTION_SCROLL_UP = 5661 new AccessibilityAction(R.id.accessibilityActionScrollUp); 5662 5663 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5664 /** 5665 * Action to scroll the node content left. 5666 * 5667 * <p>The UI element that implements this should send a 5668 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5669 */ 5670 public static final AccessibilityAction ACTION_SCROLL_LEFT = 5671 new AccessibilityAction(R.id.accessibilityActionScrollLeft); 5672 5673 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5674 /** 5675 * Action to scroll the node content down. 5676 * 5677 * <p>The UI element that implements this should send a 5678 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5679 */ 5680 public static final AccessibilityAction ACTION_SCROLL_DOWN = 5681 new AccessibilityAction(R.id.accessibilityActionScrollDown); 5682 5683 // TODO(316638728): restore ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT in javadoc 5684 /** 5685 * Action to scroll the node content right. 5686 * 5687 * <p>The UI element that implements this should send a 5688 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5689 */ 5690 public static final AccessibilityAction ACTION_SCROLL_RIGHT = 5691 new AccessibilityAction(R.id.accessibilityActionScrollRight); 5692 5693 /** 5694 * Action to move to the page above. 5695 * <p>The UI element that implements this should send a 5696 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5697 */ 5698 public static final AccessibilityAction ACTION_PAGE_UP = 5699 new AccessibilityAction(R.id.accessibilityActionPageUp); 5700 5701 /** 5702 * Action to move to the page below. 5703 * <p>The UI element that implements this should send a 5704 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5705 */ 5706 public static final AccessibilityAction ACTION_PAGE_DOWN = 5707 new AccessibilityAction(R.id.accessibilityActionPageDown); 5708 5709 /** 5710 * Action to move to the page left. 5711 * <p>The UI element that implements this should send a 5712 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5713 */ 5714 public static final AccessibilityAction ACTION_PAGE_LEFT = 5715 new AccessibilityAction(R.id.accessibilityActionPageLeft); 5716 5717 /** 5718 * Action to move to the page right. 5719 * <p>The UI element that implements this should send a 5720 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 5721 */ 5722 public static final AccessibilityAction ACTION_PAGE_RIGHT = 5723 new AccessibilityAction(R.id.accessibilityActionPageRight); 5724 5725 /** 5726 * Action that context clicks the node. 5727 * 5728 * <p>The UI element that implements this should send a 5729 * {@link AccessibilityEvent#TYPE_VIEW_CONTEXT_CLICKED} event. In the View system, 5730 * the default handling of this action when performed by a service is to call 5731 * {@link View#performContextClick()}, and setting a 5732 * {@link View#setOnContextClickListener(View.OnContextClickListener)} automatically adds 5733 * this action. 5734 * 5735 * <p>A context click usually occurs from a mouse pointer right-click or a stylus button 5736 * press. 5737 * 5738 * <p>{@link #isContextClickable()} should return true if this action is available. 5739 */ 5740 public static final AccessibilityAction ACTION_CONTEXT_CLICK = 5741 new AccessibilityAction(R.id.accessibilityActionContextClick); 5742 5743 /** 5744 * Action that sets progress between {@link RangeInfo#getMin() RangeInfo.getMin()} and 5745 * {@link RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as 5746 * {@link RangeInfo#getType() RangeInfo.getType()} 5747 * <p> 5748 * <strong>Arguments:</strong> 5749 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE} 5750 * 5751 * @see RangeInfo 5752 */ 5753 public static final AccessibilityAction ACTION_SET_PROGRESS = 5754 new AccessibilityAction(R.id.accessibilityActionSetProgress); 5755 5756 /** 5757 * Action to move a window to a new location. 5758 * <p> 5759 * <strong>Arguments:</strong> 5760 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X} 5761 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y} 5762 */ 5763 public static final AccessibilityAction ACTION_MOVE_WINDOW = 5764 new AccessibilityAction(R.id.accessibilityActionMoveWindow); 5765 5766 /** 5767 * Action to show a tooltip. A node should expose this action only for views with tooltip 5768 * text that but are not currently showing a tooltip. 5769 */ 5770 public static final AccessibilityAction ACTION_SHOW_TOOLTIP = 5771 new AccessibilityAction(R.id.accessibilityActionShowTooltip); 5772 5773 /** 5774 * Action to hide a tooltip. A node should expose this action only for views that are 5775 * currently showing a tooltip. 5776 */ 5777 public static final AccessibilityAction ACTION_HIDE_TOOLTIP = 5778 new AccessibilityAction(R.id.accessibilityActionHideTooltip); 5779 5780 /** 5781 * Action that presses and holds a node. 5782 * <p> 5783 * This action is for nodes that have distinct behavior that depends on how long a press is 5784 * held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK} 5785 * instead of this action, and nodes should not expose both actions. 5786 * <p> 5787 * When calling {@code performAction(ACTION_PRESS_AND_HOLD, bundle}, use 5788 * {@link #ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT} to specify how long the 5789 * node is pressed. The first time an accessibility service performs ACTION_PRES_AND_HOLD 5790 * on a node, it must specify 0 as ACTION_ARGUMENT_PRESS_AND_HOLD, so the application is 5791 * notified that the held state has started. To ensure reasonable behavior, the values 5792 * must be increased incrementally and may not exceed 10,000. UIs requested 5793 * to hold for times outside of this range should ignore the action. 5794 * <p> 5795 * The total time the element is held could be specified by an accessibility user up-front, 5796 * or may depend on what happens on the UI as the user continues to request the hold. 5797 * <p> 5798 * <strong>Note:</strong> The time between dispatching the action and it arriving in the 5799 * UI process is not guaranteed. It is possible on a busy system for the time to expire 5800 * unexpectedly. For the case of holding down a key for a repeating action, a delayed 5801 * arrival should be benign. Please do not use this sort of action in cases where such 5802 * delays will lead to unexpected UI behavior. 5803 * <p> 5804 */ 5805 @NonNull public static final AccessibilityAction ACTION_PRESS_AND_HOLD = 5806 new AccessibilityAction(R.id.accessibilityActionPressAndHold); 5807 5808 /** 5809 * Action to send an ime actionId which is from 5810 * {@link android.view.inputmethod.EditorInfo#actionId}. This ime actionId sets by 5811 * {@link TextView#setImeActionLabel(CharSequence, int)}, or it would be 5812 * {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific 5813 * actionId has set. A node should expose this action only for views that are currently 5814 * with input focus and editable. 5815 */ 5816 @NonNull public static final AccessibilityAction ACTION_IME_ENTER = 5817 new AccessibilityAction(R.id.accessibilityActionImeEnter); 5818 5819 /** 5820 * Action to start a drag. 5821 * <p> 5822 * This action initiates a drag & drop within the system. The source's dragged content is 5823 * prepared before the drag begins. In View, this action should prepare the arguments to 5824 * {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} and then 5825 * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} with 5826 * {@link View#DRAG_FLAG_ACCESSIBILITY_ACTION}. The equivalent should be performed for other 5827 * UI toolkits. 5828 * </p> 5829 * 5830 * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED 5831 */ 5832 @NonNull public static final AccessibilityAction ACTION_DRAG_START = 5833 new AccessibilityAction(R.id.accessibilityActionDragStart); 5834 5835 /** 5836 * Action to trigger a drop of the content being dragged. 5837 * <p> 5838 * This action is added to potential drop targets if the source started a drag with 5839 * {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted 5840 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an 5841 * {@link View.OnDragListener}, and the drop occurs at the center location of the View's 5842 * window bounds. 5843 * </p> 5844 * 5845 * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED 5846 */ 5847 @NonNull public static final AccessibilityAction ACTION_DRAG_DROP = 5848 new AccessibilityAction(R.id.accessibilityActionDragDrop); 5849 5850 /** 5851 * Action to cancel a drag. 5852 * <p> 5853 * This action is added to the source that started a drag with {@link #ACTION_DRAG_START}. 5854 * </p> 5855 * 5856 * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED 5857 */ 5858 @NonNull public static final AccessibilityAction ACTION_DRAG_CANCEL = 5859 new AccessibilityAction(R.id.accessibilityActionDragCancel); 5860 5861 /** 5862 * Action to show suggestions for editable text. 5863 */ 5864 @NonNull public static final AccessibilityAction ACTION_SHOW_TEXT_SUGGESTIONS = 5865 new AccessibilityAction(R.id.accessibilityActionShowTextSuggestions); 5866 5867 private final int mActionId; 5868 private final CharSequence mLabel; 5869 5870 /** @hide */ 5871 public long mSerializationFlag = -1L; 5872 5873 /** 5874 * Creates a new AccessibilityAction. For adding a standard action without a specific label, 5875 * use the static constants. 5876 * 5877 * You can also override the description for one the standard actions. Below is an example 5878 * how to override the standard click action by adding a custom label: 5879 * <pre> 5880 * AccessibilityAction action = new AccessibilityAction( 5881 * AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel()); 5882 * node.addAction(action); 5883 * </pre> 5884 * 5885 * @param actionId The id for this action. This should either be one of the 5886 * standard actions or a specific action for your app. In that case it is 5887 * required to use a resource identifier. 5888 * @param label The label for the new AccessibilityAction. 5889 */ AccessibilityAction(int actionId, @Nullable CharSequence label)5890 public AccessibilityAction(int actionId, @Nullable CharSequence label) { 5891 mActionId = actionId; 5892 mLabel = label; 5893 } 5894 5895 /** 5896 * Constructor for a {@link #sStandardActions standard} action 5897 */ AccessibilityAction(int standardActionId)5898 private AccessibilityAction(int standardActionId) { 5899 this(standardActionId, null); 5900 5901 mSerializationFlag = bitAt(sStandardActions.size()); 5902 sStandardActions.add(this); 5903 } 5904 5905 /** 5906 * Gets the id for this action. 5907 * 5908 * @return The action id. 5909 */ getId()5910 public int getId() { 5911 return mActionId; 5912 } 5913 5914 /** 5915 * Gets the label for this action. Its purpose is to describe the 5916 * action to user. 5917 * 5918 * @return The label. 5919 */ getLabel()5920 public CharSequence getLabel() { 5921 return mLabel; 5922 } 5923 5924 @Override hashCode()5925 public int hashCode() { 5926 return mActionId; 5927 } 5928 5929 @Override equals(@ullable Object other)5930 public boolean equals(@Nullable Object other) { 5931 if (other == null) { 5932 return false; 5933 } 5934 5935 if (other == this) { 5936 return true; 5937 } 5938 5939 if (getClass() != other.getClass()) { 5940 return false; 5941 } 5942 5943 return mActionId == ((AccessibilityAction)other).mActionId; 5944 } 5945 5946 @Override toString()5947 public String toString() { 5948 return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel; 5949 } 5950 5951 /** 5952 * {@inheritDoc} 5953 */ 5954 @Override describeContents()5955 public int describeContents() { 5956 return 0; 5957 } 5958 5959 /** 5960 * Write data into a parcel. 5961 */ writeToParcel(@onNull Parcel out, int flags)5962 public void writeToParcel(@NonNull Parcel out, int flags) { 5963 out.writeInt(mActionId); 5964 out.writeCharSequence(mLabel); 5965 } 5966 5967 public static final @NonNull Parcelable.Creator<AccessibilityAction> CREATOR = 5968 new Parcelable.Creator<AccessibilityAction>() { 5969 public AccessibilityAction createFromParcel(Parcel in) { 5970 return new AccessibilityAction(in); 5971 } 5972 5973 public AccessibilityAction[] newArray(int size) { 5974 return new AccessibilityAction[size]; 5975 } 5976 }; 5977 AccessibilityAction(Parcel in)5978 private AccessibilityAction(Parcel in) { 5979 mActionId = in.readInt(); 5980 mLabel = in.readCharSequence(); 5981 } 5982 } 5983 5984 /** 5985 * Class with information if a node is a range. 5986 */ 5987 public static final class RangeInfo { 5988 5989 /** Range type: integer. */ 5990 public static final int RANGE_TYPE_INT = 0; 5991 /** Range type: float. */ 5992 public static final int RANGE_TYPE_FLOAT = 1; 5993 /** Range type: percent with values from zero to one hundred. */ 5994 public static final int RANGE_TYPE_PERCENT = 2; 5995 5996 private int mType; 5997 private float mMin; 5998 private float mMax; 5999 private float mCurrent; 6000 /** 6001 * Instantiates a new RangeInfo. 6002 * 6003 * @deprecated Object pooling has been discontinued. Create a new instance using the 6004 * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, float, float, 6005 * float)} instead. 6006 * 6007 * @param type The type of the range. 6008 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no 6009 * minimum. 6010 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no 6011 * maximum. 6012 * @param current The current value. 6013 */ 6014 @Deprecated obtain(int type, float min, float max, float current)6015 public static RangeInfo obtain(int type, float min, float max, float current) { 6016 return new RangeInfo(type, min, max, current); 6017 } 6018 6019 /** 6020 * Creates a new range. 6021 * 6022 * @param type The type of the range. 6023 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no 6024 * minimum. 6025 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no 6026 * maximum. 6027 * @param current The current value. 6028 */ RangeInfo(int type, float min, float max, float current)6029 public RangeInfo(int type, float min, float max, float current) { 6030 mType = type; 6031 mMin = min; 6032 mMax = max; 6033 mCurrent = current; 6034 } 6035 6036 /** 6037 * Gets the range type. 6038 * 6039 * @return The range type. 6040 * 6041 * @see #RANGE_TYPE_INT 6042 * @see #RANGE_TYPE_FLOAT 6043 * @see #RANGE_TYPE_PERCENT 6044 */ getType()6045 public int getType() { 6046 return mType; 6047 } 6048 6049 /** 6050 * Gets the minimum value. 6051 * 6052 * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists. 6053 */ getMin()6054 public float getMin() { 6055 return mMin; 6056 } 6057 6058 /** 6059 * Gets the maximum value. 6060 * 6061 * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists. 6062 */ getMax()6063 public float getMax() { 6064 return mMax; 6065 } 6066 6067 /** 6068 * Gets the current value. 6069 * 6070 * @return The current value. 6071 */ getCurrent()6072 public float getCurrent() { 6073 return mCurrent; 6074 } 6075 6076 /** 6077 * Recycles this instance. 6078 * 6079 * @deprecated Object pooling has been discontinued. Calling this function now will have 6080 * no effect. 6081 */ 6082 @Deprecated recycle()6083 void recycle() {} 6084 clear()6085 private void clear() { 6086 mType = 0; 6087 mMin = 0; 6088 mMax = 0; 6089 mCurrent = 0; 6090 } 6091 } 6092 6093 /** 6094 * Class with information if a node is a collection. 6095 * <p> 6096 * A collection of items has rows and columns and may be hierarchical. 6097 * For example, a horizontal list is a collection with one column, as 6098 * many rows as the list items, and is not hierarchical; A table is a 6099 * collection with several rows, several columns, and is not hierarchical; 6100 * A vertical tree is a hierarchical collection with one column and 6101 * as many rows as the first level children. 6102 * </p> 6103 */ 6104 public static final class CollectionInfo { 6105 /** Selection mode where items are not selectable. */ 6106 public static final int SELECTION_MODE_NONE = 0; 6107 6108 /** Selection mode where a single item may be selected. */ 6109 public static final int SELECTION_MODE_SINGLE = 1; 6110 6111 /** Selection mode where multiple items may be selected. */ 6112 public static final int SELECTION_MODE_MULTIPLE = 2; 6113 6114 /** 6115 * Constant to denote a missing collection count. 6116 * 6117 * This should be used for {@code mItemCount} and 6118 * {@code mImportantForAccessibilityItemCount} when values for those fields are not known. 6119 */ 6120 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) 6121 public static final int UNDEFINED = -1; 6122 6123 private int mRowCount; 6124 private int mColumnCount; 6125 private boolean mHierarchical; 6126 private int mSelectionMode; 6127 private int mItemCount; 6128 private int mImportantForAccessibilityItemCount; 6129 6130 /** 6131 * Instantiates a CollectionInfo that is a clone of another one. 6132 * 6133 * @deprecated Object pooling has been discontinued. Create a new instance using the 6134 * constructor {@link 6135 * AccessibilityNodeInfo.CollectionInfo#CollectionInfo} instead. 6136 * 6137 * @param other The instance to clone. 6138 * @hide 6139 */ obtain(CollectionInfo other)6140 public static CollectionInfo obtain(CollectionInfo other) { 6141 return new CollectionInfo(other.mRowCount, other.mColumnCount, other.mHierarchical, 6142 other.mSelectionMode, other.mItemCount, 6143 other.mImportantForAccessibilityItemCount); 6144 } 6145 6146 /** 6147 * Obtains a pooled instance. 6148 * 6149 * @deprecated Object pooling has been discontinued. Create a new instance using the 6150 * constructor {@link 6151 * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int, 6152 * boolean)} instead. 6153 * 6154 * @param rowCount The number of rows, or -1 if count is unknown. 6155 * @param columnCount The number of columns, or -1 if count is unknown. 6156 * @param hierarchical Whether the collection is hierarchical. 6157 */ obtain(int rowCount, int columnCount, boolean hierarchical)6158 public static CollectionInfo obtain(int rowCount, int columnCount, 6159 boolean hierarchical) { 6160 return new CollectionInfo(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE); 6161 } 6162 6163 /** 6164 * Obtains a pooled instance. 6165 * 6166 * @deprecated Object pooling has been discontinued. Create a new instance using the 6167 * constructor {@link 6168 * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int, 6169 * boolean, int)} instead. 6170 * 6171 * @param rowCount The number of rows. 6172 * @param columnCount The number of columns. 6173 * @param hierarchical Whether the collection is hierarchical. 6174 * @param selectionMode The collection's selection mode, one of: 6175 * <ul> 6176 * <li>{@link #SELECTION_MODE_NONE} 6177 * <li>{@link #SELECTION_MODE_SINGLE} 6178 * <li>{@link #SELECTION_MODE_MULTIPLE} 6179 * </ul> 6180 */ obtain(int rowCount, int columnCount, boolean hierarchical, int selectionMode)6181 public static CollectionInfo obtain(int rowCount, int columnCount, 6182 boolean hierarchical, int selectionMode) { 6183 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode); 6184 } 6185 6186 /** 6187 * Creates a new instance. 6188 * 6189 * @param rowCount The number of rows. 6190 * @param columnCount The number of columns. 6191 * @param hierarchical Whether the collection is hierarchical. 6192 */ CollectionInfo(int rowCount, int columnCount, boolean hierarchical)6193 public CollectionInfo(int rowCount, int columnCount, boolean hierarchical) { 6194 this(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE); 6195 } 6196 6197 /** 6198 * Creates a new instance. 6199 * 6200 * @param rowCount The number of rows. 6201 * @param columnCount The number of columns. 6202 * @param hierarchical Whether the collection is hierarchical. 6203 * @param selectionMode The collection's selection mode. 6204 */ CollectionInfo(int rowCount, int columnCount, boolean hierarchical, int selectionMode)6205 public CollectionInfo(int rowCount, int columnCount, boolean hierarchical, 6206 int selectionMode) { 6207 mRowCount = rowCount; 6208 mColumnCount = columnCount; 6209 mHierarchical = hierarchical; 6210 mSelectionMode = selectionMode; 6211 mItemCount = UNDEFINED; 6212 mImportantForAccessibilityItemCount = UNDEFINED; 6213 } 6214 6215 /** 6216 * Creates a new instance. 6217 * 6218 * @param rowCount The number of rows. 6219 * @param columnCount The number of columns. 6220 * @param hierarchical Whether the collection is hierarchical. 6221 * @param selectionMode The collection's selection mode. 6222 * @param itemCount The collection's item count, which includes items that are unimportant 6223 * for accessibility. When ViewGroups map cleanly to both row and column 6224 * semantics, clients should populate the row and column counts and 6225 * optionally populate this field. In all other cases, clients should 6226 * populate this field so that accessibility services can use it to relay 6227 * the collection size to users. This should be set to {@code UNDEFINED} if 6228 * the item count is not known. 6229 * @param importantForAccessibilityItemCount The count of the collection's views considered 6230 * important for accessibility. 6231 * @hide 6232 */ CollectionInfo(int rowCount, int columnCount, boolean hierarchical, int selectionMode, int itemCount, int importantForAccessibilityItemCount)6233 public CollectionInfo(int rowCount, int columnCount, boolean hierarchical, 6234 int selectionMode, int itemCount, int importantForAccessibilityItemCount) { 6235 mRowCount = rowCount; 6236 mColumnCount = columnCount; 6237 mHierarchical = hierarchical; 6238 mSelectionMode = selectionMode; 6239 mItemCount = itemCount; 6240 mImportantForAccessibilityItemCount = importantForAccessibilityItemCount; 6241 } 6242 6243 /** 6244 * Gets the number of rows. 6245 * 6246 * @return The row count, or -1 if count is unknown. 6247 */ getRowCount()6248 public int getRowCount() { 6249 return mRowCount; 6250 } 6251 6252 /** 6253 * Gets the number of columns. 6254 * 6255 * @return The column count, or -1 if count is unknown. 6256 */ getColumnCount()6257 public int getColumnCount() { 6258 return mColumnCount; 6259 } 6260 6261 /** 6262 * Gets if the collection is a hierarchically ordered. 6263 * 6264 * @return Whether the collection is hierarchical. 6265 */ isHierarchical()6266 public boolean isHierarchical() { 6267 return mHierarchical; 6268 } 6269 6270 /** 6271 * Gets the collection's selection mode. 6272 * 6273 * @return The collection's selection mode, one of: 6274 * <ul> 6275 * <li>{@link #SELECTION_MODE_NONE} 6276 * <li>{@link #SELECTION_MODE_SINGLE} 6277 * <li>{@link #SELECTION_MODE_MULTIPLE} 6278 * </ul> 6279 */ getSelectionMode()6280 public int getSelectionMode() { 6281 return mSelectionMode; 6282 } 6283 6284 /** 6285 * Gets the number of items in the collection. 6286 * 6287 * @return The count of items, which may be {@code UNDEFINED} if the count is not known. 6288 */ 6289 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) getItemCount()6290 public int getItemCount() { 6291 return mItemCount; 6292 } 6293 6294 /** 6295 * Gets the number of items in the collection considered important for accessibility. 6296 * 6297 * @return The count of items important for accessibility, which may be {@code UNDEFINED} 6298 * if the count is not known. 6299 */ 6300 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) getImportantForAccessibilityItemCount()6301 public int getImportantForAccessibilityItemCount() { 6302 return mImportantForAccessibilityItemCount; 6303 } 6304 6305 /** 6306 * Previously would recycle this instance. 6307 * 6308 * @deprecated Object pooling has been discontinued. Calling this function now will have 6309 * no effect. 6310 */ 6311 @Deprecated recycle()6312 void recycle() {} 6313 clear()6314 private void clear() { 6315 mRowCount = 0; 6316 mColumnCount = 0; 6317 mHierarchical = false; 6318 mSelectionMode = SELECTION_MODE_NONE; 6319 mItemCount = UNDEFINED; 6320 mImportantForAccessibilityItemCount = UNDEFINED; 6321 } 6322 6323 /** 6324 * The builder for CollectionInfo. 6325 */ 6326 6327 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) 6328 public static final class Builder { 6329 private int mRowCount = 0; 6330 private int mColumnCount = 0; 6331 private boolean mHierarchical = false; 6332 private int mSelectionMode; 6333 private int mItemCount = UNDEFINED; 6334 private int mImportantForAccessibilityItemCount = UNDEFINED; 6335 6336 /** 6337 * Creates a new Builder. 6338 */ 6339 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) Builder()6340 public Builder() { 6341 } 6342 6343 /** 6344 * Sets the row count. 6345 * @param rowCount The number of rows in the collection. 6346 * @return This builder. 6347 */ 6348 @NonNull 6349 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setRowCount(int rowCount)6350 public CollectionInfo.Builder setRowCount(int rowCount) { 6351 mRowCount = rowCount; 6352 return this; 6353 } 6354 6355 /** 6356 * Sets the column count. 6357 * @param columnCount The number of columns in the collection. 6358 * @return This builder. 6359 */ 6360 @NonNull 6361 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setColumnCount(int columnCount)6362 public CollectionInfo.Builder setColumnCount(int columnCount) { 6363 mColumnCount = columnCount; 6364 return this; 6365 } 6366 /** 6367 * Sets whether the collection is hierarchical. 6368 * @param hierarchical Whether the collection is hierarchical. 6369 * @return This builder. 6370 */ 6371 @NonNull 6372 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setHierarchical(boolean hierarchical)6373 public CollectionInfo.Builder setHierarchical(boolean hierarchical) { 6374 mHierarchical = hierarchical; 6375 return this; 6376 } 6377 6378 /** 6379 * Sets the selection mode. 6380 * @param selectionMode The selection mode. 6381 * @return This builder. 6382 */ 6383 @NonNull 6384 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setSelectionMode(int selectionMode)6385 public CollectionInfo.Builder setSelectionMode(int selectionMode) { 6386 mSelectionMode = selectionMode; 6387 return this; 6388 } 6389 6390 /** 6391 * Sets the number of items in the collection. Can be optionally set for ViewGroups with 6392 * clear row and column semantics; should be set for all other clients. 6393 * 6394 * @param itemCount The number of items in the collection. This should be set to 6395 * {@code UNDEFINED} if the item count is not known. 6396 * @return This builder. 6397 */ 6398 @NonNull 6399 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setItemCount(int itemCount)6400 public CollectionInfo.Builder setItemCount(int itemCount) { 6401 mItemCount = itemCount; 6402 return this; 6403 } 6404 6405 /** 6406 * Sets the number of views considered important for accessibility. 6407 * @param importantForAccessibilityItemCount The number of items important for 6408 * accessibility. 6409 * @return This builder. 6410 */ 6411 @NonNull 6412 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) setImportantForAccessibilityItemCount( int importantForAccessibilityItemCount)6413 public CollectionInfo.Builder setImportantForAccessibilityItemCount( 6414 int importantForAccessibilityItemCount) { 6415 mImportantForAccessibilityItemCount = importantForAccessibilityItemCount; 6416 return this; 6417 } 6418 6419 /** 6420 * Creates a new {@link CollectionInfo} instance. 6421 */ 6422 @NonNull 6423 @FlaggedApi(Flags.FLAG_COLLECTION_INFO_ITEM_COUNTS) build()6424 public CollectionInfo build() { 6425 CollectionInfo collectionInfo = new CollectionInfo(mRowCount, mColumnCount, 6426 mHierarchical); 6427 collectionInfo.mSelectionMode = mSelectionMode; 6428 collectionInfo.mItemCount = mItemCount; 6429 collectionInfo.mImportantForAccessibilityItemCount = 6430 mImportantForAccessibilityItemCount; 6431 return collectionInfo; 6432 } 6433 } 6434 } 6435 6436 /** 6437 * Class with information if a node is a collection item. 6438 * <p> 6439 * A collection item is contained in a collection, it starts at 6440 * a given row and column in the collection, and spans one or 6441 * more rows and columns. For example, a header of two related 6442 * table columns starts at the first row and the first column, 6443 * spans one row and two columns. 6444 * </p> 6445 */ 6446 public static final class CollectionItemInfo { 6447 /** 6448 * Instantiates a CollectionItemInfo that is a clone of another one. 6449 * 6450 * @deprecated Object pooling has been discontinued. Create a new instance using the 6451 * constructor {@link 6452 * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo} 6453 * instead. 6454 * 6455 * @param other The instance to clone. 6456 * @hide 6457 */ 6458 @Deprecated obtain(CollectionItemInfo other)6459 public static CollectionItemInfo obtain(CollectionItemInfo other) { 6460 return new CollectionItemInfo(other.mRowTitle, other.mRowIndex, other.mRowSpan, 6461 other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading, 6462 other.mSelected); 6463 } 6464 6465 /** 6466 * Instantiates a new CollectionItemInfo. 6467 * 6468 * @deprecated Object pooling has been discontinued. Create a new instance using the 6469 * constructor {@link 6470 * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, 6471 * int, int, int, boolean)} instead. 6472 * @param rowIndex The row index at which the item is located. 6473 * @param rowSpan The number of rows the item spans. 6474 * @param columnIndex The column index at which the item is located. 6475 * @param columnSpan The number of columns the item spans. 6476 * @param heading Whether the item is a heading. (Prefer 6477 * {@link AccessibilityNodeInfo#setHeading(boolean)}). 6478 */ 6479 @Deprecated obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading)6480 public static CollectionItemInfo obtain(int rowIndex, int rowSpan, 6481 int columnIndex, int columnSpan, boolean heading) { 6482 return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading, 6483 false); 6484 } 6485 6486 /** 6487 * Instantiates a new CollectionItemInfo. 6488 * 6489 * @deprecated Object pooling has been discontinued. Create a new instance using the 6490 * constructor {@link 6491 * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, 6492 * int, int, int, boolean)} instead. 6493 * @param rowIndex The row index at which the item is located. 6494 * @param rowSpan The number of rows the item spans. 6495 * @param columnIndex The column index at which the item is located. 6496 * @param columnSpan The number of columns the item spans. 6497 * @param heading Whether the item is a heading. (Prefer 6498 * {@link AccessibilityNodeInfo#setHeading(boolean)}). 6499 * @param selected Whether the item is selected. 6500 */ 6501 @Deprecated obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected)6502 public static CollectionItemInfo obtain(int rowIndex, int rowSpan, 6503 int columnIndex, int columnSpan, boolean heading, boolean selected) { 6504 return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading, 6505 selected); 6506 } 6507 6508 /** 6509 * Instantiates a new CollectionItemInfo. 6510 * 6511 * @deprecated Object pooling has been discontinued. Creates a new instance using the 6512 * constructor {@link 6513 * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, 6514 * int, int, int, boolean, boolean)} instead. 6515 * 6516 * @param rowTitle The row title at which the item is located. 6517 * @param rowIndex The row index at which the item is located. 6518 * @param rowSpan The number of rows the item spans. 6519 * @param columnTitle The column title at which the item is located. 6520 * @param columnIndex The column index at which the item is located. 6521 * @param columnSpan The number of columns the item spans. 6522 * @param heading Whether the item is a heading. (Prefer 6523 * {@link AccessibilityNodeInfo#setHeading(boolean)}) 6524 * @param selected Whether the item is selected. 6525 * @removed 6526 */ 6527 @Deprecated 6528 @NonNull obtain(@ullable String rowTitle, int rowIndex, int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan, boolean heading, boolean selected)6529 public static CollectionItemInfo obtain(@Nullable String rowTitle, int rowIndex, 6530 int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan, 6531 boolean heading, boolean selected) { 6532 return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle, columnIndex, 6533 columnSpan, heading, selected); 6534 } 6535 6536 private boolean mHeading; 6537 private int mColumnIndex; 6538 private int mRowIndex; 6539 private int mColumnSpan; 6540 private int mRowSpan; 6541 private boolean mSelected; 6542 private String mRowTitle; 6543 private String mColumnTitle; 6544 CollectionItemInfo()6545 private CollectionItemInfo() { 6546 /* do nothing */ 6547 } 6548 6549 /** 6550 * Creates a new instance. 6551 * 6552 * @param rowIndex The row index at which the item is located. 6553 * @param rowSpan The number of rows the item spans. 6554 * @param columnIndex The column index at which the item is located. 6555 * @param columnSpan The number of columns the item spans. 6556 * @param heading Whether the item is a heading. 6557 */ CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading)6558 public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, 6559 boolean heading) { 6560 this(rowIndex, rowSpan, columnIndex, columnSpan, heading, false); 6561 } 6562 6563 /** 6564 * Creates a new instance. 6565 * 6566 * @param rowIndex The row index at which the item is located. 6567 * @param rowSpan The number of rows the item spans. 6568 * @param columnIndex The column index at which the item is located. 6569 * @param columnSpan The number of columns the item spans. 6570 * @param heading Whether the item is a heading. 6571 * @param selected Whether the item is selected. 6572 */ CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected)6573 public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, 6574 boolean heading, boolean selected) { 6575 this(null, rowIndex, rowSpan, null, columnIndex, columnSpan, 6576 heading, selected); 6577 } 6578 6579 /** 6580 * Creates a new instance. 6581 * 6582 * @param rowTitle The row title at which the item is located. 6583 * @param rowIndex The row index at which the item is located. 6584 * @param rowSpan The number of rows the item spans. 6585 * @param columnTitle The column title at which the item is located. 6586 * @param columnIndex The column index at which the item is located. 6587 * @param columnSpan The number of columns the item spans. 6588 * @param heading Whether the item is a heading. 6589 * @param selected Whether the item is selected. 6590 * @hide 6591 */ CollectionItemInfo(@ullable String rowTitle, int rowIndex, int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan, boolean heading, boolean selected)6592 public CollectionItemInfo(@Nullable String rowTitle, int rowIndex, int rowSpan, 6593 @Nullable String columnTitle, int columnIndex, int columnSpan, boolean heading, 6594 boolean selected) { 6595 mRowIndex = rowIndex; 6596 mRowSpan = rowSpan; 6597 mColumnIndex = columnIndex; 6598 mColumnSpan = columnSpan; 6599 mHeading = heading; 6600 mSelected = selected; 6601 mRowTitle = rowTitle; 6602 mColumnTitle = columnTitle; 6603 } 6604 6605 /** 6606 * Gets the column index at which the item is located. 6607 * 6608 * @return The column index. 6609 */ getColumnIndex()6610 public int getColumnIndex() { 6611 return mColumnIndex; 6612 } 6613 6614 /** 6615 * Gets the row index at which the item is located. 6616 * 6617 * @return The row index. 6618 */ getRowIndex()6619 public int getRowIndex() { 6620 return mRowIndex; 6621 } 6622 6623 /** 6624 * Gets the number of columns the item spans. 6625 * 6626 * @return The column span. 6627 */ getColumnSpan()6628 public int getColumnSpan() { 6629 return mColumnSpan; 6630 } 6631 6632 /** 6633 * Gets the number of rows the item spans. 6634 * 6635 * @return The row span. 6636 */ getRowSpan()6637 public int getRowSpan() { 6638 return mRowSpan; 6639 } 6640 6641 /** 6642 * Gets if the collection item is a heading. For example, section 6643 * heading, table header, etc. 6644 * 6645 * @return If the item is a heading. 6646 * @deprecated Use {@link AccessibilityNodeInfo#isHeading()} 6647 */ isHeading()6648 public boolean isHeading() { 6649 return mHeading; 6650 } 6651 6652 /** 6653 * Gets if the collection item is selected. 6654 * 6655 * @return If the item is selected. 6656 */ isSelected()6657 public boolean isSelected() { 6658 return mSelected; 6659 } 6660 6661 /** 6662 * Gets the row title at which the item is located. 6663 * 6664 * @return The row title. 6665 */ 6666 @Nullable getRowTitle()6667 public String getRowTitle() { 6668 return mRowTitle; 6669 } 6670 6671 /** 6672 * Gets the column title at which the item is located. 6673 * 6674 * @return The column title. 6675 */ 6676 @Nullable getColumnTitle()6677 public String getColumnTitle() { 6678 return mColumnTitle; 6679 } 6680 6681 /** 6682 * Recycles this instance. 6683 * 6684 * @deprecated Object pooling has been discontinued. Calling this function now will have 6685 * no effect. 6686 */ 6687 @Deprecated recycle()6688 void recycle() {} 6689 clear()6690 private void clear() { 6691 mColumnIndex = 0; 6692 mColumnSpan = 0; 6693 mRowIndex = 0; 6694 mRowSpan = 0; 6695 mHeading = false; 6696 mSelected = false; 6697 mRowTitle = null; 6698 mColumnTitle = null; 6699 } 6700 6701 /** 6702 * Builder for creating {@link CollectionItemInfo} objects. 6703 */ 6704 public static final class Builder { 6705 private boolean mHeading; 6706 private int mColumnIndex; 6707 private int mRowIndex; 6708 private int mColumnSpan; 6709 private int mRowSpan; 6710 private boolean mSelected; 6711 private String mRowTitle; 6712 private String mColumnTitle; 6713 6714 /** 6715 * Creates a new Builder. 6716 */ Builder()6717 public Builder() { 6718 } 6719 6720 /** 6721 * Sets the collection item is a heading. 6722 * 6723 * @param heading The heading state 6724 * @return This builder 6725 */ 6726 @NonNull setHeading(boolean heading)6727 public CollectionItemInfo.Builder setHeading(boolean heading) { 6728 mHeading = heading; 6729 return this; 6730 } 6731 6732 /** 6733 * Sets the column index at which the item is located. 6734 * 6735 * @param columnIndex The column index 6736 * @return This builder 6737 */ 6738 @NonNull setColumnIndex(int columnIndex)6739 public CollectionItemInfo.Builder setColumnIndex(int columnIndex) { 6740 mColumnIndex = columnIndex; 6741 return this; 6742 } 6743 6744 /** 6745 * Sets the row index at which the item is located. 6746 * 6747 * @param rowIndex The row index 6748 * @return This builder 6749 */ 6750 @NonNull setRowIndex(int rowIndex)6751 public CollectionItemInfo.Builder setRowIndex(int rowIndex) { 6752 mRowIndex = rowIndex; 6753 return this; 6754 } 6755 6756 /** 6757 * Sets the number of columns the item spans. 6758 * 6759 * @param columnSpan The number of columns spans 6760 * @return This builder 6761 */ 6762 @NonNull setColumnSpan(int columnSpan)6763 public CollectionItemInfo.Builder setColumnSpan(int columnSpan) { 6764 mColumnSpan = columnSpan; 6765 return this; 6766 } 6767 6768 /** 6769 * Sets the number of rows the item spans. 6770 * 6771 * @param rowSpan The number of rows spans 6772 * @return This builder 6773 */ 6774 @NonNull setRowSpan(int rowSpan)6775 public CollectionItemInfo.Builder setRowSpan(int rowSpan) { 6776 mRowSpan = rowSpan; 6777 return this; 6778 } 6779 6780 /** 6781 * Sets the collection item is selected. 6782 * 6783 * @param selected The number of rows spans 6784 * @return This builder 6785 */ 6786 @NonNull setSelected(boolean selected)6787 public CollectionItemInfo.Builder setSelected(boolean selected) { 6788 mSelected = selected; 6789 return this; 6790 } 6791 6792 /** 6793 * Sets the row title at which the item is located. 6794 * 6795 * @param rowTitle The row title 6796 * @return This builder 6797 */ 6798 @NonNull setRowTitle(@ullable String rowTitle)6799 public CollectionItemInfo.Builder setRowTitle(@Nullable String rowTitle) { 6800 mRowTitle = rowTitle; 6801 return this; 6802 } 6803 6804 /** 6805 * Sets the column title at which the item is located. 6806 * 6807 * @param columnTitle The column title 6808 * @return This builder 6809 */ 6810 @NonNull setColumnTitle(@ullable String columnTitle)6811 public CollectionItemInfo.Builder setColumnTitle(@Nullable String columnTitle) { 6812 mColumnTitle = columnTitle; 6813 return this; 6814 } 6815 6816 /** 6817 * Builds and returns a {@link CollectionItemInfo}. 6818 */ 6819 @NonNull build()6820 public CollectionItemInfo build() { 6821 CollectionItemInfo collectionItemInfo = new CollectionItemInfo(); 6822 collectionItemInfo.mHeading = mHeading; 6823 collectionItemInfo.mColumnIndex = mColumnIndex; 6824 collectionItemInfo.mRowIndex = mRowIndex; 6825 collectionItemInfo.mColumnSpan = mColumnSpan; 6826 collectionItemInfo.mRowSpan = mRowSpan; 6827 collectionItemInfo.mSelected = mSelected; 6828 collectionItemInfo.mRowTitle = mRowTitle; 6829 collectionItemInfo.mColumnTitle = mColumnTitle; 6830 6831 return collectionItemInfo; 6832 } 6833 } 6834 } 6835 6836 /** 6837 * Class with information of touch delegated views and regions from {@link TouchDelegate} for 6838 * the {@link AccessibilityNodeInfo}. 6839 * 6840 * @see AccessibilityNodeInfo#setTouchDelegateInfo(TouchDelegateInfo) 6841 */ 6842 public static final class TouchDelegateInfo implements Parcelable { 6843 private ArrayMap<Region, Long> mTargetMap; 6844 // Two ids are initialized lazily in AccessibilityNodeInfo#getTouchDelegateInfo 6845 private int mConnectionId; 6846 private int mWindowId; 6847 6848 /** 6849 * Create a new instance of {@link TouchDelegateInfo}. 6850 * 6851 * @param targetMap A map from regions (in view coordinates) to delegated views. 6852 * @throws IllegalArgumentException if targetMap is empty or {@code null} in 6853 * Regions or Views. 6854 */ TouchDelegateInfo(@onNull Map<Region, View> targetMap)6855 public TouchDelegateInfo(@NonNull Map<Region, View> targetMap) { 6856 Preconditions.checkArgument(!targetMap.isEmpty() 6857 && !targetMap.containsKey(null) && !targetMap.containsValue(null)); 6858 mTargetMap = new ArrayMap<>(targetMap.size()); 6859 for (final Region region : targetMap.keySet()) { 6860 final View view = targetMap.get(region); 6861 mTargetMap.put(region, (long) view.getAccessibilityViewId()); 6862 } 6863 } 6864 6865 /** 6866 * Create a new instance from target map. 6867 * 6868 * @param targetMap A map from regions (in view coordinates) to delegated views' 6869 * accessibility id. 6870 * @param doCopy True if shallow copy targetMap. 6871 * @throws IllegalArgumentException if targetMap is empty or {@code null} in 6872 * Regions or Views. 6873 */ TouchDelegateInfo(@onNull ArrayMap<Region, Long> targetMap, boolean doCopy)6874 TouchDelegateInfo(@NonNull ArrayMap<Region, Long> targetMap, boolean doCopy) { 6875 Preconditions.checkArgument(!targetMap.isEmpty() 6876 && !targetMap.containsKey(null) && !targetMap.containsValue(null)); 6877 if (doCopy) { 6878 mTargetMap = new ArrayMap<>(targetMap.size()); 6879 mTargetMap.putAll(targetMap); 6880 } else { 6881 mTargetMap = targetMap; 6882 } 6883 } 6884 6885 /** 6886 * Set the connection ID. 6887 * 6888 * @param connectionId The connection id. 6889 */ setConnectionId(int connectionId)6890 private void setConnectionId(int connectionId) { 6891 mConnectionId = connectionId; 6892 } 6893 6894 /** 6895 * Set the window ID. 6896 * 6897 * @param windowId The window id. 6898 */ setWindowId(int windowId)6899 private void setWindowId(int windowId) { 6900 mWindowId = windowId; 6901 } 6902 6903 /** 6904 * Returns the number of touch delegate target region. 6905 * 6906 * @return Number of touch delegate target region. 6907 */ getRegionCount()6908 public int getRegionCount() { 6909 return mTargetMap.size(); 6910 } 6911 6912 /** 6913 * Return the {@link Region} at the given index in the {@link TouchDelegateInfo}. 6914 * 6915 * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1. 6916 * @return Returns the {@link Region} stored at the given index. 6917 */ 6918 @NonNull getRegionAt(int index)6919 public Region getRegionAt(int index) { 6920 return mTargetMap.keyAt(index); 6921 } 6922 6923 /** 6924 * Return the target {@link AccessibilityNodeInfo} for the given {@link Region}. 6925 * <p> 6926 * <strong>Note:</strong> This api can only be called from {@link AccessibilityService}. 6927 * </p> 6928 * 6929 * @param region The region retrieved from {@link #getRegionAt(int)}. 6930 * @return The target node associates with the given region. 6931 */ 6932 @Nullable getTargetForRegion(@onNull Region region)6933 public AccessibilityNodeInfo getTargetForRegion(@NonNull Region region) { 6934 return getNodeForAccessibilityId(mConnectionId, mWindowId, mTargetMap.get(region)); 6935 } 6936 6937 /** 6938 * Return the accessibility id of target node. 6939 * 6940 * @param region The region retrieved from {@link #getRegionAt(int)}. 6941 * @return The accessibility id of target node. 6942 * 6943 * @hide 6944 */ 6945 @TestApi getAccessibilityIdForRegion(@onNull Region region)6946 public long getAccessibilityIdForRegion(@NonNull Region region) { 6947 return mTargetMap.get(region); 6948 } 6949 6950 /** 6951 * {@inheritDoc} 6952 */ 6953 @Override describeContents()6954 public int describeContents() { 6955 return 0; 6956 } 6957 6958 /** 6959 * {@inheritDoc} 6960 */ 6961 @Override writeToParcel(Parcel dest, int flags)6962 public void writeToParcel(Parcel dest, int flags) { 6963 dest.writeInt(mTargetMap.size()); 6964 for (int i = 0; i < mTargetMap.size(); i++) { 6965 final Region region = mTargetMap.keyAt(i); 6966 final Long accessibilityId = mTargetMap.valueAt(i); 6967 region.writeToParcel(dest, flags); 6968 dest.writeLong(accessibilityId); 6969 } 6970 } 6971 6972 /** 6973 * @see android.os.Parcelable.Creator 6974 */ 6975 public static final @NonNull Parcelable.Creator<TouchDelegateInfo> CREATOR = 6976 new Parcelable.Creator<TouchDelegateInfo>() { 6977 @Override 6978 public TouchDelegateInfo createFromParcel(Parcel parcel) { 6979 final int size = parcel.readInt(); 6980 if (size == 0) { 6981 return null; 6982 } 6983 final ArrayMap<Region, Long> targetMap = new ArrayMap<>(size); 6984 for (int i = 0; i < size; i++) { 6985 final Region region = Region.CREATOR.createFromParcel(parcel); 6986 final long accessibilityId = parcel.readLong(); 6987 targetMap.put(region, accessibilityId); 6988 } 6989 final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo( 6990 targetMap, false); 6991 return touchDelegateInfo; 6992 } 6993 6994 @Override 6995 public TouchDelegateInfo[] newArray(int size) { 6996 return new TouchDelegateInfo[size]; 6997 } 6998 }; 6999 } 7000 7001 /** 7002 * Class with information of a view useful to evaluate accessibility needs. Developers can 7003 * refresh the node with the key {@link #EXTRA_DATA_RENDERING_INFO_KEY} to fetch the text size 7004 * and unit if it is {@link TextView} and the height and the width of layout params from 7005 * {@link ViewGroup} or {@link TextView}. 7006 * 7007 * @see #EXTRA_DATA_RENDERING_INFO_KEY 7008 * @see #refreshWithExtraData(String, Bundle) 7009 */ 7010 public static final class ExtraRenderingInfo { 7011 private static final int UNDEFINED_VALUE = -1; 7012 7013 private Size mLayoutSize; 7014 private float mTextSizeInPx = UNDEFINED_VALUE; 7015 private int mTextSizeUnit = UNDEFINED_VALUE; 7016 7017 /** 7018 * Instantiates an ExtraRenderingInfo, by copying an existing one. 7019 * 7020 * @hide 7021 * @deprecated Object pooling has been discontinued. Create a new instance using the 7022 * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead. 7023 */ 7024 @Deprecated 7025 @NonNull obtain()7026 public static ExtraRenderingInfo obtain() { 7027 return new ExtraRenderingInfo(null); 7028 } 7029 7030 /** 7031 * Instantiates an ExtraRenderingInfo, by copying an existing one. 7032 * 7033 * @deprecated Object pooling has been discontinued. Create a new instance using the 7034 * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead. 7035 * @param other 7036 */ 7037 @Deprecated obtain(ExtraRenderingInfo other)7038 private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) { 7039 return new ExtraRenderingInfo(other); 7040 } 7041 7042 /** 7043 * Creates a new rendering info of a view, and this new instance is initialized from 7044 * the given <code>other</code>. 7045 * 7046 * @param other The instance to clone. 7047 */ ExtraRenderingInfo(@ullable ExtraRenderingInfo other)7048 private ExtraRenderingInfo(@Nullable ExtraRenderingInfo other) { 7049 if (other != null) { 7050 mLayoutSize = other.mLayoutSize; 7051 mTextSizeInPx = other.mTextSizeInPx; 7052 mTextSizeUnit = other.mTextSizeUnit; 7053 } 7054 } 7055 7056 /** 7057 * Gets the size object containing the height and the width of 7058 * {@link android.view.ViewGroup.LayoutParams} if the node is a {@link ViewGroup} or 7059 * a {@link TextView}, or null otherwise. Useful for some accessibility services to 7060 * understand whether the text is scalable and fits the view or not. 7061 * 7062 * @return a {@link Size} stores layout height and layout width of the view, or null 7063 * otherwise. And the size value may be in pixels, 7064 * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}, 7065 * or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} 7066 */ getLayoutSize()7067 public @Nullable Size getLayoutSize() { 7068 return mLayoutSize; 7069 } 7070 7071 /** 7072 * Sets layout width and layout height of the view. 7073 * 7074 * @param width The layout width. 7075 * @param height The layout height. 7076 * @hide 7077 */ setLayoutSize(int width, int height)7078 public void setLayoutSize(int width, int height) { 7079 mLayoutSize = new Size(width, height); 7080 } 7081 7082 /** 7083 * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for some 7084 * accessibility services to understand whether the text is scalable and fits the view or 7085 * not. 7086 * 7087 * @return the text size of a {@code TextView}, or -1 otherwise. 7088 */ getTextSizeInPx()7089 public float getTextSizeInPx() { 7090 return mTextSizeInPx; 7091 } 7092 7093 /** 7094 * Sets text size of the view. 7095 * 7096 * @param textSizeInPx The text size in pixels. 7097 * @hide 7098 */ setTextSizeInPx(float textSizeInPx)7099 public void setTextSizeInPx(float textSizeInPx) { 7100 mTextSizeInPx = textSizeInPx; 7101 } 7102 7103 /** 7104 * Gets the text size unit if the node is a {@link TextView}, or -1 otherwise. 7105 * Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and 7106 * convert from other units. Useful for some accessibility services to understand whether 7107 * the text is scalable and fits the view or not. 7108 * 7109 * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a 7110 * {@code TextView}, or -1 otherwise. 7111 * 7112 * @see TypedValue#TYPE_DIMENSION 7113 */ getTextSizeUnit()7114 public int getTextSizeUnit() { 7115 return mTextSizeUnit; 7116 } 7117 7118 /** 7119 * Sets text size unit of the view. 7120 * 7121 * @param textSizeUnit The text size unit. 7122 * @hide 7123 */ setTextSizeUnit(int textSizeUnit)7124 public void setTextSizeUnit(int textSizeUnit) { 7125 mTextSizeUnit = textSizeUnit; 7126 } 7127 7128 /** 7129 * Previously would recycle this instance. 7130 * 7131 * @deprecated Object pooling has been discontinued. Calling this function now will have 7132 * no effect. 7133 */ 7134 @Deprecated recycle()7135 void recycle() {} 7136 clear()7137 private void clear() { 7138 mLayoutSize = null; 7139 mTextSizeInPx = UNDEFINED_VALUE; 7140 mTextSizeUnit = UNDEFINED_VALUE; 7141 } 7142 } 7143 7144 /** 7145 * @see android.os.Parcelable.Creator 7146 */ 7147 public static final @NonNull Parcelable.Creator<AccessibilityNodeInfo> CREATOR = 7148 new Parcelable.Creator<AccessibilityNodeInfo>() { 7149 @Override 7150 public AccessibilityNodeInfo createFromParcel(Parcel parcel) { 7151 AccessibilityNodeInfo info = new AccessibilityNodeInfo(); 7152 info.initFromParcel(parcel); 7153 return info; 7154 } 7155 7156 @Override 7157 public AccessibilityNodeInfo[] newArray(int size) { 7158 return new AccessibilityNodeInfo[size]; 7159 } 7160 }; 7161 } 7162