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