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