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 = 0x00000001; 70 private static final int PROPERTY_ENABLED = 0x00000002; 71 private static final int PROPERTY_PASSWORD = 0x00000004; 72 private static final int PROPERTY_FULL_SCREEN = 0x00000080; 73 private static final int PROPERTY_SCROLLABLE = 0x00000100; 74 private static final int PROPERTY_IMPORTANT_FOR_ACCESSIBILITY = 0x00000200; 75 private static final int PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 0x00000400; 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 */ 201 @Nullable getSource( @ccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy)202 public AccessibilityNodeInfo getSource( 203 @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) { 204 enforceSealed(); 205 if ((mConnectionId == UNDEFINED) 206 || (mSourceWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) 207 || (AccessibilityNodeInfo.getAccessibilityViewId(mSourceNodeId) 208 == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)) { 209 return null; 210 } 211 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 212 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId, 213 mSourceNodeId, false, prefetchingStrategy, null); 214 } 215 216 /** 217 * Sets the display id. 218 * 219 * @param displayId The displayId id. 220 * 221 * @hide 222 */ 223 @TestApi setDisplayId(int displayId)224 public void setDisplayId(int displayId) { 225 mSourceDisplayId = displayId; 226 } 227 228 /** 229 * Gets the id of the display from which the event comes from. 230 * 231 * @return The display id. 232 */ getDisplayId()233 public int getDisplayId() { 234 return mSourceDisplayId; 235 } 236 237 /** 238 * Sets the window id. 239 * 240 * @param windowId The window id. 241 * 242 * @hide 243 */ setWindowId(int windowId)244 public void setWindowId(int windowId) { 245 mSourceWindowId = windowId; 246 } 247 248 /** 249 * Gets the id of the window from which the event comes from. 250 * 251 * @return The window id. 252 */ getWindowId()253 public int getWindowId() { 254 return mSourceWindowId; 255 } 256 257 /** 258 * Gets if the source is checked. 259 * 260 * @return True if the view is checked, false otherwise. 261 */ isChecked()262 public boolean isChecked() { 263 return getBooleanProperty(PROPERTY_CHECKED); 264 } 265 266 /** 267 * Sets if the source is checked. 268 * 269 * @param isChecked True if the view is checked, false otherwise. 270 * 271 * @throws IllegalStateException If called from an AccessibilityService. 272 */ setChecked(boolean isChecked)273 public void setChecked(boolean isChecked) { 274 enforceNotSealed(); 275 setBooleanProperty(PROPERTY_CHECKED, isChecked); 276 } 277 278 /** 279 * Gets if the source is enabled. 280 * 281 * @return True if the view is enabled, false otherwise. 282 */ isEnabled()283 public boolean isEnabled() { 284 return getBooleanProperty(PROPERTY_ENABLED); 285 } 286 287 /** 288 * Sets if the source is enabled. 289 * 290 * @param isEnabled True if the view is enabled, false otherwise. 291 * 292 * @throws IllegalStateException If called from an AccessibilityService. 293 */ setEnabled(boolean isEnabled)294 public void setEnabled(boolean isEnabled) { 295 enforceNotSealed(); 296 setBooleanProperty(PROPERTY_ENABLED, isEnabled); 297 } 298 299 /** 300 * Gets if the source is a password field. 301 * 302 * @return True if the view is a password field, false otherwise. 303 */ isPassword()304 public boolean isPassword() { 305 return getBooleanProperty(PROPERTY_PASSWORD); 306 } 307 308 /** 309 * Sets if the source is a password field. 310 * 311 * @param isPassword True if the view is a password field, false otherwise. 312 * 313 * @throws IllegalStateException If called from an AccessibilityService. 314 */ setPassword(boolean isPassword)315 public void setPassword(boolean isPassword) { 316 enforceNotSealed(); 317 setBooleanProperty(PROPERTY_PASSWORD, isPassword); 318 } 319 320 /** 321 * Gets if the source is taking the entire screen. 322 * 323 * @return True if the source is full screen, false otherwise. 324 */ isFullScreen()325 public boolean isFullScreen() { 326 return getBooleanProperty(PROPERTY_FULL_SCREEN); 327 } 328 329 /** 330 * Sets if the source is taking the entire screen. 331 * 332 * @param isFullScreen True if the source is full screen, false otherwise. 333 * 334 * @throws IllegalStateException If called from an AccessibilityService. 335 */ setFullScreen(boolean isFullScreen)336 public void setFullScreen(boolean isFullScreen) { 337 enforceNotSealed(); 338 setBooleanProperty(PROPERTY_FULL_SCREEN, isFullScreen); 339 } 340 341 /** 342 * Gets if the source is scrollable. 343 * 344 * @return True if the source is scrollable, false otherwise. 345 */ isScrollable()346 public boolean isScrollable() { 347 return getBooleanProperty(PROPERTY_SCROLLABLE); 348 } 349 350 /** 351 * Sets if the source is scrollable. 352 * 353 * @param scrollable True if the source is scrollable, false otherwise. 354 * 355 * @throws IllegalStateException If called from an AccessibilityService. 356 */ setScrollable(boolean scrollable)357 public void setScrollable(boolean scrollable) { 358 enforceNotSealed(); 359 setBooleanProperty(PROPERTY_SCROLLABLE, scrollable); 360 } 361 362 /** 363 * Gets if the source is important for accessibility. 364 * 365 * <strong>Note:</strong> Used only internally to determine whether 366 * to deliver the event to a given accessibility service since some 367 * services may want to regard all views for accessibility while others 368 * may want to regard only the important views for accessibility. 369 * 370 * @return True if the source is important for accessibility, 371 * false otherwise. 372 * 373 * @hide 374 */ isImportantForAccessibility()375 public boolean isImportantForAccessibility() { 376 return getBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY); 377 } 378 379 /** 380 * Sets if the source is important for accessibility. 381 * 382 * @param importantForAccessibility True if the source is important for accessibility, 383 * false otherwise. 384 * 385 * @throws IllegalStateException If called from an AccessibilityService. 386 * @hide 387 */ setImportantForAccessibility(boolean importantForAccessibility)388 public void setImportantForAccessibility(boolean importantForAccessibility) { 389 enforceNotSealed(); 390 setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, importantForAccessibility); 391 } 392 393 /** 394 * @see AccessibilityEvent#isAccessibilityDataSensitive 395 * @hide 396 */ isAccessibilityDataSensitive()397 boolean isAccessibilityDataSensitive() { 398 return getBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); 399 } 400 401 /** 402 * @see AccessibilityEvent#setAccessibilityDataSensitive 403 * @hide 404 */ setAccessibilityDataSensitive(boolean accessibilityDataSensitive)405 void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { 406 enforceNotSealed(); 407 setBooleanProperty(PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, accessibilityDataSensitive); 408 } 409 410 /** 411 * Gets the number of items that can be visited. 412 * 413 * @return The number of items. 414 */ getItemCount()415 public int getItemCount() { 416 return mItemCount; 417 } 418 419 /** 420 * Sets the number of items that can be visited. 421 * 422 * @param itemCount The number of items. 423 * 424 * @throws IllegalStateException If called from an AccessibilityService. 425 */ setItemCount(int itemCount)426 public void setItemCount(int itemCount) { 427 enforceNotSealed(); 428 mItemCount = itemCount; 429 } 430 431 /** 432 * Gets the index of the source in the list of items the can be visited. 433 * 434 * @return The current item index. 435 */ getCurrentItemIndex()436 public int getCurrentItemIndex() { 437 return mCurrentItemIndex; 438 } 439 440 /** 441 * Sets the index of the source in the list of items that can be visited. 442 * 443 * @param currentItemIndex The current item index. 444 * 445 * @throws IllegalStateException If called from an AccessibilityService. 446 */ setCurrentItemIndex(int currentItemIndex)447 public void setCurrentItemIndex(int currentItemIndex) { 448 enforceNotSealed(); 449 mCurrentItemIndex = currentItemIndex; 450 } 451 452 /** 453 * Gets the index of the first character of the changed sequence, 454 * or the beginning of a text selection or the index of the first 455 * visible item when scrolling. 456 * 457 * @return The index of the first character or selection 458 * start or the first visible item. 459 */ getFromIndex()460 public int getFromIndex() { 461 return mFromIndex; 462 } 463 464 /** 465 * Sets the index of the first character of the changed sequence 466 * or the beginning of a text selection or the index of the first 467 * visible item when scrolling. 468 * 469 * @param fromIndex The index of the first character or selection 470 * start or the first visible item. 471 * 472 * @throws IllegalStateException If called from an AccessibilityService. 473 */ setFromIndex(int fromIndex)474 public void setFromIndex(int fromIndex) { 475 enforceNotSealed(); 476 mFromIndex = fromIndex; 477 } 478 479 /** 480 * Gets the index of text selection end or the index of the last 481 * visible item when scrolling. 482 * 483 * @return The index of selection end or last item index. 484 */ getToIndex()485 public int getToIndex() { 486 return mToIndex; 487 } 488 489 /** 490 * Sets the index of text selection end or the index of the last 491 * visible item when scrolling. 492 * 493 * @param toIndex The index of selection end or last item index. 494 */ setToIndex(int toIndex)495 public void setToIndex(int toIndex) { 496 enforceNotSealed(); 497 mToIndex = toIndex; 498 } 499 500 /** 501 * Gets the scroll offset of the source left edge in pixels. 502 * 503 * @return The scroll. 504 */ getScrollX()505 public int getScrollX() { 506 return mScrollX; 507 } 508 509 /** 510 * Sets the scroll offset of the source left edge in pixels. 511 * 512 * @param scrollX The scroll. 513 */ setScrollX(int scrollX)514 public void setScrollX(int scrollX) { 515 enforceNotSealed(); 516 mScrollX = scrollX; 517 } 518 519 /** 520 * Gets the scroll offset of the source top edge in pixels. 521 * 522 * @return The scroll. 523 */ getScrollY()524 public int getScrollY() { 525 return mScrollY; 526 } 527 528 /** 529 * Sets the scroll offset of the source top edge in pixels. 530 * 531 * @param scrollY The scroll. 532 */ setScrollY(int scrollY)533 public void setScrollY(int scrollY) { 534 enforceNotSealed(); 535 mScrollY = scrollY; 536 } 537 538 /** 539 * Gets the difference in pixels between the horizontal position before the scroll and the 540 * current horizontal position 541 * 542 * @return the scroll delta x 543 */ getScrollDeltaX()544 public int getScrollDeltaX() { 545 return mScrollDeltaX; 546 } 547 548 /** 549 * Sets the difference in pixels between the horizontal position before the scroll and the 550 * current horizontal position 551 * 552 * @param scrollDeltaX the scroll delta x 553 */ setScrollDeltaX(int scrollDeltaX)554 public void setScrollDeltaX(int scrollDeltaX) { 555 enforceNotSealed(); 556 mScrollDeltaX = scrollDeltaX; 557 } 558 559 /** 560 * Gets the difference in pixels between the vertical position before the scroll and the 561 * current vertical position 562 * 563 * @return the scroll delta y 564 */ getScrollDeltaY()565 public int getScrollDeltaY() { 566 return mScrollDeltaY; 567 } 568 569 /** 570 * Sets the difference in pixels between the vertical position before the scroll and the 571 * current vertical position 572 * 573 * @param scrollDeltaY the scroll delta y 574 */ setScrollDeltaY(int scrollDeltaY)575 public void setScrollDeltaY(int scrollDeltaY) { 576 enforceNotSealed(); 577 mScrollDeltaY = scrollDeltaY; 578 } 579 580 /** 581 * Gets the max scroll offset of the source left edge in pixels. 582 * 583 * @return The max scroll. 584 */ getMaxScrollX()585 public int getMaxScrollX() { 586 return mMaxScrollX; 587 } 588 589 /** 590 * Sets the max scroll offset of the source left edge in pixels. 591 * 592 * @param maxScrollX The max scroll. 593 */ setMaxScrollX(int maxScrollX)594 public void setMaxScrollX(int maxScrollX) { 595 enforceNotSealed(); 596 mMaxScrollX = maxScrollX; 597 } 598 599 /** 600 * Gets the max scroll offset of the source top edge in pixels. 601 * 602 * @return The max scroll. 603 */ getMaxScrollY()604 public int getMaxScrollY() { 605 return mMaxScrollY; 606 } 607 608 /** 609 * Sets the max scroll offset of the source top edge in pixels. 610 * 611 * @param maxScrollY The max scroll. 612 */ setMaxScrollY(int maxScrollY)613 public void setMaxScrollY(int maxScrollY) { 614 enforceNotSealed(); 615 mMaxScrollY = maxScrollY; 616 } 617 618 /** 619 * Gets the number of added characters. 620 * 621 * @return The number of added characters. 622 */ getAddedCount()623 public int getAddedCount() { 624 return mAddedCount; 625 } 626 627 /** 628 * Sets the number of added characters. 629 * 630 * @param addedCount The number of added characters. 631 * 632 * @throws IllegalStateException If called from an AccessibilityService. 633 */ setAddedCount(int addedCount)634 public void setAddedCount(int addedCount) { 635 enforceNotSealed(); 636 mAddedCount = addedCount; 637 } 638 639 /** 640 * Gets the number of removed characters. 641 * 642 * @return The number of removed characters. 643 */ getRemovedCount()644 public int getRemovedCount() { 645 return mRemovedCount; 646 } 647 648 /** 649 * Sets the number of removed characters. 650 * 651 * @param removedCount The number of removed characters. 652 * 653 * @throws IllegalStateException If called from an AccessibilityService. 654 */ setRemovedCount(int removedCount)655 public void setRemovedCount(int removedCount) { 656 enforceNotSealed(); 657 mRemovedCount = removedCount; 658 } 659 660 /** 661 * Gets the class name of the source. 662 * 663 * @return The class name. 664 */ getClassName()665 public @Nullable CharSequence getClassName() { 666 return mClassName; 667 } 668 669 /** 670 * Sets the class name of the source. 671 * 672 * @param className The lass name. 673 * 674 * @throws IllegalStateException If called from an AccessibilityService. 675 */ setClassName(@ullable CharSequence className)676 public void setClassName(@Nullable CharSequence className) { 677 enforceNotSealed(); 678 mClassName = className; 679 } 680 681 /** 682 * Gets the text of the event. The index in the list represents the priority 683 * of the text. Specifically, the lower the index the higher the priority. 684 * 685 * @return The text. 686 */ getText()687 public @NonNull List<CharSequence> getText() { 688 return mText; 689 } 690 691 /** 692 * Gets the text before a change. 693 * 694 * @return The text before the change. 695 */ getBeforeText()696 public @Nullable CharSequence getBeforeText() { 697 return mBeforeText; 698 } 699 700 /** 701 * Sets the text before a change. 702 * 703 * @param beforeText The text before the change. 704 * 705 * @throws IllegalStateException If called from an AccessibilityService. 706 */ setBeforeText(@ullable CharSequence beforeText)707 public void setBeforeText(@Nullable CharSequence beforeText) { 708 enforceNotSealed(); 709 mBeforeText = (beforeText == null) ? null 710 : beforeText.subSequence(0, beforeText.length()); 711 } 712 713 /** 714 * Gets the description of the source. 715 * 716 * @return The description. 717 */ getContentDescription()718 public @Nullable CharSequence getContentDescription() { 719 return mContentDescription; 720 } 721 722 /** 723 * Sets the description of the source. 724 * 725 * @param contentDescription The description. 726 * 727 * @throws IllegalStateException If called from an AccessibilityService. 728 */ setContentDescription(@ullable CharSequence contentDescription)729 public void setContentDescription(@Nullable CharSequence contentDescription) { 730 enforceNotSealed(); 731 mContentDescription = (contentDescription == null) ? null 732 : contentDescription.subSequence(0, contentDescription.length()); 733 } 734 735 /** 736 * Gets the {@link Parcelable} data. 737 * 738 * @return The parcelable data. 739 */ getParcelableData()740 public @Nullable Parcelable getParcelableData() { 741 return mParcelableData; 742 } 743 744 /** 745 * Sets the {@link Parcelable} data of the event. 746 * 747 * @param parcelableData The parcelable data. 748 * 749 * @throws IllegalStateException If called from an AccessibilityService. 750 */ setParcelableData(@ullable Parcelable parcelableData)751 public void setParcelableData(@Nullable Parcelable parcelableData) { 752 enforceNotSealed(); 753 mParcelableData = parcelableData; 754 } 755 756 /** 757 * Gets the id of the source node. 758 * 759 * @return The id. 760 * 761 * @hide 762 */ 763 @UnsupportedAppUsage getSourceNodeId()764 public long getSourceNodeId() { 765 return mSourceNodeId; 766 } 767 768 /** 769 * Sets the unique id of the IAccessibilityServiceConnection over which 770 * this instance can send requests to the system. 771 * 772 * @param connectionId The connection id. 773 * 774 * @hide 775 */ setConnectionId(int connectionId)776 public void setConnectionId(int connectionId) { 777 enforceNotSealed(); 778 mConnectionId = connectionId; 779 } 780 781 /** 782 * Sets if this instance is sealed. 783 * 784 * @param sealed Whether is sealed. 785 * 786 * @hide 787 */ setSealed(boolean sealed)788 public void setSealed(boolean sealed) { 789 mSealed = sealed; 790 } 791 792 /** 793 * Gets if this instance is sealed. 794 * 795 * @return Whether is sealed. 796 */ isSealed()797 boolean isSealed() { 798 return mSealed; 799 } 800 801 /** 802 * Enforces that this instance is sealed. 803 * 804 * @throws IllegalStateException If this instance is not sealed. 805 */ enforceSealed()806 void enforceSealed() { 807 if (!isSealed()) { 808 throw new IllegalStateException("Cannot perform this " 809 + "action on a not sealed instance."); 810 } 811 } 812 813 /** 814 * Enforces that this instance is not sealed. 815 * 816 * @throws IllegalStateException If this instance is sealed. 817 */ enforceNotSealed()818 void enforceNotSealed() { 819 if (isSealed()) { 820 throw new IllegalStateException("Cannot perform this " 821 + "action on a sealed instance."); 822 } 823 } 824 825 /** 826 * Gets the value of a boolean property. 827 * 828 * @param property The property. 829 * @return The value. 830 */ getBooleanProperty(int property)831 private boolean getBooleanProperty(int property) { 832 return (mBooleanProperties & property) == property; 833 } 834 835 /** 836 * Sets a boolean property. 837 * 838 * @param property The property. 839 * @param value The value. 840 */ setBooleanProperty(int property, boolean value)841 private void setBooleanProperty(int property, boolean value) { 842 if (value) { 843 mBooleanProperties |= property; 844 } else { 845 mBooleanProperties &= ~property; 846 } 847 } 848 849 /** 850 * Instantiates a new record initialized with data from the 851 * given record. 852 * 853 * @deprecated Object pooling has been discontinued. Create a new instance using the 854 * constructor {@link #AccessibilityRecord()} instead. 855 * @return An instance. 856 */ 857 @Deprecated obtain(@onNull AccessibilityRecord record)858 public static @NonNull AccessibilityRecord obtain(@NonNull AccessibilityRecord record) { 859 AccessibilityRecord clone = AccessibilityRecord.obtain(); 860 clone.init(record); 861 return clone; 862 } 863 864 /** 865 * Instantiates a new record. 866 * 867 * @deprecated Object pooling has been discontinued. Create a new instance using the 868 * constructor {@link #AccessibilityRecord()} instead. 869 * @return An instance. 870 */ 871 @Deprecated obtain()872 public static @NonNull AccessibilityRecord obtain() { 873 return new AccessibilityRecord(); 874 } 875 876 /** 877 * Would previously return an instance back to be reused. 878 * 879 * @deprecated Object pooling has been discontinued. Calling this function now will have 880 * no effect. 881 */ 882 @Deprecated recycle()883 public void recycle() { } 884 885 /** 886 * Initialize this record from another one. 887 * 888 * @param record The to initialize from. 889 */ init(@onNull AccessibilityRecord record)890 void init(@NonNull AccessibilityRecord record) { 891 mSealed = record.mSealed; 892 mBooleanProperties = record.mBooleanProperties; 893 mCurrentItemIndex = record.mCurrentItemIndex; 894 mItemCount = record.mItemCount; 895 mFromIndex = record.mFromIndex; 896 mToIndex = record.mToIndex; 897 mScrollX = record.mScrollX; 898 mScrollY = record.mScrollY; 899 mMaxScrollX = record.mMaxScrollX; 900 mMaxScrollY = record.mMaxScrollY; 901 mScrollDeltaX = record.mScrollDeltaX; 902 mScrollDeltaY = record.mScrollDeltaY; 903 mAddedCount = record.mAddedCount; 904 mRemovedCount = record.mRemovedCount; 905 mClassName = record.mClassName; 906 mContentDescription = record.mContentDescription; 907 mBeforeText = record.mBeforeText; 908 mParcelableData = record.mParcelableData; 909 mText.addAll(record.mText); 910 mSourceWindowId = record.mSourceWindowId; 911 mSourceNodeId = record.mSourceNodeId; 912 mSourceDisplayId = record.mSourceDisplayId; 913 mConnectionId = record.mConnectionId; 914 } 915 916 /** 917 * Clears the state of this instance. 918 */ clear()919 void clear() { 920 mSealed = false; 921 mBooleanProperties = 0; 922 mCurrentItemIndex = UNDEFINED; 923 mItemCount = UNDEFINED; 924 mFromIndex = UNDEFINED; 925 mToIndex = UNDEFINED; 926 mScrollX = 0; 927 mScrollY = 0; 928 mMaxScrollX = 0; 929 mMaxScrollY = 0; 930 mScrollDeltaX = UNDEFINED; 931 mScrollDeltaY = UNDEFINED; 932 mAddedCount = UNDEFINED; 933 mRemovedCount = UNDEFINED; 934 mClassName = null; 935 mContentDescription = null; 936 mBeforeText = null; 937 mParcelableData = null; 938 mText.clear(); 939 mSourceNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 940 mSourceWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 941 mSourceDisplayId = Display.INVALID_DISPLAY; 942 mConnectionId = UNDEFINED; 943 } 944 945 @Override toString()946 public String toString() { 947 return appendTo(new StringBuilder()).toString(); 948 } 949 appendTo(StringBuilder builder)950 StringBuilder appendTo(StringBuilder builder) { 951 builder.append(" [ ClassName: ").append(mClassName); 952 if (!DEBUG_CONCISE_TOSTRING || !isEmpty(mText)) { 953 appendPropName(builder, "Text").append(mText); 954 } 955 append(builder, "ContentDescription", mContentDescription); 956 append(builder, "ItemCount", mItemCount); 957 append(builder, "CurrentItemIndex", mCurrentItemIndex); 958 959 appendUnless(true, PROPERTY_ENABLED, builder); 960 appendUnless(false, PROPERTY_PASSWORD, builder); 961 appendUnless(false, PROPERTY_CHECKED, builder); 962 appendUnless(false, PROPERTY_FULL_SCREEN, builder); 963 appendUnless(false, PROPERTY_SCROLLABLE, builder); 964 appendUnless(false, PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, builder); 965 appendUnless(false, PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, builder); 966 967 append(builder, "BeforeText", mBeforeText); 968 append(builder, "FromIndex", mFromIndex); 969 append(builder, "ToIndex", mToIndex); 970 append(builder, "ScrollX", mScrollX); 971 append(builder, "ScrollY", mScrollY); 972 append(builder, "MaxScrollX", mMaxScrollX); 973 append(builder, "MaxScrollY", mMaxScrollY); 974 append(builder, "ScrollDeltaX", mScrollDeltaX); 975 append(builder, "ScrollDeltaY", mScrollDeltaY); 976 append(builder, "AddedCount", mAddedCount); 977 append(builder, "RemovedCount", mRemovedCount); 978 append(builder, "ParcelableData", mParcelableData); 979 append(builder, "DisplayId", mSourceDisplayId); 980 builder.append(" ]"); 981 return builder; 982 } 983 appendUnless(boolean defValue, int prop, StringBuilder builder)984 private void appendUnless(boolean defValue, int prop, StringBuilder builder) { 985 boolean value = getBooleanProperty(prop); 986 if (DEBUG_CONCISE_TOSTRING && value == defValue) return; 987 appendPropName(builder, singleBooleanPropertyToString(prop)) 988 .append(value); 989 } 990 singleBooleanPropertyToString(int prop)991 private static String singleBooleanPropertyToString(int prop) { 992 switch (prop) { 993 case PROPERTY_CHECKED: return "Checked"; 994 case PROPERTY_ENABLED: return "Enabled"; 995 case PROPERTY_PASSWORD: return "Password"; 996 case PROPERTY_FULL_SCREEN: return "FullScreen"; 997 case PROPERTY_SCROLLABLE: return "Scrollable"; 998 case PROPERTY_IMPORTANT_FOR_ACCESSIBILITY: 999 return "ImportantForAccessibility"; 1000 case PROPERTY_ACCESSIBILITY_DATA_SENSITIVE: 1001 return "AccessibilityDataSensitive"; 1002 default: return Integer.toHexString(prop); 1003 } 1004 } 1005 append(StringBuilder builder, String propName, int propValue)1006 private void append(StringBuilder builder, String propName, int propValue) { 1007 if (DEBUG_CONCISE_TOSTRING && propValue == UNDEFINED) return; 1008 appendPropName(builder, propName).append(propValue); 1009 } 1010 append(StringBuilder builder, String propName, Object propValue)1011 private void append(StringBuilder builder, String propName, Object propValue) { 1012 if (DEBUG_CONCISE_TOSTRING && propValue == null) return; 1013 appendPropName(builder, propName).append(propValue); 1014 } 1015 appendPropName(StringBuilder builder, String propName)1016 private StringBuilder appendPropName(StringBuilder builder, String propName) { 1017 return builder.append("; ").append(propName).append(": "); 1018 } 1019 } 1020