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