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