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