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