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