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