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