AccessibilityEvent.java revision 9210ccbdc3629cead65a822d729e1783a773118c
1/*
2 * Copyright (C) 2009 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
17package android.view.accessibility;
18
19import android.accessibilityservice.IAccessibilityServiceConnection;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.os.RemoteException;
23import android.text.TextUtils;
24import android.view.View;
25
26import java.util.ArrayList;
27
28/**
29 * This class represents accessibility events that are sent by the system when
30 * something notable happens in the user interface. For example, when a
31 * {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc.
32 * <p>
33 * An accessibility event is fired by an individual view which populates the event with
34 * a record for its state and requests from its parent to send the event to interested
35 * parties. The parent can optionally add a record for itself before dispatching a similar
36 * request to its parent. A parent can also choose not to respect the request for sending
37 * an event. The accessibility event is sent by the topmost view in the view tree.
38 * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore
39 * all records in an accessibility event to obtain more information about the context
40 * in which the event was fired.
41 * <p>
42 * A client can add, remove, and modify records. The getters and setters for individual
43 * properties operate on the current record which can be explicitly set by the client. By
44 * default current is the first record. Thus, querying a record would require setting
45 * it as the current one and interacting with the property getters and setters.
46 * <p>
47 * This class represents various semantically different accessibility event
48 * types. Each event type has associated a set of related properties. In other
49 * words, each event type is characterized via a subset of the properties exposed
50 * by this class. For each event type there is a corresponding constant defined
51 * in this class. Since some event types are semantically close there are mask
52 * constants that group them together. Follows a specification of the event
53 * types and their associated properties:
54 * <p>
55 * <b>VIEW TYPES</b> <br>
56 * <p>
57 * <b>View clicked</b> - represents the event of clicking on a {@link android.view.View}
58 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br>
59 * Type:{@link #TYPE_VIEW_CLICKED} <br>
60 * Properties:
61 * {@link #getClassName()},
62 * {@link #getPackageName()},
63 * {@link #getEventTime()},
64 * {@link #getText()},
65 * {@link #isChecked()},
66 * {@link #isEnabled()},
67 * {@link #isPassword()},
68 * {@link #getItemCount()},
69 * {@link #getCurrentItemIndex()}
70 * <p>
71 * <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View}
72 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br>
73 * Type:{@link #TYPE_VIEW_LONG_CLICKED} <br>
74 * Properties:
75 * {@link #getClassName()},
76 * {@link #getPackageName()},
77 * {@link #getEventTime()},
78 * {@link #getText()},
79 * {@link #isChecked()},
80 * {@link #isEnabled()},
81 * {@link #isPassword()},
82 * {@link #getItemCount()},
83 * {@link #getCurrentItemIndex()}
84 * <p>
85 * <b>View selected</b> - represents the event of selecting an item usually in
86 * the context of an {@link android.widget.AdapterView}. <br>
87 * Type: {@link #TYPE_VIEW_SELECTED} <br>
88 * Properties:
89 * {@link #getClassName()},
90 * {@link #getPackageName()},
91 * {@link #getEventTime()},
92 * {@link #getText()},
93 * {@link #isChecked()},
94 * {@link #isEnabled()},
95 * {@link #isPassword()},
96 * {@link #getItemCount()},
97 * {@link #getCurrentItemIndex()}
98 * <p>
99 * <b>View focused</b> - represents the event of focusing a
100 * {@link android.view.View}. <br>
101 * Type: {@link #TYPE_VIEW_FOCUSED} <br>
102 * Properties:
103 * {@link #getClassName()},
104 * {@link #getPackageName()},
105 * {@link #getEventTime()},
106 * {@link #getText()},
107 * {@link #isChecked()},
108 * {@link #isEnabled()},
109 * {@link #isPassword()},
110 * {@link #getItemCount()},
111 * {@link #getCurrentItemIndex()}
112 * <p>
113 * <b>View text changed</b> - represents the event of changing the text of an
114 * {@link android.widget.EditText}. <br>
115 * Type: {@link #TYPE_VIEW_TEXT_CHANGED} <br>
116 * Properties:
117 * {@link #getClassName()},
118 * {@link #getPackageName()},
119 * {@link #getEventTime()},
120 * {@link #getText()},
121 * {@link #isChecked()},
122 * {@link #isEnabled()},
123 * {@link #isPassword()},
124 * {@link #getItemCount()},
125 * {@link #getCurrentItemIndex()},
126 * {@link #getFromIndex()},
127 * {@link #getAddedCount()},
128 * {@link #getRemovedCount()},
129 * {@link #getBeforeText()}
130 * <p>
131 * <b>TRANSITION TYPES</b> <br>
132 * <p>
133 * <b>Window state changed</b> - represents the event of opening/closing a
134 * {@link android.widget.PopupWindow}, {@link android.view.Menu},
135 * {@link android.app.Dialog}, etc. <br>
136 * Type: {@link #TYPE_WINDOW_STATE_CHANGED} <br>
137 * Properties:
138 * {@link #getClassName()},
139 * {@link #getPackageName()},
140 * {@link #getEventTime()},
141 * {@link #getText()}
142 * <p>
143 * <b>NOTIFICATION TYPES</b> <br>
144 * <p>
145 * <b>Notification state changed</b> - represents the event showing/hiding
146 * {@link android.app.Notification}.
147 * Type: {@link #TYPE_NOTIFICATION_STATE_CHANGED} <br>
148 * Properties:
149 * {@link #getClassName()},
150 * {@link #getPackageName()},
151 * {@link #getEventTime()},
152 * {@link #getText()}
153 * {@link #getParcelableData()}
154 * <p>
155 * <b>Security note</b>
156 * <p>
157 * Since an event contains the text of its source privacy can be compromised by leaking of
158 * sensitive information such as passwords. To address this issue any event fired in response
159 * to manipulation of a PASSWORD field does NOT CONTAIN the text of the password.
160 *
161 * @see android.view.accessibility.AccessibilityManager
162 * @see android.accessibilityservice.AccessibilityService
163 */
164public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
165    private static final boolean DEBUG = false;
166
167    /**
168     * Invalid selection/focus position.
169     *
170     * @see #getCurrentItemIndex()
171     */
172    public static final int INVALID_POSITION = -1;
173
174    /**
175     * Maximum length of the text fields.
176     *
177     * @see #getBeforeText()
178     * @see #getText()
179     * </br>
180     * Note: This constant is no longer needed since there
181     *       is no limit on the length of text that is contained
182     *       in an accessibility event anymore.
183     */
184    @Deprecated
185    public static final int MAX_TEXT_LENGTH = 500;
186
187    /**
188     * Represents the event of clicking on a {@link android.view.View} like
189     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
190     */
191    public static final int TYPE_VIEW_CLICKED = 0x00000001;
192
193    /**
194     * Represents the event of long clicking on a {@link android.view.View} like
195     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
196     */
197    public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002;
198
199    /**
200     * Represents the event of selecting an item usually in the context of an
201     * {@link android.widget.AdapterView}.
202     */
203    public static final int TYPE_VIEW_SELECTED = 0x00000004;
204
205    /**
206     * Represents the event of focusing a {@link android.view.View}.
207     */
208    public static final int TYPE_VIEW_FOCUSED = 0x00000008;
209
210    /**
211     * Represents the event of changing the text of an {@link android.widget.EditText}.
212     */
213    public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010;
214
215    /**
216     * Represents the event of opening/closing a {@link android.widget.PopupWindow},
217     * {@link android.view.Menu}, {@link android.app.Dialog}, etc.
218     */
219    public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020;
220
221    /**
222     * Represents the event showing/hiding a {@link android.app.Notification}.
223     */
224    public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
225
226    /**
227     * Represents the event of a hover enter over a {@link android.view.View}.
228     */
229    public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
230
231    /**
232     * Represents the event of a hover exit over a {@link android.view.View}.
233     */
234    public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
235
236    /**
237     * Represents the event of starting a touch exploration gesture.
238     */
239    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
240
241    /**
242     * Represents the event of ending a touch exploration gesture.
243     */
244    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
245
246    /**
247     * Mask for {@link AccessibilityEvent} all types.
248     *
249     * @see #TYPE_VIEW_CLICKED
250     * @see #TYPE_VIEW_LONG_CLICKED
251     * @see #TYPE_VIEW_SELECTED
252     * @see #TYPE_VIEW_FOCUSED
253     * @see #TYPE_VIEW_TEXT_CHANGED
254     * @see #TYPE_WINDOW_STATE_CHANGED
255     * @see #TYPE_NOTIFICATION_STATE_CHANGED
256     */
257    public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
258
259    private static final int MAX_POOL_SIZE = 10;
260    private static final Object sPoolLock = new Object();
261    private static AccessibilityEvent sPool;
262    private static int sPoolSize;
263    private AccessibilityEvent mNext;
264    private boolean mIsInPool;
265
266    private int mEventType;
267    private int mSourceAccessibilityViewId = View.NO_ID;
268    private int mSourceAccessibilityWindowId = View.NO_ID;
269    private CharSequence mPackageName;
270    private long mEventTime;
271
272    private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
273
274    private IAccessibilityServiceConnection mConnection;
275
276    /*
277     * Hide constructor from clients.
278     */
279    private AccessibilityEvent() {
280    }
281
282    /**
283     * Initialize an event from another one.
284     *
285     * @param event The event to initialize from.
286     */
287    void init(AccessibilityEvent event) {
288        super.init(event);
289        mEventType = event.mEventType;
290        mEventTime = event.mEventTime;
291        mSourceAccessibilityWindowId = event.mSourceAccessibilityWindowId;
292        mSourceAccessibilityViewId = event.mSourceAccessibilityViewId;
293        mPackageName = event.mPackageName;
294        mConnection = event.mConnection;
295    }
296
297    /**
298     * Gets the number of records contained in the event.
299     *
300     * @return The number of records.
301     */
302    public int getRecordCount() {
303        return mRecords.size();
304    }
305
306    /**
307     * Appends an {@link AccessibilityRecord} to the end of event records.
308     *
309     * @param record The record to append.
310     *
311     * @throws IllegalStateException If called from an AccessibilityService.
312     */
313    public void appendRecord(AccessibilityRecord record) {
314        enforceNotSealed();
315        mRecords.add(record);
316    }
317
318    /**
319     * Gets the records at a given index.
320     *
321     * @param index The index.
322     * @return The records at the specified index.
323     */
324    public AccessibilityRecord getRecord(int index) {
325        return mRecords.get(index);
326    }
327
328    /**
329     * Gets the event type.
330     *
331     * @return The event type.
332     */
333    public int getEventType() {
334        return mEventType;
335    }
336
337    /**
338     * Sets the event source.
339     *
340     * @param source The source.
341     *
342     * @throws IllegalStateException If called from an AccessibilityService.
343     */
344    public void setSource(View source) {
345        enforceNotSealed();
346        if (source != null) {
347            mSourceAccessibilityWindowId = source.getAccessibilityWindowId();
348            mSourceAccessibilityViewId = source.getAccessibilityViewId();
349        } else {
350            mSourceAccessibilityWindowId = View.NO_ID;
351            mSourceAccessibilityViewId = View.NO_ID;
352        }
353    }
354
355    /**
356     * Gets the {@link AccessibilityNodeInfo} of the event source.
357     * <p>
358     *   <strong>
359     *     It is a client responsibility to recycle the received info by
360     *     calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
361     *     of multiple instances.
362     *   </strong>
363     * </p>
364     * @return The info.
365     */
366    public AccessibilityNodeInfo getSource() {
367        enforceSealed();
368        if (mSourceAccessibilityWindowId == View.NO_ID
369                || mSourceAccessibilityViewId == View.NO_ID) {
370            return null;
371        }
372        try {
373            return mConnection.findAccessibilityNodeInfoByAccessibilityId(
374                    mSourceAccessibilityWindowId, mSourceAccessibilityViewId);
375        } catch (RemoteException e) {
376            return null;
377        }
378    }
379
380    /**
381     * Gets the id of the window from which the event comes from.
382     *
383     * @return The window id.
384     */
385    public int getAccessibilityWindowId() {
386        return mSourceAccessibilityWindowId;
387    }
388
389    /**
390     * Sets the client token for the accessibility service that
391     * provided this node info.
392     *
393     * @param connection The connection.
394     *
395     * @hide
396     */
397    public final void setConnection(IAccessibilityServiceConnection connection) {
398        mConnection = connection;
399    }
400
401    /**
402     * Gets the accessibility window id of the source window.
403     *
404     * @return The id.
405     *
406     * @hide
407     */
408    public int getSourceAccessibilityWindowId() {
409        return mSourceAccessibilityWindowId;
410    }
411
412    /**
413     * Sets the event type.
414     *
415     * @param eventType The event type.
416     *
417     * @throws IllegalStateException If called from an AccessibilityService.
418     */
419    public void setEventType(int eventType) {
420        enforceNotSealed();
421        mEventType = eventType;
422    }
423
424    /**
425     * Gets the time in which this event was sent.
426     *
427     * @return The event time.
428     */
429    public long getEventTime() {
430        return mEventTime;
431    }
432
433    /**
434     * Sets the time in which this event was sent.
435     *
436     * @param eventTime The event time.
437     *
438     * @throws IllegalStateException If called from an AccessibilityService.
439     */
440    public void setEventTime(long eventTime) {
441        enforceNotSealed();
442        mEventTime = eventTime;
443    }
444
445    /**
446     * Gets the package name of the source.
447     *
448     * @return The package name.
449     */
450    public CharSequence getPackageName() {
451        return mPackageName;
452    }
453
454    /**
455     * Sets the package name of the source.
456     *
457     * @param packageName The package name.
458     *
459     * @throws IllegalStateException If called from an AccessibilityService.
460     */
461    public void setPackageName(CharSequence packageName) {
462        enforceNotSealed();
463        mPackageName = packageName;
464    }
465
466    /**
467     * Returns a cached instance if such is available or a new one is
468     * instantiated with type property set.
469     *
470     * @param eventType The event type.
471     * @return An instance.
472     */
473    public static AccessibilityEvent obtain(int eventType) {
474        AccessibilityEvent event = AccessibilityEvent.obtain();
475        event.setEventType(eventType);
476        return event;
477    }
478
479    /**
480     * Returns a cached instance if such is available or a new one is
481     * instantiated with type property set.
482     *
483     * @param event The other event.
484     * @return An instance.
485     */
486    public static AccessibilityEvent obtain(AccessibilityEvent event) {
487        AccessibilityEvent eventClone = AccessibilityEvent.obtain();
488        eventClone.init(event);
489
490        final int recordCount = event.mRecords.size();
491        for (int i = 0; i < recordCount; i++) {
492            AccessibilityRecord record = event.mRecords.get(i);
493            AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
494            eventClone.mRecords.add(recordClone);
495        }
496
497        return eventClone;
498    }
499
500    /**
501     * Returns a cached instance if such is available or a new one is
502     * instantiated.
503     *
504     * @return An instance.
505     */
506    public static AccessibilityEvent obtain() {
507        synchronized (sPoolLock) {
508            if (sPool != null) {
509                AccessibilityEvent event = sPool;
510                sPool = sPool.mNext;
511                sPoolSize--;
512                event.mNext = null;
513                event.mIsInPool = false;
514                return event;
515            }
516            return new AccessibilityEvent();
517        }
518    }
519
520    /**
521     * Return an instance back to be reused.
522     * <p>
523     * <b>Note: You must not touch the object after calling this function.</b>
524     *
525     * @throws IllegalStateException If the event is already recycled.
526     */
527    @Override
528    public void recycle() {
529        if (mIsInPool) {
530            throw new IllegalStateException("Event already recycled!");
531        }
532        clear();
533        synchronized (sPoolLock) {
534            if (sPoolSize <= MAX_POOL_SIZE) {
535                mNext = sPool;
536                sPool = this;
537                mIsInPool = true;
538                sPoolSize++;
539            }
540        }
541    }
542
543    /**
544     * Clears the state of this instance.
545     *
546     * @hide
547     */
548    @Override
549    protected void clear() {
550        super.clear();
551        mConnection = null;
552        mEventType = 0;
553        mSourceAccessibilityViewId = View.NO_ID;
554        mSourceAccessibilityWindowId = View.NO_ID;
555        mPackageName = null;
556        mEventTime = 0;
557        while (!mRecords.isEmpty()) {
558            AccessibilityRecord record = mRecords.remove(0);
559            record.recycle();
560        }
561    }
562
563    /**
564     * Creates a new instance from a {@link Parcel}.
565     *
566     * @param parcel A parcel containing the state of a {@link AccessibilityEvent}.
567     */
568    public void initFromParcel(Parcel parcel) {
569        if (parcel.readInt() == 1) {
570            mConnection = IAccessibilityServiceConnection.Stub.asInterface(
571                    parcel.readStrongBinder());
572        }
573        setSealed(parcel.readInt() == 1);
574        mEventType = parcel.readInt();
575        mSourceAccessibilityWindowId = parcel.readInt();
576        mSourceAccessibilityViewId = parcel.readInt();
577        mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
578        mEventTime = parcel.readLong();
579        readAccessibilityRecordFromParcel(this, parcel);
580
581        // Read the records.
582        final int recordCount = parcel.readInt();
583        for (int i = 0; i < recordCount; i++) {
584            AccessibilityRecord record = AccessibilityRecord.obtain();
585            readAccessibilityRecordFromParcel(record, parcel);
586            mRecords.add(record);
587        }
588    }
589
590    /**
591     * Reads an {@link AccessibilityRecord} from a parcel.
592     *
593     * @param record The record to initialize.
594     * @param parcel The parcel to read from.
595     */
596    private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
597            Parcel parcel) {
598        record.mBooleanProperties = parcel.readInt();
599        record.mCurrentItemIndex = parcel.readInt();
600        record.mItemCount = parcel.readInt();
601        record.mFromIndex = parcel.readInt();
602        record.mAddedCount = parcel.readInt();
603        record.mRemovedCount = parcel.readInt();
604        record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
605        record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
606        record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
607        record.mParcelableData = parcel.readParcelable(null);
608        parcel.readList(record.mText, null);
609    }
610
611    /**
612     * {@inheritDoc}
613     */
614    public void writeToParcel(Parcel parcel, int flags) {
615        if (mConnection == null) {
616            parcel.writeInt(0);
617        } else {
618            parcel.writeInt(1);
619            parcel.writeStrongBinder(mConnection.asBinder());
620        }
621        parcel.writeInt(isSealed() ? 1 : 0);
622        parcel.writeInt(mEventType);
623        parcel.writeInt(mSourceAccessibilityWindowId);
624        parcel.writeInt(mSourceAccessibilityViewId);
625        TextUtils.writeToParcel(mPackageName, parcel, 0);
626        parcel.writeLong(mEventTime);
627        writeAccessibilityRecordToParcel(this, parcel, flags);
628
629        // Write the records.
630        final int recordCount = getRecordCount();
631        parcel.writeInt(recordCount);
632        for (int i = 0; i < recordCount; i++) {
633            AccessibilityRecord record = mRecords.get(i);
634            writeAccessibilityRecordToParcel(record, parcel, flags);
635        }
636    }
637
638    /**
639     * Writes an {@link AccessibilityRecord} to a parcel.
640     *
641     * @param record The record to write.
642     * @param parcel The parcel to which to write.
643     */
644    private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel,
645            int flags) {
646        parcel.writeInt(record.mBooleanProperties);
647        parcel.writeInt(record.mCurrentItemIndex);
648        parcel.writeInt(record.mItemCount);
649        parcel.writeInt(record.mFromIndex);
650        parcel.writeInt(record.mAddedCount);
651        parcel.writeInt(record.mRemovedCount);
652        TextUtils.writeToParcel(record.mClassName, parcel, flags);
653        TextUtils.writeToParcel(record.mContentDescription, parcel, flags);
654        TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
655        parcel.writeParcelable(record.mParcelableData, flags);
656        parcel.writeList(record.mText);
657    }
658
659    /**
660     * {@inheritDoc}
661     */
662    public int describeContents() {
663        return 0;
664    }
665
666    @Override
667    public String toString() {
668        StringBuilder builder = new StringBuilder();
669        builder.append("; EventType: ").append(eventTypeToString(mEventType));
670        builder.append("; EventTime: ").append(mEventTime);
671        builder.append("; PackageName: ").append(mPackageName);
672        builder.append(super.toString());
673        if (DEBUG) {
674            builder.append("\n");
675            builder.append("; sourceAccessibilityWindowId: ").append(mSourceAccessibilityWindowId);
676            builder.append("; sourceAccessibilityViewId: ").append(mSourceAccessibilityViewId);
677            for (int i = 0; i < mRecords.size(); i++) {
678                AccessibilityRecord record = mRecords.get(i);
679                builder.append("  Record ");
680                builder.append(i);
681                builder.append(":");
682                builder.append(" [ ClassName: " + record.mClassName);
683                builder.append("; Text: " + record.mText);
684                builder.append("; ContentDescription: " + record.mContentDescription);
685                builder.append("; ItemCount: " + record.mItemCount);
686                builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex);
687                builder.append("; IsEnabled: " + record.isEnabled());
688                builder.append("; IsPassword: " + record.isPassword());
689                builder.append("; IsChecked: " + record.isChecked());
690                builder.append("; IsFullScreen: " + record.isFullScreen());
691                builder.append("; BeforeText: " + record.mBeforeText);
692                builder.append("; FromIndex: " + record.mFromIndex);
693                builder.append("; AddedCount: " + record.mAddedCount);
694                builder.append("; RemovedCount: " + record.mRemovedCount);
695                builder.append("; ParcelableData: " + record.mParcelableData);
696                builder.append(" ]");
697                builder.append("\n");
698            }
699        } else {
700            builder.append("; recordCount: ").append(getAddedCount());
701        }
702        return builder.toString();
703    }
704
705    /**
706     * Returns the string representation of an event type. For example,
707     * {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED.
708     *
709     * @param feedbackType The event type
710     * @return The string representation.
711     */
712    public static String eventTypeToString(int feedbackType) {
713        switch (feedbackType) {
714            case TYPE_VIEW_CLICKED:
715                return "TYPE_VIEW_CLICKED";
716            case TYPE_VIEW_LONG_CLICKED:
717                return "TYPE_VIEW_LONG_CLICKED";
718            case TYPE_VIEW_SELECTED:
719                return "TYPE_VIEW_SELECTED";
720            case TYPE_VIEW_FOCUSED:
721                return "TYPE_VIEW_FOCUSED";
722            case TYPE_VIEW_TEXT_CHANGED:
723                return "TYPE_VIEW_TEXT_CHANGED";
724            case TYPE_WINDOW_STATE_CHANGED:
725                return "TYPE_WINDOW_STATE_CHANGED";
726            case TYPE_VIEW_HOVER_ENTER:
727                return "TYPE_VIEW_HOVER_ENTER";
728            case TYPE_VIEW_HOVER_EXIT:
729                return "TYPE_VIEW_HOVER_EXIT";
730            case TYPE_NOTIFICATION_STATE_CHANGED:
731                return "TYPE_NOTIFICATION_STATE_CHANGED";
732            case TYPE_TOUCH_EXPLORATION_GESTURE_START:
733                return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
734            case TYPE_TOUCH_EXPLORATION_GESTURE_END:
735                return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
736            default:
737                return null;
738        }
739    }
740
741    /**
742     * @see Parcelable.Creator
743     */
744    public static final Parcelable.Creator<AccessibilityEvent> CREATOR =
745            new Parcelable.Creator<AccessibilityEvent>() {
746        public AccessibilityEvent createFromParcel(Parcel parcel) {
747            AccessibilityEvent event = AccessibilityEvent.obtain();
748            event.initFromParcel(parcel);
749            return event;
750        }
751
752        public AccessibilityEvent[] newArray(int size) {
753            return new AccessibilityEvent[size];
754        }
755    };
756}
757