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