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