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