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