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