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