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 17 package android.view.accessibility; 18 19 import static com.android.internal.util.CollectionUtils.isEmpty; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.TestApi; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.os.Parcelable; 26 import android.view.Display; 27 import android.view.View; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Represents a record in an {@link AccessibilityEvent} and contains information 34 * about state change of its source {@link android.view.View}. When a view fires 35 * an accessibility event it requests from its parent to dispatch the 36 * constructed event. The parent may optionally append a record for itself 37 * for providing more context to 38 * {@link android.accessibilityservice.AccessibilityService}s. Hence, 39 * accessibility services can facilitate additional accessibility records 40 * to enhance feedback. 41 * </p> 42 * <p> 43 * Once the accessibility event containing a record is dispatched the record is 44 * made immutable and calling a state mutation method generates an error. 45 * </p> 46 * <p> 47 * <strong>Note:</strong> Not all properties are applicable to all accessibility 48 * event types. For detailed information please refer to {@link AccessibilityEvent}. 49 * </p> 50 * 51 * <div class="special reference"> 52 * <h3>Developer Guides</h3> 53 * <p>For more information about creating and processing AccessibilityRecords, read the 54 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 55 * developer guide.</p> 56 * </div> 57 * 58 * @see AccessibilityEvent 59 * @see AccessibilityManager 60 * @see android.accessibilityservice.AccessibilityService 61 * @see AccessibilityNodeInfo 62 */ 63 public class AccessibilityRecord { 64 /** @hide */ 65 protected static final boolean DEBUG_CONCISE_TOSTRING = false; 66 67 private static final int UNDEFINED = -1; 68 69 private static final int PROPERTY_CHECKED = 1 /* << 0 */; 70 private static final int PROPERTY_ENABLED = 1 << 1; 71 private static final int PROPERTY_PASSWORD = 1 << 2; 72 private static final int PROPERTY_FULL_SCREEN = 1 << 7; 73 private static final int PROPERTY_SCROLLABLE = 1 << 8; 74 private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 1 << 9; 75 private static final int PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 1 << 10; 76 77 private static final int GET_SOURCE_PREFETCH_FLAGS = 78 AccessibilityNodeInfo.FLAG_PREFETCH_ANCESTORS 79 | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS 80 | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID; 81 82 @UnsupportedAppUsage 83 boolean mSealed; 84 int mBooleanProperties = 0; 85 int mCurrentItemIndex = UNDEFINED; 86 int mItemCount = UNDEFINED; 87 int mFromIndex = UNDEFINED; 88 int mToIndex = UNDEFINED; 89 int mScrollX = 0; 90 int mScrollY = 0; 91 92 int mScrollDeltaX = UNDEFINED; 93 int mScrollDeltaY = UNDEFINED; 94 int mMaxScrollX = 0; 95 int mMaxScrollY = 0; 96 97 int mAddedCount= UNDEFINED; 98 int mRemovedCount = UNDEFINED; 99 @UnsupportedAppUsage 100 long mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_NODE_ID; 101 int mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 102 int mSourceDisplayId = Display.INVALID_DISPLAY; 103 104 CharSequence mClassName; 105 CharSequence mContentDescription; 106 CharSequence mBeforeText; 107 Parcelable mParcelableData; 108 109 final List<CharSequence> mText = new ArrayList<CharSequence>(); 110 111 int mConnectionId = UNDEFINED; 112 113 /** 114 * Creates a new {@link AccessibilityRecord}. 115 */ AccessibilityRecord()116 public AccessibilityRecord() { 117 } 118 119 /** 120 * Copy constructor. Creates a new {@link AccessibilityRecord}, and this instance is initialized 121 * with data from the given <code>record</code>. 122 * 123 * @param record The other record. 124 */ AccessibilityRecord(@onNull AccessibilityRecord record)125 public AccessibilityRecord(@NonNull AccessibilityRecord record) { 126 init(record); 127 } 128 129 /** 130 * Sets the event source. 131 * 132 * @param source The source. 133 * 134 * @throws IllegalStateException If called from an AccessibilityService. 135 */ setSource(@ullable View source)136 public void setSource(@Nullable View source) { 137 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID); 138 } 139 140 /** 141 * Sets the source to be a virtual descendant of the given <code>root</code>. 142 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root 143 * is set as the source. 144 * <p> 145 * A virtual descendant is an imaginary View that is reported as a part of the view 146 * hierarchy for accessibility purposes. This enables custom views that draw complex 147 * content to report them selves as a tree of virtual views, thus conveying their 148 * logical structure. 149 * </p> 150 * 151 * @param root The root of the virtual subtree. 152 * @param virtualDescendantId The id of the virtual descendant. 153 */ setSource(@ullable View root, int virtualDescendantId)154 public void setSource(@Nullable View root, int virtualDescendantId) { 155 enforceNotSealed(); 156 boolean important = true; 157 int rootViewId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 158 mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 159 if (root != null) { 160 important = root.isImportantForAccessibility(); 161 rootViewId = root.getAccessibilityViewId(); 162 mSourceWindowId = root.getAccessibilityWindowId(); 163 setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, 164 root.isAccessibilityDataSensitive()); 165 } 166 setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important); 167 mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId); 168 } 169 170 /** 171 * Set the source node ID directly 172 * 173 * @param sourceNodeId The source node Id 174 * @hide 175 */ setSourceNodeId(long sourceNodeId)176 public void setSourceNodeId(long sourceNodeId) { 177 mSourceNodeId = sourceNodeId; 178 } 179 180 /** 181 * Gets the {@link AccessibilityNodeInfo} of the event source. 182 * <p> 183 * <strong>Note:</strong> It is a client responsibility to recycle the received info 184 * by calling {@link AccessibilityNodeInfo#recycle() AccessibilityNodeInfo#recycle()} 185 * to avoid creating of multiple instances. 186 * </p> 187 * @return The info of the source. 188 */ getSource()189 public @Nullable AccessibilityNodeInfo getSource() { 190 return getSource(GET_SOURCE_PREFETCH_FLAGS); 191 } 192 193 /** 194 * Gets the {@link AccessibilityNodeInfo} of the event source. 195 * 196 * @param prefetchingStrategy the prefetching strategy. 197 * @return The info of the source. 198 * 199 * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching. 200 */ getSource( @ccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy)201 public @Nullable AccessibilityNodeInfo getSource( 202 @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) { 203 enforceSealed(); 204 if ((mConnectionId == UNDEFINED) 205 || (mSourceWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) 206 || (AccessibilityNodeInfo.getAccessibilityViewId(mSourceNodeId) 207 == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)) { 208 return null; 209 } 210 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 211 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId, 212 mSourceNodeId, false, prefetchingStrategy, null); 213 } 214 215 /** 216 * Sets the display id. 217 * 218 * @param displayId The displayId id. 219 * 220 * @hide 221 */ 222 @TestApi setDisplayId(int displayId)223 public void setDisplayId(int displayId) { 224 mSourceDisplayId = displayId; 225 } 226 227 /** 228 * Gets the id of the display from which the event comes from. 229 * 230 * @return The display id. 231 */ getDisplayId()232 public int getDisplayId() { 233 return mSourceDisplayId; 234 } 235 236 /** 237 * Sets the window id. 238 * 239 * @param windowId The window id. 240 * 241 * @hide 242 */ setWindowId(int windowId)243 public void setWindowId(int windowId) { 244 mSourceWindowId = windowId; 245 } 246 247 /** 248 * Gets the id of the window from which the event comes from. 249 * 250 * @return The window id. 251 */ getWindowId()252 public int getWindowId() { 253 return mSourceWindowId; 254 } 255 256 /** 257 * Gets if the source is checked. 258 * 259 * @return True if the view is checked, false otherwise. 260 */ isChecked()261 public boolean isChecked() { 262 return getBooleanProperty(PROPERTY_CHECKED); 263 } 264 265 /** 266 * Sets if the source is checked. 267 * 268 * @param isChecked True if the view is checked, false otherwise. 269 * 270 * @throws IllegalStateException If called from an AccessibilityService. 271 */ setChecked(boolean isChecked)272 public void setChecked(boolean isChecked) { 273 enforceNotSealed(); 274 setBooleanProperty(PROPERTY_CHECKED, isChecked); 275 } 276 277 /** 278 * Gets if the source is enabled. 279 * 280 * @return True if the view is enabled, false otherwise. 281 */ isEnabled()282 public boolean isEnabled() { 283 return getBooleanProperty(PROPERTY_ENABLED); 284 } 285 286 /** 287 * Sets if the source is enabled. 288 * 289 * @param isEnabled True if the view is enabled, false otherwise. 290 * 291 * @throws IllegalStateException If called from an AccessibilityService. 292 */ setEnabled(boolean isEnabled)293 public void setEnabled(boolean isEnabled) { 294 enforceNotSealed(); 295 setBooleanProperty(PROPERTY_ENABLED, isEnabled); 296 } 297 298 /** 299 * Gets if the source is a password field. 300 * 301 * @return True if the view is a password field, false otherwise. 302 */ isPassword()303 public boolean isPassword() { 304 return getBooleanProperty(PROPERTY_PASSWORD); 305 } 306 307 /** 308 * Sets if the source is a password field. 309 * 310 * @param isPassword True if the view is a password field, false otherwise. 311 * 312 * @throws IllegalStateException If called from an AccessibilityService. 313 */ setPassword(boolean isPassword)314 public void setPassword(boolean isPassword) { 315 enforceNotSealed(); 316 setBooleanProperty(PROPERTY_PASSWORD, isPassword); 317 } 318 319 /** 320 * Gets if the source is taking the entire screen. 321 * 322 * @return True if the source is full screen, false otherwise. 323 */ isFullScreen()324 public boolean isFullScreen() { 325 return getBooleanProperty(PROPERTY_FULL_SCREEN); 326 } 327 328 /** 329 * Sets if the source is taking the entire screen. 330 * 331 * @param isFullScreen True if the source is full screen, false otherwise. 332 * 333 * @throws IllegalStateException If called from an AccessibilityService. 334 */ setFullScreen(boolean isFullScreen)335 public void setFullScreen(boolean isFullScreen) { 336 enforceNotSealed(); 337 setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen); 338 } 339 340 /** 341 * Gets if the source is scrollable. 342 * 343 * @return True if the source is scrollable, false otherwise. 344 */ isScrollable()345 public boolean isScrollable() { 346 return getBooleanProperty(PROPERTY_SCROLLABLE); 347 } 348 349 /** 350 * Sets if the source is scrollable. 351 * 352 * @param scrollable True if the source is scrollable, false otherwise. 353 * 354 * @throws IllegalStateException If called from an AccessibilityService. 355 */ setScrollable(boolean scrollable)356 public void setScrollable(boolean scrollable) { 357 enforceNotSealed(); 358 setBooleanProperty(PROPERTY_SCROLLABLE, scrollable); 359 } 360 361 /** 362 * Gets if the source is important for accessibility. 363 * 364 * <strong>Note:</strong> Used only internally to determine whether 365 * to deliver the event to a given accessibility service since some 366 * services may want to regard all views for accessibility while others 367 * may want to regard only the important views for accessibility. 368 * 369 * @return True if the source is important for accessibility, 370 * false otherwise. 371 * 372 * @hide 373 */ isImportantForAccessibility()374 public boolean isImportantForAccessibility() { 375 return getBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY); 376 } 377 378 /** 379 * Sets if the source is important for accessibility. 380 * 381 * @param importantForAccessibility True if the source is important for accessibility, 382 * false otherwise. 383 * 384 * @throws IllegalStateException If called from an AccessibilityService. 385 * @hide 386 */ setImportantForAccessibility(boolean importantForAccessibility)387 public void setImportantForAccessibility(boolean importantForAccessibility) { 388 enforceNotSealed(); 389 setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, importantForAccessibility); 390 } 391 392 /** 393 * @see AccessibilityEvent#isAccessibilityDataSensitive 394 * @hide 395 */ isAccessibilityDataSensitive()396 boolean isAccessibilityDataSensitive() { 397 return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); 398 } 399 400 /** 401 * @see AccessibilityEvent#setAccessibilityDataSensitive 402 * @hide 403 */ setAccessibilityDataSensitive(boolean accessibilityDataSensitive)404 void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { 405 enforceNotSealed(); 406 setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, accessibilityDataSensitive); 407 } 408 409 /** 410 * Gets the number of items that can be visited. 411 * 412 * @return The number of items. 413 */ getItemCount()414 public int getItemCount() { 415 return mItemCount; 416 } 417 418 /** 419 * Sets the number of items that can be visited. 420 * 421 * @param itemCount The number of items. 422 * 423 * @throws IllegalStateException If called from an AccessibilityService. 424 */ setItemCount(int itemCount)425 public void setItemCount(int itemCount) { 426 enforceNotSealed(); 427 mItemCount = itemCount; 428 } 429 430 /** 431 * Gets the index of the source in the list of items the can be visited. 432 * 433 * @return The current item index. 434 */ getCurrentItemIndex()435 public int getCurrentItemIndex() { 436 return mCurrentItemIndex; 437 } 438 439 /** 440 * Sets the index of the source in the list of items that can be visited. 441 * 442 * @param currentItemIndex The current item index. 443 * 444 * @throws IllegalStateException If called from an AccessibilityService. 445 */ setCurrentItemIndex(int currentItemIndex)446 public void setCurrentItemIndex(int currentItemIndex) { 447 enforceNotSealed(); 448 mCurrentItemIndex = currentItemIndex; 449 } 450 451 /** 452 * Gets the index of the first character of the changed sequence, 453 * or the beginning of a text selection or the index of the first 454 * visible item when scrolling. 455 * 456 * @return The index of the first character or selection 457 * start or the first visible item. 458 */ getFromIndex()459 public int getFromIndex() { 460 return mFromIndex; 461 } 462 463 /** 464 * Sets the index of the first character of the changed sequence 465 * or the beginning of a text selection or the index of the first 466 * visible item when scrolling. 467 * 468 * @param fromIndex The index of the first character or selection 469 * start or the first visible item. 470 * 471 * @throws IllegalStateException If called from an AccessibilityService. 472 */ setFromIndex(int fromIndex)473 public void setFromIndex(int fromIndex) { 474 enforceNotSealed(); 475 mFromIndex = fromIndex; 476 } 477 478 /** 479 * Gets the index of text selection end or the index of the last 480 * visible item when scrolling. 481 * 482 * @return The index of selection end or last item index. 483 */ getToIndex()484 public int getToIndex() { 485 return mToIndex; 486 } 487 488 /** 489 * Sets the index of text selection end or the index of the last 490 * visible item when scrolling. 491 * 492 * @param toIndex The index of selection end or last item index. 493 */ setToIndex(int toIndex)494 public void setToIndex(int toIndex) { 495 enforceNotSealed(); 496 mToIndex = toIndex; 497 } 498 499 /** 500 * Gets the scroll offset of the source left edge in pixels. 501 * 502 * @return The scroll. 503 */ getScrollX()504 public int getScrollX() { 505 return mScrollX; 506 } 507 508 /** 509 * Sets the scroll offset of the source left edge in pixels. 510 * 511 * @param scrollX The scroll. 512 */ setScrollX(int scrollX)513 public void setScrollX(int scrollX) { 514 enforceNotSealed(); 515 mScrollX = scrollX; 516 } 517 518 /** 519 * Gets the scroll offset of the source top edge in pixels. 520 * 521 * @return The scroll. 522 */ getScrollY()523 public int getScrollY() { 524 return mScrollY; 525 } 526 527 /** 528 * Sets the scroll offset of the source top edge in pixels. 529 * 530 * @param scrollY The scroll. 531 */ setScrollY(int scrollY)532 public void setScrollY(int scrollY) { 533 enforceNotSealed(); 534 mScrollY = scrollY; 535 } 536 537 /** 538 * Gets the difference in pixels between the horizontal position before the scroll and the 539 * current horizontal position 540 * 541 * @return the scroll delta x 542 */ getScrollDeltaX()543 public int getScrollDeltaX() { 544 return mScrollDeltaX; 545 } 546 547 /** 548 * Sets the difference in pixels between the horizontal position before the scroll and the 549 * current horizontal position 550 * 551 * @param scrollDeltaX the scroll delta x 552 */ setScrollDeltaX(int scrollDeltaX)553 public void setScrollDeltaX(int scrollDeltaX) { 554 enforceNotSealed(); 555 mScrollDeltaX = scrollDeltaX; 556 } 557 558 /** 559 * Gets the difference in pixels between the vertical position before the scroll and the 560 * current vertical position 561 * 562 * @return the scroll delta y 563 */ getScrollDeltaY()564 public int getScrollDeltaY() { 565 return mScrollDeltaY; 566 } 567 568 /** 569 * Sets the difference in pixels between the vertical position before the scroll and the 570 * current vertical position 571 * 572 * @param scrollDeltaY the scroll delta y 573 */ setScrollDeltaY(int scrollDeltaY)574 public void setScrollDeltaY(int scrollDeltaY) { 575 enforceNotSealed(); 576 mScrollDeltaY = scrollDeltaY; 577 } 578 579 /** 580 * Gets the max scroll offset of the source left edge in pixels. 581 * 582 * @return The max scroll. 583 */ getMaxScrollX()584 public int getMaxScrollX() { 585 return mMaxScrollX; 586 } 587 588 /** 589 * Sets the max scroll offset of the source left edge in pixels. 590 * 591 * @param maxScrollX The max scroll. 592 */ setMaxScrollX(int maxScrollX)593 public void setMaxScrollX(int maxScrollX) { 594 enforceNotSealed(); 595 mMaxScrollX = maxScrollX; 596 } 597 598 /** 599 * Gets the max scroll offset of the source top edge in pixels. 600 * 601 * @return The max scroll. 602 */ getMaxScrollY()603 public int getMaxScrollY() { 604 return mMaxScrollY; 605 } 606 607 /** 608 * Sets the max scroll offset of the source top edge in pixels. 609 * 610 * @param maxScrollY The max scroll. 611 */ setMaxScrollY(int maxScrollY)612 public void setMaxScrollY(int maxScrollY) { 613 enforceNotSealed(); 614 mMaxScrollY = maxScrollY; 615 } 616 617 /** 618 * Gets the number of added characters. 619 * 620 * @return The number of added characters. 621 */ getAddedCount()622 public int getAddedCount() { 623 return mAddedCount; 624 } 625 626 /** 627 * Sets the number of added characters. 628 * 629 * @param addedCount The number of added characters. 630 * 631 * @throws IllegalStateException If called from an AccessibilityService. 632 */ setAddedCount(int addedCount)633 public void setAddedCount(int addedCount) { 634 enforceNotSealed(); 635 mAddedCount = addedCount; 636 } 637 638 /** 639 * Gets the number of removed characters. 640 * 641 * @return The number of removed characters. 642 */ getRemovedCount()643 public int getRemovedCount() { 644 return mRemovedCount; 645 } 646 647 /** 648 * Sets the number of removed characters. 649 * 650 * @param removedCount The number of removed characters. 651 * 652 * @throws IllegalStateException If called from an AccessibilityService. 653 */ setRemovedCount(int removedCount)654 public void setRemovedCount(int removedCount) { 655 enforceNotSealed(); 656 mRemovedCount = removedCount; 657 } 658 659 /** 660 * Gets the class name of the source. 661 * 662 * @return The class name. 663 */ getClassName()664 public @Nullable CharSequence getClassName() { 665 return mClassName; 666 } 667 668 /** 669 * Sets the class name of the source. 670 * 671 * @param className The lass name. 672 * 673 * @throws IllegalStateException If called from an AccessibilityService. 674 */ setClassName(@ullable CharSequence className)675 public void setClassName(@Nullable CharSequence className) { 676 enforceNotSealed(); 677 mClassName = className; 678 } 679 680 /** 681 * Gets the text of the event. The index in the list represents the priority 682 * of the text. Specifically, the lower the index the higher the priority. 683 * 684 * @return The text. 685 */ getText()686 public @NonNull List<CharSequence> getText() { 687 return mText; 688 } 689 690 /** 691 * Gets the text before a change. 692 * 693 * @return The text before the change. 694 */ getBeforeText()695 public @Nullable CharSequence getBeforeText() { 696 return mBeforeText; 697 } 698 699 /** 700 * Sets the text before a change. 701 * 702 * @param beforeText The text before the change. 703 * 704 * @throws IllegalStateException If called from an AccessibilityService. 705 */ setBeforeText(@ullable CharSequence beforeText)706 public void setBeforeText(@Nullable CharSequence beforeText) { 707 enforceNotSealed(); 708 mBeforeText = (beforeText == null) ? null 709 : beforeText.subSequence(0, beforeText.length()); 710 } 711 712 /** 713 * Gets the description of the source. 714 * 715 * @return The description. 716 */ getContentDescription()717 public @Nullable CharSequence getContentDescription() { 718 return mContentDescription; 719 } 720 721 /** 722 * Sets the description of the source. 723 * 724 * @param contentDescription The description. 725 * 726 * @throws IllegalStateException If called from an AccessibilityService. 727 */ setContentDescription(@ullable CharSequence contentDescription)728 public void setContentDescription(@Nullable CharSequence contentDescription) { 729 enforceNotSealed(); 730 mContentDescription = (contentDescription == null) ? null 731 : contentDescription.subSequence(0, contentDescription.length()); 732 } 733 734 /** 735 * Gets the {@link Parcelable} data. 736 * 737 * @return The parcelable data. 738 */ getParcelableData()739 public @Nullable Parcelable getParcelableData() { 740 return mParcelableData; 741 } 742 743 /** 744 * Sets the {@link Parcelable} data of the event. 745 * 746 * @param parcelableData The parcelable data. 747 * 748 * @throws IllegalStateException If called from an AccessibilityService. 749 */ setParcelableData(@ullable Parcelable parcelableData)750 public void setParcelableData(@Nullable Parcelable parcelableData) { 751 enforceNotSealed(); 752 mParcelableData = parcelableData; 753 } 754 755 /** 756 * Gets the id of the source node. 757 * 758 * @return The id. 759 * 760 * @hide 761 */ 762 @UnsupportedAppUsage getSourceNodeId()763 public long getSourceNodeId() { 764 return mSourceNodeId; 765 } 766 767 /** 768 * Sets the unique id of the IAccessibilityServiceConnection over which 769 * this instance can send requests to the system. 770 * 771 * @param connectionId The connection id. 772 * 773 * @hide 774 */ setConnectionId(int connectionId)775 public void setConnectionId(int connectionId) { 776 enforceNotSealed(); 777 mConnectionId = connectionId; 778 } 779 780 /** 781 * Sets if this instance is sealed. 782 * 783 * @param sealed Whether is sealed. 784 * 785 * @hide 786 */ setSealed(boolean sealed)787 public void setSealed(boolean sealed) { 788 mSealed = sealed; 789 } 790 791 /** 792 * Gets if this instance is sealed. 793 * 794 * @return Whether is sealed. 795 */ isSealed()796 boolean isSealed() { 797 return mSealed; 798 } 799 800 /** 801 * Enforces that this instance is sealed. 802 * 803 * @throws IllegalStateException If this instance is not sealed. 804 */ enforceSealed()805 void enforceSealed() { 806 if (!isSealed()) { 807 throw new IllegalStateException("Cannot perform this " 808 + "action on a not sealed instance."); 809 } 810 } 811 812 /** 813 * Enforces that this instance is not sealed. 814 * 815 * @throws IllegalStateException If this instance is sealed. 816 */ enforceNotSealed()817 void enforceNotSealed() { 818 if (isSealed()) { 819 throw new IllegalStateException("Cannot perform this " 820 + "action on a sealed instance."); 821 } 822 } 823 824 /** 825 * Gets the value of a boolean property. 826 * 827 * @param property The property. 828 * @return The value. 829 */ getBooleanProperty(int property)830 private boolean getBooleanProperty(int property) { 831 return (mBooleanProperties & property) == property; 832 } 833 834 /** 835 * Sets a boolean property. 836 * 837 * @param property The property. 838 * @param value The value. 839 */ setBooleanProperty(int property, boolean value)840 private void setBooleanProperty(int property, boolean value) { 841 if (value) { 842 mBooleanProperties |= property; 843 } else { 844 mBooleanProperties &= ~property; 845 } 846 } 847 848 /** 849 * Instantiates a new record initialized with data from the 850 * given record. 851 * 852 * @deprecated Object pooling has been discontinued. Create a new instance using the 853 * constructor {@link #AccessibilityRecord()} instead. 854 * @return An instance. 855 */ 856 @Deprecated obtain(@onNull AccessibilityRecord record)857 public static @NonNull AccessibilityRecord obtain(@NonNull AccessibilityRecord record) { 858 AccessibilityRecord clone = AccessibilityRecord.obtain(); 859 clone.init(record); 860 return clone; 861 } 862 863 /** 864 * Instantiates a new record. 865 * 866 * @deprecated Object pooling has been discontinued. Create a new instance using the 867 * constructor {@link #AccessibilityRecord()} instead. 868 * @return An instance. 869 */ 870 @Deprecated obtain()871 public static @NonNull AccessibilityRecord obtain() { 872 return new AccessibilityRecord(); 873 } 874 875 /** 876 * Would previously return an instance back to be reused. 877 * 878 * @deprecated Object pooling has been discontinued. Calling this function now will have 879 * no effect. 880 */ 881 @Deprecated recycle()882 public void recycle() { } 883 884 /** 885 * Initialize this record from another one. 886 * 887 * @param record The to initialize from. 888 */ init(@onNull AccessibilityRecord record)889 void init(@NonNull AccessibilityRecord record) { 890 mSealed = record.mSealed; 891 mBooleanProperties = record.mBooleanProperties; 892 mCurrentItemIndex = record.mCurrentItemIndex; 893 mItemCount = record.mItemCount; 894 mFromIndex = record.mFromIndex; 895 mToIndex = record.mToIndex; 896 mScrollX = record.mScrollX; 897 mScrollY = record.mScrollY; 898 mMaxScrollX = record.mMaxScrollX; 899 mMaxScrollY = record.mMaxScrollY; 900 mScrollDeltaX = record.mScrollDeltaX; 901 mScrollDeltaY = record.mScrollDeltaY; 902 mAddedCount = record.mAddedCount; 903 mRemovedCount = record.mRemovedCount; 904 mClassName = record.mClassName; 905 mContentDescription = record.mContentDescription; 906 mBeforeText = record.mBeforeText; 907 mParcelableData = record.mParcelableData; 908 mText.addAll(record.mText); 909 mSourceWindowId = record.mSourceWindowId; 910 mSourceNodeId = record.mSourceNodeId; 911 mSourceDisplayId = record.mSourceDisplayId; 912 mConnectionId = record.mConnectionId; 913 } 914 915 /** 916 * Clears the state of this instance. 917 */ clear()918 void clear() { 919 mSealed = false; 920 mBooleanProperties = 0; 921 mCurrentItemIndex = UNDEFINED; 922 mItemCount = UNDEFINED; 923 mFromIndex = UNDEFINED; 924 mToIndex = UNDEFINED; 925 mScrollX = 0; 926 mScrollY = 0; 927 mMaxScrollX = 0; 928 mMaxScrollY = 0; 929 mScrollDeltaX = UNDEFINED; 930 mScrollDeltaY = UNDEFINED; 931 mAddedCount = UNDEFINED; 932 mRemovedCount = UNDEFINED; 933 mClassName = null; 934 mContentDescription = null; 935 mBeforeText = null; 936 mParcelableData = null; 937 mText.clear(); 938 mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 939 mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 940 mSourceDisplayId = Display.INVALID_DISPLAY; 941 mConnectionId = UNDEFINED; 942 } 943 944 @Override toString()945 public String toString() { 946 return appendTo(new StringBuilder()).toString(); 947 } 948 appendTo(StringBuilder builder)949 StringBuilder appendTo(StringBuilder builder) { 950 builder.append(" [ ClassName: ").append(mClassName); 951 if (!DEBUG_CONCISE_TOSTRING || !isEmpty(mText)) { 952 appendPropName(builder, "Text").append(mText); 953 } 954 append(builder, "ContentDescription", mContentDescription); 955 append(builder, "ItemCount", mItemCount); 956 append(builder, "CurrentItemIndex", mCurrentItemIndex); 957 958 appendUnless(true, PROPERTY_ENABLED, builder); 959 appendUnless(false, PROPERTY_PASSWORD, builder); 960 appendUnless(false, PROPERTY_CHECKED, builder); 961 appendUnless(false, PROPERTY_FULL_SCREEN, builder); 962 appendUnless(false, PROPERTY_SCROLLABLE, builder); 963 appendUnless(false, PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, builder); 964 appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, builder); 965 966 append(builder, "BeforeText", mBeforeText); 967 append(builder, "FromIndex", mFromIndex); 968 append(builder, "ToIndex", mToIndex); 969 append(builder, "ScrollX", mScrollX); 970 append(builder, "ScrollY", mScrollY); 971 append(builder, "MaxScrollX", mMaxScrollX); 972 append(builder, "MaxScrollY", mMaxScrollY); 973 append(builder, "ScrollDeltaX", mScrollDeltaX); 974 append(builder, "ScrollDeltaY", mScrollDeltaY); 975 append(builder, "AddedCount", mAddedCount); 976 append(builder, "RemovedCount", mRemovedCount); 977 append(builder, "ParcelableData", mParcelableData); 978 append(builder, "DisplayId", mSourceDisplayId); 979 builder.append(" ]"); 980 return builder; 981 } 982 appendUnless(boolean defValue, int prop, StringBuilder builder)983 private void appendUnless(boolean defValue, int prop, StringBuilder builder) { 984 boolean value = getBooleanProperty(prop); 985 if (DEBUG_CONCISE_TOSTRING && value == defValue) return; 986 appendPropName(builder, singleBooleanPropertyToString(prop)) 987 .append(value); 988 } 989 singleBooleanPropertyToString(int prop)990 private static String singleBooleanPropertyToString(int prop) { 991 switch (prop) { 992 case PROPERTY_CHECKED: return "Checked"; 993 case PROPERTY_ENABLED: return "Enabled"; 994 case PROPERTY_PASSWORD: return "Password"; 995 case PROPERTY_FULL_SCREEN: return "FullScreen"; 996 case PROPERTY_SCROLLABLE: return "Scrollable"; 997 case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY: 998 return "ImportantForAccessibility"; 999 case PROPERTY_ACCESSIBILITY_DATA_SENSITIVE: 1000 return "AccessibilityDataSensitive"; 1001 default: return Integer.toHexString(prop); 1002 } 1003 } 1004 append(StringBuilder builder, String propName, int propValue)1005 private void append(StringBuilder builder, String propName, int propValue) { 1006 if (DEBUG_CONCISE_TOSTRING && propValue == UNDEFINED) return; 1007 appendPropName(builder, propName).append(propValue); 1008 } 1009 append(StringBuilder builder, String propName, Object propValue)1010 private void append(StringBuilder builder, String propName, Object propValue) { 1011 if (DEBUG_CONCISE_TOSTRING && propValue == null) return; 1012 appendPropName(builder, propName).append(propValue); 1013 } 1014 appendPropName(StringBuilder builder, String propName)1015 private StringBuilder appendPropName(StringBuilder builder, String propName) { 1016 return builder.append("; ").append(propName).append(": "); 1017 } 1018 } 1019