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