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