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