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