AccessibilityEvent.java revision abad55d860be793b8b9b3e288a74214da89fb368
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;
22import android.util.Pools.SynchronizedPool;
23
24import java.util.ArrayList;
25import java.util.List;
26
27/**
28 * <p>
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 * <p>
34 * An accessibility event is fired by an individual view which populates the event with
35 * data for its state and requests from its parent to send the event to interested
36 * parties. The parent can optionally add an {@link AccessibilityRecord} for itself before
37 * dispatching a similar request to its parent. A parent can also choose not to respect the
38 * request for sending an event. The accessibility event is sent by the topmost view in the
39 * view tree. Therefore, an {@link android.accessibilityservice.AccessibilityService} can
40 * explore all records in an accessibility event to obtain more information about the
41 * context in which the event was fired.
42 * </p>
43 * <p>
44 * The main purpose of an accessibility event is to expose enough information for an
45 * {@link android.accessibilityservice.AccessibilityService} to provide meaningful feedback
46 * to the user. Sometimes however, an accessibility service may need more contextual
47 * information then the one in the event pay-load. In such cases the service can obtain
48 * the event source which is an {@link AccessibilityNodeInfo} (snapshot of a View state)
49 * which can be used for exploring the window content. Note that the privilege for accessing
50 * an event's source, thus the window content, has to be explicitly requested. For more
51 * details refer to {@link android.accessibilityservice.AccessibilityService}. If an
52 * accessibility service has not requested to retrieve the window content the event will
53 * not contain reference to its source. Also for events of type
54 * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available.
55 * </p>
56 * <p>
57 * This class represents various semantically different accessibility event
58 * types. Each event type has an associated set of related properties. In other
59 * words, each event type is characterized via a subset of the properties exposed
60 * by this class. For each event type there is a corresponding constant defined
61 * in this class. Follows a specification of the event types and their associated properties:
62 * </p>
63 * <div class="special reference">
64 * <h3>Developer Guides</h3>
65 * <p>For more information about creating and processing AccessibilityEvents, read the
66 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
67 * developer guide.</p>
68 * </div>
69 * <p>
70 * <b>VIEW TYPES</b></br>
71 * </p>
72 * <p>
73 * <b>View clicked</b> - represents the event of clicking on a {@link android.view.View}
74 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.</br>
75 * <em>Type:</em>{@link #TYPE_VIEW_CLICKED}</br>
76 * <em>Properties:</em></br>
77 * <ul>
78 *   <li>{@link #getEventType()} - The type of the event.</li>
79 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
80 *   <li>{@link #getClassName()} - The class name of the source.</li>
81 *   <li>{@link #getPackageName()} - The package name of the source.</li>
82 *   <li>{@link #getEventTime()}  - The event time.</li>
83 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
84 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
85 *   <li>{@link #isPassword()} - Whether the source is password.</li>
86 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
87 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
88 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
89 *       (without descendants of AdapterView).</li>
90 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
91 *       (without descendants of AdapterView).</li>
92 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
93 *       inclusive (for descendants of AdapterView).</li>
94 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
95 *       inclusive (for descendants of AdapterView).</li>
96 *   <li>{@link #getItemCount()} - The total items of the source
97 *       (for descendants of AdapterView).</li>
98 * </ul>
99 * </p>
100 * <p>
101 * <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View}
102 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc </br>
103 * <em>Type:</em>{@link #TYPE_VIEW_LONG_CLICKED}</br>
104 * <em>Properties:</em></br>
105 * <ul>
106 *   <li>{@link #getEventType()} - The type of the event.</li>
107 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
108 *   <li>{@link #getClassName()} - The class name of the source.</li>
109 *   <li>{@link #getPackageName()} - The package name of the source.</li>
110 *   <li>{@link #getEventTime()}  - The event time.</li>
111 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
112 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
113 *   <li>{@link #isPassword()} - Whether the source is password.</li>
114 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
115 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
116 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
117 *       (without descendants of AdapterView).</li>
118 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
119 *       (without descendants of AdapterView).</li>
120 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
121 *       inclusive (for descendants of AdapterView).</li>
122 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
123 *       inclusive (for descendants of AdapterView).</li>
124 *   <li>{@link #getItemCount()} - The total items of the source
125 *       (for descendants of AdapterView).</li>
126 * </ul>
127 * </p>
128 * <p>
129 * <b>View selected</b> - represents the event of selecting an item usually in
130 * the context of an {@link android.widget.AdapterView}.</br>
131 * <em>Type:</em> {@link #TYPE_VIEW_SELECTED}</br>
132 * <em>Properties:</em></br>
133 * <ul>
134 *   <li>{@link #getEventType()} - The type of the event.</li>
135 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
136 *   <li>{@link #getClassName()} - The class name of the source.</li>
137 *   <li>{@link #getPackageName()} - The package name of the source.</li>
138 *   <li>{@link #getEventTime()}  - The event time.</li>
139 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
140 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
141 *   <li>{@link #isPassword()} - Whether the source is password.</li>
142 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
143 *   <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
144 *   <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
145 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
146 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
147 *       (without descendants of AdapterView).</li>
148 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
149 *       (without descendants of AdapterView).</li>
150 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
151 *       inclusive (for descendants of AdapterView).</li>
152 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
153 *       inclusive (for descendants of AdapterView).</li>
154 *   <li>{@link #getItemCount()} - The total items of the source
155 *       (for descendants of AdapterView).</li>
156 * </ul>
157 * </p>
158 * <p>
159 * <b>View focused</b> - represents the event of focusing a
160 * {@link android.view.View}.</br>
161 * <em>Type:</em> {@link #TYPE_VIEW_FOCUSED}</br>
162 * <em>Properties:</em></br>
163 * <ul>
164 *   <li>{@link #getEventType()} - The type of the event.</li>
165 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
166 *   <li>{@link #getClassName()} - The class name of the source.</li>
167 *   <li>{@link #getPackageName()} - The package name of the source.</li>
168 *   <li>{@link #getEventTime()}  - The event time.</li>
169 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
170 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
171 *   <li>{@link #isPassword()} - Whether the source is password.</li>
172 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
173 *   <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
174 *   <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
175 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
176 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
177 *       (without descendants of AdapterView).</li>
178 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
179 *       (without descendants of AdapterView).</li>
180 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
181 *       inclusive (for descendants of AdapterView).</li>
182 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
183 *       inclusive (for descendants of AdapterView).</li>
184 *   <li>{@link #getItemCount()} - The total items of the source
185 *       (for descendants of AdapterView).</li>
186 * </ul>
187 * </p>
188 * <p>
189 * <b>View text changed</b> - represents the event of changing the text of an
190 * {@link android.widget.EditText}.</br>
191 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_CHANGED}</br>
192 * <em>Properties:</em></br>
193 * <ul>
194 *   <li>{@link #getEventType()} - The type of the event.</li>
195 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
196 *   <li>{@link #getClassName()} - The class name of the source.</li>
197 *   <li>{@link #getPackageName()} - The package name of the source.</li>
198 *   <li>{@link #getEventTime()}  - The event time.</li>
199 *   <li>{@link #getText()} - The text of the source.</li>
200 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
201 *   <li>{@link #isPassword()} - Whether the source is password.</li>
202 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
203 *   <li>{@link #getFromIndex()} - The text change start index.</li>
204 *   <li>{@link #getAddedCount()} - The number of added characters.</li>
205 *   <li>{@link #getRemovedCount()} - The number of removed characters.</li>
206 *   <li>{@link #getBeforeText()} - The text of the source before the change.</li>
207 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
208 * </ul>
209 * </p>
210 * <p>
211 * <b>View text selection changed</b> - represents the event of changing the text
212 * selection of an {@link android.widget.EditText}.</br>
213 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} </br>
214 * <em>Properties:</em></br>
215 * <ul>
216 *   <li>{@link #getEventType()} - The type of the event.</li>
217 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
218 *   <li>{@link #getClassName()} - The class name of the source.</li>
219 *   <li>{@link #getPackageName()} - The package name of the source.</li>
220 *   <li>{@link #getEventTime()}  - The event time.</li>
221 *   <li>{@link #getText()} - The text of the source.</li>
222 *   <li>{@link #isPassword()} - Whether the source is password.</li>
223 *   <li>{@link #getFromIndex()} - The selection start index.</li>
224 *   <li>{@link #getToIndex()} - The selection end index.</li>
225 *   <li>{@link #getItemCount()} - The length of the source text.</li>
226 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
227 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
228 * </ul>
229 * </p>
230 * <b>View text traversed at movement granularity</b> - represents the event of traversing the
231 * text of a view at a given granularity. For example, moving to the next word.</br>
232 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY} </br>
233 * <em>Properties:</em></br>
234 * <ul>
235 *   <li>{@link #getEventType()} - The type of the event.</li>
236 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
237 *   <li>{@link #getClassName()} - The class name of the source.</li>
238 *   <li>{@link #getPackageName()} - The package name of the source.</li>
239 *   <li>{@link #getEventTime()}  - The event time.</li>
240 *   <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
241 *       was traversed.</li>
242 *   <li>{@link #getText()} -  The text of the source's sub-tree.</li>
243 *   <li>{@link #getFromIndex()} - The start of the next/previous text at the specified granularity
244 *           - inclusive.</li>
245 *   <li>{@link #getToIndex()} - The end of the next/previous text at the specified granularity
246 *           - exclusive.</li>
247 *   <li>{@link #isPassword()} - Whether the source is password.</li>
248 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
249 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
250 *   <li>{@link #getMovementGranularity()} - Sets the granularity at which a view's text
251 *       was traversed.</li>
252 *   <li>{@link #getAction()} - Gets traversal action which specifies the direction.</li>
253 * </ul>
254 * </p>
255 * <p>
256 * <b>View scrolled</b> - represents the event of scrolling a view. If
257 * the source is a descendant of {@link android.widget.AdapterView} the
258 * scroll is reported in terms of visible items - the first visible item,
259 * the last visible item, and the total items - because the the source
260 * is unaware of its pixel size since its adapter is responsible for
261 * creating views. In all other cases the scroll is reported as the current
262 * scroll on the X and Y axis respectively plus the height of the source in
263 * pixels.</br>
264 * <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br>
265 * <em>Properties:</em></br>
266 * <ul>
267 *   <li>{@link #getEventType()} - The type of the event.</li>
268 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
269 *   <li>{@link #getClassName()} - The class name of the source.</li>
270 *   <li>{@link #getPackageName()} - The package name of the source.</li>
271 *   <li>{@link #getEventTime()}  - The event time.</li>
272 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
273 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
274 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
275 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
276 *       (without descendants of AdapterView).</li>
277 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
278 *       (without descendants of AdapterView).</li>
279 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
280 *       inclusive (for descendants of AdapterView).</li>
281 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
282 *       inclusive (for descendants of AdapterView).</li>
283 *   <li>{@link #getItemCount()} - The total items of the source
284 *       (for descendants of AdapterView).</li>
285 * </ul>
286 * <em>Note:</em> This event type is not dispatched to descendants though
287 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
288 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
289 * source {@link android.view.View} and the sub-tree rooted at it will not receive
290 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
291 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
292 * text content to such events is by setting the
293 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
294 * view.</br>
295 * </p>
296 * <p>
297 * <b>TRANSITION TYPES</b></br>
298 * </p>
299 * <p>
300 * <b>Window state changed</b> - represents the event of opening a
301 * {@link android.widget.PopupWindow}, {@link android.view.Menu},
302 * {@link android.app.Dialog}, etc.</br>
303 * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
304 * <em>Properties:</em></br>
305 * <ul>
306 *   <li>{@link #getEventType()} - The type of the event.</li>
307 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
308 *   <li>{@link #getClassName()} - The class name of the source.</li>
309 *   <li>{@link #getPackageName()} - The package name of the source.</li>
310 *   <li>{@link #getEventTime()}  - The event time.</li>
311 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
312 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
313 * </ul>
314 * </p>
315 * <p>
316 * <b>Window content changed</b> - represents the event of change in the
317 * content of a window. This change can be adding/removing view, changing
318 * a view size, etc.</br>
319 * </p>
320 * <p>
321 * <strong>Note:</strong> This event is fired only for the window source of the
322 * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED}
323 * and its purpose is to notify clients that the content of the user interaction
324 * window has changed.</br>
325 * <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br>
326 * <em>Properties:</em></br>
327 * <ul>
328 *   <li>{@link #getEventType()} - The type of the event.</li>
329 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
330 *   <li>{@link #getClassName()} - The class name of the source.</li>
331 *   <li>{@link #getPackageName()} - The package name of the source.</li>
332 *   <li>{@link #getEventTime()}  - The event time.</li>
333 * </ul>
334 * <em>Note:</em> This event type is not dispatched to descendants though
335 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
336 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
337 * source {@link android.view.View} and the sub-tree rooted at it will not receive
338 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
339 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
340 * text content to such events is by setting the
341 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
342 * view.</br>
343 * </p>
344 * <p>
345 * <b>NOTIFICATION TYPES</b></br>
346 * </p>
347 * <p>
348 * <b>Notification state changed</b> - represents the event showing
349 * {@link android.app.Notification}.</br>
350 * <em>Type:</em> {@link #TYPE_NOTIFICATION_STATE_CHANGED}</br>
351 * <em>Properties:</em></br>
352 * <ul>
353 *   <li>{@link #getEventType()} - The type of the event.</li>
354 *   <li>{@link #getClassName()} - The class name of the source.</li>
355 *   <li>{@link #getPackageName()} - The package name of the source.</li>
356 *   <li>{@link #getEventTime()}  - The event time.</li>
357 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
358 *   <li>{@link #getParcelableData()} - The posted {@link android.app.Notification}.</li>
359 *   <li>{@link #getText()} - Text for providing more context.</li>
360 * </ul>
361 * <em>Note:</em> This event type is not dispatched to descendants though
362 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
363 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
364 * source {@link android.view.View} and the sub-tree rooted at it will not receive
365 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
366 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
367 * text content to such events is by setting the
368 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
369 * view.</br>
370 * </p>
371 * <p>
372 * <b>EXPLORATION TYPES</b></br>
373 * </p>
374 * <p>
375 * <b>View hover enter</b> - represents the event of beginning to hover
376 * over a {@link android.view.View}. The hover may be generated via
377 * exploring the screen by touch or via a pointing device.</br>
378 * <em>Type:</em> {@link #TYPE_VIEW_HOVER_ENTER}</br>
379 * <em>Properties:</em></br>
380 * <ul>
381 *   <li>{@link #getEventType()} - The type of the event.</li>
382 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
383 *   <li>{@link #getClassName()} - The class name of the source.</li>
384 *   <li>{@link #getPackageName()} - The package name of the source.</li>
385 *   <li>{@link #getEventTime()}  - The event time.</li>
386 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
387 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
388 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
389 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
390 *       (without descendants of AdapterView).</li>
391 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
392 *       (without descendants of AdapterView).</li>
393 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
394 *       inclusive (for descendants of AdapterView).</li>
395 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
396 *       inclusive (for descendants of AdapterView).</li>
397 *   <li>{@link #getItemCount()} - The total items of the source
398 *       (for descendants of AdapterView).</li>
399 * </ul>
400 * </p>
401 * <b>View hover exit</b> - represents the event of stopping to hover
402 * over a {@link android.view.View}. The hover may be generated via
403 * exploring the screen by touch or via a pointing device.</br>
404 * <em>Type:</em> {@link #TYPE_VIEW_HOVER_EXIT}</br>
405 * <em>Properties:</em></br>
406 * <ul>
407 *   <li>{@link #getEventType()} - The type of the event.</li>
408 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
409 *   <li>{@link #getClassName()} - The class name of the source.</li>
410 *   <li>{@link #getPackageName()} - The package name of the source.</li>
411 *   <li>{@link #getEventTime()}  - The event time.</li>
412 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
413 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
414 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
415 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
416 *       (without descendants of AdapterView).</li>
417 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
418 *       (without descendants of AdapterView).</li>
419 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
420 *       inclusive (for descendants of AdapterView).</li>
421 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
422 *       inclusive (for descendants of AdapterView).</li>
423 *   <li>{@link #getItemCount()} - The total items of the source
424 *       (for descendants of AdapterView).</li>
425 * </ul>
426 * </p>
427 * <p>
428 * <b>Touch interaction start</b> - represents the event of starting a touch
429 * interaction, which is the user starts touching the screen.</br>
430 * <em>Type:</em> {@link #TYPE_TOUCH_INTERACTION_START}</br>
431 * <em>Properties:</em></br>
432 * <ul>
433 *   <li>{@link #getEventType()} - The type of the event.</li>
434 * </ul>
435 * <em>Note:</em> This event is fired only by the system and is not passed to the
436 * view tree to be populated.</br>
437 * </p>
438 * <p>
439 * <b>Touch interaction end</b> - represents the event of ending a touch
440 * interaction, which is the user stops touching the screen.</br>
441 * <em>Type:</em> {@link #TYPE_TOUCH_INTERACTION_END}</br>
442 * <em>Properties:</em></br>
443 * <ul>
444 *   <li>{@link #getEventType()} - The type of the event.</li>
445 * </ul>
446 * <em>Note:</em> This event is fired only by the system and is not passed to the
447 * view tree to be populated.</br>
448 * </p>
449 * <p>
450 * <b>Touch exploration gesture start</b> - represents the event of starting a touch
451 * exploring gesture.</br>
452 * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_START}</br>
453 * <em>Properties:</em></br>
454 * <ul>
455 *   <li>{@link #getEventType()} - The type of the event.</li>
456 * </ul>
457 * <em>Note:</em> This event is fired only by the system and is not passed to the
458 * view tree to be populated.</br>
459 * </p>
460 * <p>
461 * <b>Touch exploration gesture end</b> - represents the event of ending a touch
462 * exploring gesture.</br>
463 * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_END}</br>
464 * <em>Properties:</em></br>
465 * <ul>
466 *   <li>{@link #getEventType()} - The type of the event.</li>
467 * </ul>
468 * <em>Note:</em> This event is fired only by the system and is not passed to the
469 * view tree to be populated.</br>
470 * </p>
471 * <p>
472 * <b>Touch gesture detection start</b> - represents the event of starting a user
473 * gesture detection.</br>
474 * <em>Type:</em> {@link #TYPE_GESTURE_DETECTION_START}</br>
475 * <em>Properties:</em></br>
476 * <ul>
477 *   <li>{@link #getEventType()} - The type of the event.</li>
478 * </ul>
479 * <em>Note:</em> This event is fired only by the system and is not passed to the
480 * view tree to be populated.</br>
481 * </p>
482 * <p>
483 * <b>Touch gesture detection end</b> - represents the event of ending a user
484 * gesture detection.</br>
485 * <em>Type:</em> {@link #TYPE_GESTURE_DETECTION_END}</br>
486 * <em>Properties:</em></br>
487 * <ul>
488 *   <li>{@link #getEventType()} - The type of the event.</li>
489 * </ul>
490 * <em>Note:</em> This event is fired only by the system and is not passed to the
491 * view tree to be populated.</br>
492 * </p>
493 * <p>
494 * <b>MISCELLANEOUS TYPES</b></br>
495 * </p>
496 * <p>
497 * <b>Announcement</b> - represents the event of an application making an
498 * announcement. Usually this announcement is related to some sort of a context
499 * change for which none of the events representing UI transitions is a good fit.
500 * For example, announcing a new page in a book.</br>
501 * <em>Type:</em> {@link #TYPE_ANNOUNCEMENT}</br>
502 * <em>Properties:</em></br>
503 * <ul>
504 *   <li>{@link #getEventType()} - The type of the event.</li>
505 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
506 *   <li>{@link #getClassName()} - The class name of the source.</li>
507 *   <li>{@link #getPackageName()} - The package name of the source.</li>
508 *   <li>{@link #getEventTime()}  - The event time.</li>
509 *   <li>{@link #getText()} - The text of the announcement.</li>
510 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
511 * </ul>
512 * </p>
513 * <p>
514 * <b>Security note</b>
515 * <p>
516 * Since an event contains the text of its source privacy can be compromised by leaking
517 * sensitive information such as passwords. To address this issue any event fired in response
518 * to manipulation of a PASSWORD field does NOT CONTAIN the text of the password.
519 * </p>
520 *
521 * @see android.view.accessibility.AccessibilityManager
522 * @see android.accessibilityservice.AccessibilityService
523 * @see AccessibilityNodeInfo
524 */
525public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
526    private static final boolean DEBUG = false;
527
528    /**
529     * Invalid selection/focus position.
530     *
531     * @see #getCurrentItemIndex()
532     */
533    public static final int INVALID_POSITION = -1;
534
535    /**
536     * Maximum length of the text fields.
537     *
538     * @see #getBeforeText()
539     * @see #getText()
540     * </br>
541     * Note: This constant is no longer needed since there
542     *       is no limit on the length of text that is contained
543     *       in an accessibility event anymore.
544     */
545    @Deprecated
546    public static final int MAX_TEXT_LENGTH = 500;
547
548    /**
549     * Represents the event of clicking on a {@link android.view.View} like
550     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
551     */
552    public static final int TYPE_VIEW_CLICKED = 0x00000001;
553
554    /**
555     * Represents the event of long clicking on a {@link android.view.View} like
556     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
557     */
558    public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002;
559
560    /**
561     * Represents the event of selecting an item usually in the context of an
562     * {@link android.widget.AdapterView}.
563     */
564    public static final int TYPE_VIEW_SELECTED = 0x00000004;
565
566    /**
567     * Represents the event of setting input focus of a {@link android.view.View}.
568     */
569    public static final int TYPE_VIEW_FOCUSED = 0x00000008;
570
571    /**
572     * Represents the event of changing the text of an {@link android.widget.EditText}.
573     */
574    public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010;
575
576    /**
577     * Represents the event of opening a {@link android.widget.PopupWindow},
578     * {@link android.view.Menu}, {@link android.app.Dialog}, etc.
579     */
580    public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020;
581
582    /**
583     * Represents the event showing a {@link android.app.Notification}.
584     */
585    public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
586
587    /**
588     * Represents the event of a hover enter over a {@link android.view.View}.
589     */
590    public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
591
592    /**
593     * Represents the event of a hover exit over a {@link android.view.View}.
594     */
595    public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
596
597    /**
598     * Represents the event of starting a touch exploration gesture.
599     */
600    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
601
602    /**
603     * Represents the event of ending a touch exploration gesture.
604     */
605    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
606
607    /**
608     * Represents the event of changing the content of a window and more
609     * specifically the sub-tree rooted at the event's source.
610     */
611    public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
612
613    /**
614     * Represents the event of scrolling a view.
615     */
616    public static final int TYPE_VIEW_SCROLLED = 0x00001000;
617
618    /**
619     * Represents the event of changing the selection in an {@link android.widget.EditText}.
620     */
621    public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000;
622
623    /**
624     * Represents the event of an application making an announcement.
625     */
626    public static final int TYPE_ANNOUNCEMENT = 0x00004000;
627
628    /**
629     * Represents the event of gaining accessibility focus.
630     */
631    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000;
632
633    /**
634     * Represents the event of clearing accessibility focus.
635     */
636    public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000;
637
638    /**
639     * Represents the event of traversing the text of a view at a given movement granularity.
640     */
641    public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 0x00020000;
642
643    /**
644     * Represents the event of beginning gesture detection.
645     */
646    public static final int TYPE_GESTURE_DETECTION_START = 0x00040000;
647
648    /**
649     * Represents the event of ending gesture detection.
650     */
651    public static final int TYPE_GESTURE_DETECTION_END = 0x00080000;
652
653    /**
654     * Represents the event of the user starting to touch the screen.
655     */
656    public static final int TYPE_TOUCH_INTERACTION_START = 0x00100000;
657
658    /**
659     * Represents the event of the user ending to touch the screen.
660     */
661    public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000;
662
663    /**
664     * Mask for {@link AccessibilityEvent} all types.
665     *
666     * @see #TYPE_VIEW_CLICKED
667     * @see #TYPE_VIEW_LONG_CLICKED
668     * @see #TYPE_VIEW_SELECTED
669     * @see #TYPE_VIEW_FOCUSED
670     * @see #TYPE_VIEW_TEXT_CHANGED
671     * @see #TYPE_WINDOW_STATE_CHANGED
672     * @see #TYPE_NOTIFICATION_STATE_CHANGED
673     * @see #TYPE_VIEW_HOVER_ENTER
674     * @see #TYPE_VIEW_HOVER_EXIT
675     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START
676     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END
677     * @see #TYPE_WINDOW_CONTENT_CHANGED
678     * @see #TYPE_VIEW_SCROLLED
679     * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED
680     * @see #TYPE_ANNOUNCEMENT
681     * @see #TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
682     * @see #TYPE_GESTURE_DETECTION_START
683     * @see #TYPE_GESTURE_DETECTION_END
684     * @see #TYPE_TOUCH_INTERACTION_START
685     * @see #TYPE_TOUCH_INTERACTION_END
686     */
687    public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
688
689    private static final int MAX_POOL_SIZE = 10;
690    private static final SynchronizedPool<AccessibilityEvent> sPool =
691            new SynchronizedPool<AccessibilityEvent>(MAX_POOL_SIZE);
692
693    private int mEventType;
694    private CharSequence mPackageName;
695    private long mEventTime;
696    int mMovementGranularity;
697    int mAction;
698
699    private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
700
701    /*
702     * Hide constructor from clients.
703     */
704    private AccessibilityEvent() {
705    }
706
707    /**
708     * Initialize an event from another one.
709     *
710     * @param event The event to initialize from.
711     */
712    void init(AccessibilityEvent event) {
713        super.init(event);
714        mEventType = event.mEventType;
715        mMovementGranularity = event.mMovementGranularity;
716        mAction = event.mAction;
717        mEventTime = event.mEventTime;
718        mPackageName = event.mPackageName;
719    }
720
721    /**
722     * Sets if this instance is sealed.
723     *
724     * @param sealed Whether is sealed.
725     *
726     * @hide
727     */
728    @Override
729    public void setSealed(boolean sealed) {
730        super.setSealed(sealed);
731        List<AccessibilityRecord> records = mRecords;
732        final int recordCount = records.size();
733        for (int i = 0; i < recordCount; i++) {
734            AccessibilityRecord record = records.get(i);
735            record.setSealed(sealed);
736        }
737    }
738
739    /**
740     * Gets the number of records contained in the event.
741     *
742     * @return The number of records.
743     */
744    public int getRecordCount() {
745        return mRecords.size();
746    }
747
748    /**
749     * Appends an {@link AccessibilityRecord} to the end of event records.
750     *
751     * @param record The record to append.
752     *
753     * @throws IllegalStateException If called from an AccessibilityService.
754     */
755    public void appendRecord(AccessibilityRecord record) {
756        enforceNotSealed();
757        mRecords.add(record);
758    }
759
760    /**
761     * Gets the record at a given index.
762     *
763     * @param index The index.
764     * @return The record at the specified index.
765     */
766    public AccessibilityRecord getRecord(int index) {
767        return mRecords.get(index);
768    }
769
770    /**
771     * Gets the event type.
772     *
773     * @return The event type.
774     */
775    public int getEventType() {
776        return mEventType;
777    }
778
779    /**
780     * Sets the event type.
781     *
782     * @param eventType The event type.
783     *
784     * @throws IllegalStateException If called from an AccessibilityService.
785     */
786    public void setEventType(int eventType) {
787        enforceNotSealed();
788        mEventType = eventType;
789    }
790
791    /**
792     * Gets the time in which this event was sent.
793     *
794     * @return The event time.
795     */
796    public long getEventTime() {
797        return mEventTime;
798    }
799
800    /**
801     * Sets the time in which this event was sent.
802     *
803     * @param eventTime The event time.
804     *
805     * @throws IllegalStateException If called from an AccessibilityService.
806     */
807    public void setEventTime(long eventTime) {
808        enforceNotSealed();
809        mEventTime = eventTime;
810    }
811
812    /**
813     * Gets the package name of the source.
814     *
815     * @return The package name.
816     */
817    public CharSequence getPackageName() {
818        return mPackageName;
819    }
820
821    /**
822     * Sets the package name of the source.
823     *
824     * @param packageName The package name.
825     *
826     * @throws IllegalStateException If called from an AccessibilityService.
827     */
828    public void setPackageName(CharSequence packageName) {
829        enforceNotSealed();
830        mPackageName = packageName;
831    }
832
833    /**
834     * Sets the movement granularity that was traversed.
835     *
836     * @param granularity The granularity.
837     *
838     * @throws IllegalStateException If called from an AccessibilityService.
839     */
840    public void setMovementGranularity(int granularity) {
841        enforceNotSealed();
842        mMovementGranularity = granularity;
843    }
844
845    /**
846     * Gets the movement granularity that was traversed.
847     *
848     * @return The granularity.
849     */
850    public int getMovementGranularity() {
851        return mMovementGranularity;
852    }
853
854    /**
855     * Sets the performed action that triggered this event.
856     *
857     * @param action The action.
858     *
859     * @throws IllegalStateException If called from an AccessibilityService.
860     */
861    public void setAction(int action) {
862        enforceNotSealed();
863        mAction = action;
864    }
865
866    /**
867     * Gets the performed action that triggered this event.
868     *
869     * @return The action.
870     */
871    public int getAction() {
872        return mAction;
873    }
874
875    /**
876     * Returns a cached instance if such is available or a new one is
877     * instantiated with its type property set.
878     *
879     * @param eventType The event type.
880     * @return An instance.
881     */
882    public static AccessibilityEvent obtain(int eventType) {
883        AccessibilityEvent event = AccessibilityEvent.obtain();
884        event.setEventType(eventType);
885        return event;
886    }
887
888    /**
889     * Returns a cached instance if such is available or a new one is
890     * created. The returned instance is initialized from the given
891     * <code>event</code>.
892     *
893     * @param event The other event.
894     * @return An instance.
895     */
896    public static AccessibilityEvent obtain(AccessibilityEvent event) {
897        AccessibilityEvent eventClone = AccessibilityEvent.obtain();
898        eventClone.init(event);
899
900        final int recordCount = event.mRecords.size();
901        for (int i = 0; i < recordCount; i++) {
902            AccessibilityRecord record = event.mRecords.get(i);
903            AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
904            eventClone.mRecords.add(recordClone);
905        }
906
907        return eventClone;
908    }
909
910    /**
911     * Returns a cached instance if such is available or a new one is
912     * instantiated.
913     *
914     * @return An instance.
915     */
916    public static AccessibilityEvent obtain() {
917        AccessibilityEvent event = sPool.acquire();
918        return (event != null) ? event : new AccessibilityEvent();
919    }
920
921    /**
922     * Recycles an instance back to be reused.
923     * <p>
924     *   <b>Note: You must not touch the object after calling this function.</b>
925     * </p>
926     *
927     * @throws IllegalStateException If the event is already recycled.
928     */
929    @Override
930    public void recycle() {
931        clear();
932        sPool.release(this);
933    }
934
935    /**
936     * Clears the state of this instance.
937     *
938     * @hide
939     */
940    @Override
941    protected void clear() {
942        super.clear();
943        mEventType = 0;
944        mMovementGranularity = 0;
945        mAction = 0;
946        mPackageName = null;
947        mEventTime = 0;
948        while (!mRecords.isEmpty()) {
949            AccessibilityRecord record = mRecords.remove(0);
950            record.recycle();
951        }
952    }
953
954    /**
955     * Creates a new instance from a {@link Parcel}.
956     *
957     * @param parcel A parcel containing the state of a {@link AccessibilityEvent}.
958     */
959    public void initFromParcel(Parcel parcel) {
960        mSealed = (parcel.readInt() == 1);
961        mEventType = parcel.readInt();
962        mMovementGranularity = parcel.readInt();
963        mAction = parcel.readInt();
964        mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
965        mEventTime = parcel.readLong();
966        mConnectionId = parcel.readInt();
967        readAccessibilityRecordFromParcel(this, parcel);
968
969        // Read the records.
970        final int recordCount = parcel.readInt();
971        for (int i = 0; i < recordCount; i++) {
972            AccessibilityRecord record = AccessibilityRecord.obtain();
973            readAccessibilityRecordFromParcel(record, parcel);
974            record.mConnectionId = mConnectionId;
975            mRecords.add(record);
976        }
977    }
978
979    /**
980     * Reads an {@link AccessibilityRecord} from a parcel.
981     *
982     * @param record The record to initialize.
983     * @param parcel The parcel to read from.
984     */
985    private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
986            Parcel parcel) {
987        record.mBooleanProperties = parcel.readInt();
988        record.mCurrentItemIndex = parcel.readInt();
989        record.mItemCount = parcel.readInt();
990        record.mFromIndex = parcel.readInt();
991        record.mToIndex = parcel.readInt();
992        record.mScrollX = parcel.readInt();
993        record.mScrollY =  parcel.readInt();
994        record.mMaxScrollX = parcel.readInt();
995        record.mMaxScrollY =  parcel.readInt();
996        record.mAddedCount = parcel.readInt();
997        record.mRemovedCount = parcel.readInt();
998        record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
999        record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
1000        record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
1001        record.mParcelableData = parcel.readParcelable(null);
1002        parcel.readList(record.mText, null);
1003        record.mSourceWindowId = parcel.readInt();
1004        record.mSourceNodeId = parcel.readLong();
1005        record.mSealed = (parcel.readInt() == 1);
1006    }
1007
1008    /**
1009     * {@inheritDoc}
1010     */
1011    public void writeToParcel(Parcel parcel, int flags) {
1012        parcel.writeInt(isSealed() ? 1 : 0);
1013        parcel.writeInt(mEventType);
1014        parcel.writeInt(mMovementGranularity);
1015        parcel.writeInt(mAction);
1016        TextUtils.writeToParcel(mPackageName, parcel, 0);
1017        parcel.writeLong(mEventTime);
1018        parcel.writeInt(mConnectionId);
1019        writeAccessibilityRecordToParcel(this, parcel, flags);
1020
1021        // Write the records.
1022        final int recordCount = getRecordCount();
1023        parcel.writeInt(recordCount);
1024        for (int i = 0; i < recordCount; i++) {
1025            AccessibilityRecord record = mRecords.get(i);
1026            writeAccessibilityRecordToParcel(record, parcel, flags);
1027        }
1028    }
1029
1030    /**
1031     * Writes an {@link AccessibilityRecord} to a parcel.
1032     *
1033     * @param record The record to write.
1034     * @param parcel The parcel to which to write.
1035     */
1036    private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel,
1037            int flags) {
1038        parcel.writeInt(record.mBooleanProperties);
1039        parcel.writeInt(record.mCurrentItemIndex);
1040        parcel.writeInt(record.mItemCount);
1041        parcel.writeInt(record.mFromIndex);
1042        parcel.writeInt(record.mToIndex);
1043        parcel.writeInt(record.mScrollX);
1044        parcel.writeInt(record.mScrollY);
1045        parcel.writeInt(record.mMaxScrollX);
1046        parcel.writeInt(record.mMaxScrollY);
1047        parcel.writeInt(record.mAddedCount);
1048        parcel.writeInt(record.mRemovedCount);
1049        TextUtils.writeToParcel(record.mClassName, parcel, flags);
1050        TextUtils.writeToParcel(record.mContentDescription, parcel, flags);
1051        TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
1052        parcel.writeParcelable(record.mParcelableData, flags);
1053        parcel.writeList(record.mText);
1054        parcel.writeInt(record.mSourceWindowId);
1055        parcel.writeLong(record.mSourceNodeId);
1056        parcel.writeInt(record.mSealed ? 1 : 0);
1057    }
1058
1059    /**
1060     * {@inheritDoc}
1061     */
1062    public int describeContents() {
1063        return 0;
1064    }
1065
1066    @Override
1067    public String toString() {
1068        StringBuilder builder = new StringBuilder();
1069        builder.append("EventType: ").append(eventTypeToString(mEventType));
1070        builder.append("; EventTime: ").append(mEventTime);
1071        builder.append("; PackageName: ").append(mPackageName);
1072        builder.append("; MovementGranularity: ").append(mMovementGranularity);
1073        builder.append("; Action: ").append(mAction);
1074        builder.append(super.toString());
1075        if (DEBUG) {
1076            builder.append("\n");
1077            builder.append("; sourceWindowId: ").append(mSourceWindowId);
1078            builder.append("; mSourceNodeId: ").append(mSourceNodeId);
1079            for (int i = 0; i < mRecords.size(); i++) {
1080                AccessibilityRecord record = mRecords.get(i);
1081                builder.append("  Record ");
1082                builder.append(i);
1083                builder.append(":");
1084                builder.append(" [ ClassName: " + record.mClassName);
1085                builder.append("; Text: " + record.mText);
1086                builder.append("; ContentDescription: " + record.mContentDescription);
1087                builder.append("; ItemCount: " + record.mItemCount);
1088                builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex);
1089                builder.append("; IsEnabled: " + record.isEnabled());
1090                builder.append("; IsPassword: " + record.isPassword());
1091                builder.append("; IsChecked: " + record.isChecked());
1092                builder.append("; IsFullScreen: " + record.isFullScreen());
1093                builder.append("; Scrollable: " + record.isScrollable());
1094                builder.append("; BeforeText: " + record.mBeforeText);
1095                builder.append("; FromIndex: " + record.mFromIndex);
1096                builder.append("; ToIndex: " + record.mToIndex);
1097                builder.append("; ScrollX: " + record.mScrollX);
1098                builder.append("; ScrollY: " + record.mScrollY);
1099                builder.append("; AddedCount: " + record.mAddedCount);
1100                builder.append("; RemovedCount: " + record.mRemovedCount);
1101                builder.append("; ParcelableData: " + record.mParcelableData);
1102                builder.append(" ]");
1103                builder.append("\n");
1104            }
1105        } else {
1106            builder.append("; recordCount: ").append(getRecordCount());
1107        }
1108        return builder.toString();
1109    }
1110
1111    /**
1112     * Returns the string representation of an event type. For example,
1113     * {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED.
1114     *
1115     * @param eventType The event type
1116     * @return The string representation.
1117     */
1118    public static String eventTypeToString(int eventType) {
1119        if (eventType == TYPES_ALL_MASK) {
1120            return "TYPES_ALL_MASK";
1121        }
1122        StringBuilder builder = new StringBuilder();
1123        int eventTypeCount = 0;
1124        while (eventType != 0) {
1125            final int eventTypeFlag = 1 << Integer.numberOfTrailingZeros(eventType);
1126            eventType &= ~eventTypeFlag;
1127            switch (eventTypeFlag) {
1128                case TYPE_VIEW_CLICKED: {
1129                    if (eventTypeCount > 0) {
1130                        builder.append(", ");
1131                    }
1132                    builder.append("TYPE_VIEW_CLICKED");
1133                    eventTypeCount++;
1134                } break;
1135                case TYPE_VIEW_LONG_CLICKED: {
1136                    if (eventTypeCount > 0) {
1137                        builder.append(", ");
1138                    }
1139                    builder.append("TYPE_VIEW_LONG_CLICKED");
1140                    eventTypeCount++;
1141                } break;
1142                case TYPE_VIEW_SELECTED: {
1143                    if (eventTypeCount > 0) {
1144                        builder.append(", ");
1145                    }
1146                    builder.append("TYPE_VIEW_SELECTED");
1147                    eventTypeCount++;
1148                } break;
1149                case TYPE_VIEW_FOCUSED: {
1150                    if (eventTypeCount > 0) {
1151                        builder.append(", ");
1152                    }
1153                    builder.append("TYPE_VIEW_FOCUSED");
1154                    eventTypeCount++;
1155                } break;
1156                case TYPE_VIEW_TEXT_CHANGED: {
1157                    if (eventTypeCount > 0) {
1158                        builder.append(", ");
1159                    }
1160                    builder.append("TYPE_VIEW_TEXT_CHANGED");
1161                    eventTypeCount++;
1162                } break;
1163                case TYPE_WINDOW_STATE_CHANGED: {
1164                    if (eventTypeCount > 0) {
1165                        builder.append(", ");
1166                    }
1167                    builder.append("TYPE_WINDOW_STATE_CHANGED");
1168                    eventTypeCount++;
1169                } break;
1170                case TYPE_VIEW_HOVER_ENTER: {
1171                    if (eventTypeCount > 0) {
1172                        builder.append(", ");
1173                    }
1174                    builder.append("TYPE_VIEW_HOVER_ENTER");
1175                    eventTypeCount++;
1176                } break;
1177                case TYPE_VIEW_HOVER_EXIT: {
1178                    if (eventTypeCount > 0) {
1179                        builder.append(", ");
1180                    }
1181                    builder.append("TYPE_VIEW_HOVER_EXIT");
1182                    eventTypeCount++;
1183                } break;
1184                case TYPE_NOTIFICATION_STATE_CHANGED: {
1185                    if (eventTypeCount > 0) {
1186                        builder.append(", ");
1187                    }
1188                    builder.append("TYPE_NOTIFICATION_STATE_CHANGED");
1189                    eventTypeCount++;
1190                } break;
1191                case TYPE_TOUCH_EXPLORATION_GESTURE_START: {
1192                    if (eventTypeCount > 0) {
1193                        builder.append(", ");
1194                    }
1195                    builder.append("TYPE_TOUCH_EXPLORATION_GESTURE_START");
1196                    eventTypeCount++;
1197                } break;
1198                case TYPE_TOUCH_EXPLORATION_GESTURE_END: {
1199                    if (eventTypeCount > 0) {
1200                        builder.append(", ");
1201                    }
1202                    builder.append("TYPE_TOUCH_EXPLORATION_GESTURE_END");
1203                    eventTypeCount++;
1204                } break;
1205                case TYPE_WINDOW_CONTENT_CHANGED: {
1206                    if (eventTypeCount > 0) {
1207                        builder.append(", ");
1208                    }
1209                    builder.append("TYPE_WINDOW_CONTENT_CHANGED");
1210                    eventTypeCount++;
1211                } break;
1212                case TYPE_VIEW_TEXT_SELECTION_CHANGED: {
1213                    if (eventTypeCount > 0) {
1214                        builder.append(", ");
1215                    }
1216                    builder.append("TYPE_VIEW_TEXT_SELECTION_CHANGED");
1217                    eventTypeCount++;
1218                } break;
1219                case TYPE_VIEW_SCROLLED: {
1220                    if (eventTypeCount > 0) {
1221                        builder.append(", ");
1222                    }
1223                    builder.append("TYPE_VIEW_SCROLLED");
1224                    eventTypeCount++;
1225                } break;
1226                case TYPE_ANNOUNCEMENT: {
1227                    if (eventTypeCount > 0) {
1228                        builder.append(", ");
1229                    }
1230                    builder.append("TYPE_ANNOUNCEMENT");
1231                    eventTypeCount++;
1232                } break;
1233                case TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
1234                    if (eventTypeCount > 0) {
1235                        builder.append(", ");
1236                    }
1237                    builder.append("TYPE_VIEW_ACCESSIBILITY_FOCUSED");
1238                    eventTypeCount++;
1239                } break;
1240                case TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
1241                    if (eventTypeCount > 0) {
1242                        builder.append(", ");
1243                    }
1244                    builder.append("TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED");
1245                    eventTypeCount++;
1246                } break;
1247                case TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: {
1248                    if (eventTypeCount > 0) {
1249                        builder.append(", ");
1250                    }
1251                    builder.append("TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY");
1252                    eventTypeCount++;
1253                } break;
1254                case TYPE_GESTURE_DETECTION_START: {
1255                    if (eventTypeCount > 0) {
1256                        builder.append(", ");
1257                    }
1258                    builder.append("TYPE_GESTURE_DETECTION_START");
1259                    eventTypeCount++;
1260                } break;
1261                case TYPE_GESTURE_DETECTION_END: {
1262                    if (eventTypeCount > 0) {
1263                        builder.append(", ");
1264                    }
1265                    builder.append("TYPE_GESTURE_DETECTION_END");
1266                    eventTypeCount++;
1267                } break;
1268                case TYPE_TOUCH_INTERACTION_START: {
1269                    if (eventTypeCount > 0) {
1270                        builder.append(", ");
1271                    }
1272                    builder.append("TYPE_TOUCH_INTERACTION_START");
1273                    eventTypeCount++;
1274                } break;
1275                case TYPE_TOUCH_INTERACTION_END: {
1276                    if (eventTypeCount > 0) {
1277                        builder.append(", ");
1278                    }
1279                    builder.append("TYPE_TOUCH_INTERACTION_END");
1280                    eventTypeCount++;
1281                } break;
1282            }
1283        }
1284        if (eventTypeCount > 1) {
1285            builder.insert(0, '[');
1286            builder.append(']');
1287        }
1288        return builder.toString();
1289    }
1290
1291    /**
1292     * @see Parcelable.Creator
1293     */
1294    public static final Parcelable.Creator<AccessibilityEvent> CREATOR =
1295            new Parcelable.Creator<AccessibilityEvent>() {
1296        public AccessibilityEvent createFromParcel(Parcel parcel) {
1297            AccessibilityEvent event = AccessibilityEvent.obtain();
1298            event.initFromParcel(parcel);
1299            return event;
1300        }
1301
1302        public AccessibilityEvent[] newArray(int size) {
1303            return new AccessibilityEvent[size];
1304        }
1305    };
1306}
1307