• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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