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