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