AccessibilityEvent.java revision d9ee72fddb8be40e414a831fb80458dc48699613
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.text.TextUtils;
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 * <p>
64 * <b>VIEW TYPES</b></br>
65 * </p>
66 * <p>
67 * <b>View clicked</b> - represents the event of clicking on a {@link android.view.View}
68 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.</br>
69 * <em>Type:</em>{@link #TYPE_VIEW_CLICKED}</br>
70 * <em>Properties:</em></br>
71 * <ul>
72 *   <li>{@link #getEventType()} - The type of the event.</li>
73 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
74 *   <li>{@link #getClassName()} - The class name of the source.</li>
75 *   <li>{@link #getPackageName()} - The package name of the source.</li>
76 *   <li>{@link #getEventTime()}  - The event time.</li>
77 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
78 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
79 *   <li>{@link #isPassword()} - Whether the source is password.</li>
80 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
81 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
82 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
83 *       (without descendants of AdapterView).</li>
84 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
85 *       (without descendants of AdapterView).</li>
86 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
87 *       inclusive (for descendants of AdapterView).</li>
88 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
89 *       inclusive (for descendants of AdapterView).</li>
90 *   <li>{@link #getItemCount()} - The total items of the source
91 *       (for descendants of AdapterView).</li>
92 * </ul>
93 * </p>
94 * <p>
95 * <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View}
96 * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc </br>
97 * <em>Type:</em>{@link #TYPE_VIEW_LONG_CLICKED}</br>
98 * <em>Properties:</em></br>
99 * <ul>
100 *   <li>{@link #getEventType()} - The type of the event.</li>
101 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
102 *   <li>{@link #getClassName()} - The class name of the source.</li>
103 *   <li>{@link #getPackageName()} - The package name of the source.</li>
104 *   <li>{@link #getEventTime()}  - The event time.</li>
105 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
106 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
107 *   <li>{@link #isPassword()} - Whether the source is password.</li>
108 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
109 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
110 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
111 *       (without descendants of AdapterView).</li>
112 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
113 *       (without descendants of AdapterView).</li>
114 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
115 *       inclusive (for descendants of AdapterView).</li>
116 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
117 *       inclusive (for descendants of AdapterView).</li>
118 *   <li>{@link #getItemCount()} - The total items of the source
119 *       (for descendants of AdapterView).</li>
120 * </ul>
121 * </p>
122 * <p>
123 * <b>View selected</b> - represents the event of selecting an item usually in
124 * the context of an {@link android.widget.AdapterView}.</br>
125 * <em>Type:</em> {@link #TYPE_VIEW_SELECTED}</br>
126 * <em>Properties:</em></br>
127 * <ul>
128 *   <li>{@link #getEventType()} - The type of the event.</li>
129 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
130 *   <li>{@link #getClassName()} - The class name of the source.</li>
131 *   <li>{@link #getPackageName()} - The package name of the source.</li>
132 *   <li>{@link #getEventTime()}  - The event time.</li>
133 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
134 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
135 *   <li>{@link #isPassword()} - Whether the source is password.</li>
136 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
137 *   <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
138 *   <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
139 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
140 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
141 *       (without descendants of AdapterView).</li>
142 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
143 *       (without descendants of AdapterView).</li>
144 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
145 *       inclusive (for descendants of AdapterView).</li>
146 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
147 *       inclusive (for descendants of AdapterView).</li>
148 *   <li>{@link #getItemCount()} - The total items of the source
149 *       (for descendants of AdapterView).</li>
150 * </ul>
151 * </p>
152 * <p>
153 * <b>View focused</b> - represents the event of focusing a
154 * {@link android.view.View}.</br>
155 * <em>Type:</em> {@link #TYPE_VIEW_FOCUSED}</br>
156 * <em>Properties:</em></br>
157 * <ul>
158 *   <li>{@link #getEventType()} - The type of the event.</li>
159 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
160 *   <li>{@link #getClassName()} - The class name of the source.</li>
161 *   <li>{@link #getPackageName()} - The package name of the source.</li>
162 *   <li>{@link #getEventTime()}  - The event time.</li>
163 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
164 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
165 *   <li>{@link #isPassword()} - Whether the source is password.</li>
166 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
167 *   <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
168 *   <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
169 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
170 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
171 *       (without descendants of AdapterView).</li>
172 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
173 *       (without descendants of AdapterView).</li>
174 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
175 *       inclusive (for descendants of AdapterView).</li>
176 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
177 *       inclusive (for descendants of AdapterView).</li>
178 *   <li>{@link #getItemCount()} - The total items of the source
179 *       (for descendants of AdapterView).</li>
180 * </ul>
181 * </p>
182 * <p>
183 * <b>View text changed</b> - represents the event of changing the text of an
184 * {@link android.widget.EditText}.</br>
185 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_CHANGED}</br>
186 * <em>Properties:</em></br>
187 * <ul>
188 *   <li>{@link #getEventType()} - The type of the event.</li>
189 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
190 *   <li>{@link #getClassName()} - The class name of the source.</li>
191 *   <li>{@link #getPackageName()} - The package name of the source.</li>
192 *   <li>{@link #getEventTime()}  - The event time.</li>
193 *   <li>{@link #getText()} - The text of the source.</li>
194 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
195 *   <li>{@link #isPassword()} - Whether the source is password.</li>
196 *   <li>{@link #isChecked()} - Whether the source is checked.</li>
197 *   <li>{@link #getFromIndex()} - The text change start index.</li>
198 *   <li>{@link #getAddedCount()} - The number of added characters.</li>
199 *   <li>{@link #getRemovedCount()} - The number of removed characters.</li>
200 *   <li>{@link #getBeforeText()} - The text of the source before the change.</li>
201 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
202 * </ul>
203 * <em>Note:</em> This event type is not dispatched to descendants though
204 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
205 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
206 * source {@link android.view.View} and the sub-tree rooted at it will not receive
207 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
208 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
209 * text content to such events is by setting the
210 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
211 * view.</br>
212 * </p>
213 * <p>
214 * <b>View text selection changed</b> - represents the event of changing the text
215 * selection of an {@link android.widget.EditText}.</br>
216 * <em>Type:</em> {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} </br>
217 * <em>Properties:</em></br>
218 * <ul>
219 *   <li>{@link #getEventType()} - The type of the event.</li>
220 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
221 *   <li>{@link #getClassName()} - The class name of the source.</li>
222 *   <li>{@link #getPackageName()} - The package name of the source.</li>
223 *   <li>{@link #getEventTime()}  - The event time.</li>
224 *   <li>{@link #getText()} - The text of the source.</li>
225 *   <li>{@link #isPassword()} - Whether the source is password.</li>
226 *   <li>{@link #getFromIndex()} - The selection start index.</li>
227 *   <li>{@link #getToIndex()} - The selection end index.</li>
228 *   <li>{@link #getItemCount()} - The length of the source text.</li>
229 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
230 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
231 * </ul>
232 * <em>Note:</em> This event type is not dispatched to descendants though
233 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
234 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
235 * source {@link android.view.View} and the sub-tree rooted at it will not receive
236 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
237 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
238 * text content to such events is by setting the
239 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
240 * view.</br>
241 * </p>
242 * <p>
243 * <b>View scrolled</b> - represents the event of scrolling a view. If
244 * the source is a descendant of {@link android.widget.AdapterView} the
245 * scroll is reported in terms of visible items - the first visible item,
246 * the last visible item, and the total items - because the the source
247 * is unaware of its pixel size since its adapter is responsible for
248 * creating views. In all other cases the scroll is reported as the current
249 * scroll on the X and Y axis respectively plus the height of the source in
250 * pixels.</br>
251 * <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br>
252 * <em>Properties:</em></br>
253 * <ul>
254 *   <li>{@link #getEventType()} - The type of the event.</li>
255 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
256 *   <li>{@link #getClassName()} - The class name of the source.</li>
257 *   <li>{@link #getPackageName()} - The package name of the source.</li>
258 *   <li>{@link #getEventTime()}  - The event time.</li>
259 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
260 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
261 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
262 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
263 *       (without descendants of AdapterView).</li>
264 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
265 *       (without descendants of AdapterView).</li>
266 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
267 *       inclusive (for descendants of AdapterView).</li>
268 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
269 *       inclusive (for descendants of AdapterView).</li>
270 *   <li>{@link #getItemCount()} - The total items of the source
271 *       (for descendants of AdapterView).</li>
272 * </ul>
273 * <em>Note:</em> This event type is not dispatched to descendants though
274 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
275 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
276 * source {@link android.view.View} and the sub-tree rooted at it will not receive
277 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
278 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
279 * text content to such events is by setting the
280 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
281 * view.</br>
282 * </p>
283 * <p>
284 * <b>TRANSITION TYPES</b></br>
285 * </p>
286 * <p>
287 * <b>Window state changed</b> - represents the event of opening a
288 * {@link android.widget.PopupWindow}, {@link android.view.Menu},
289 * {@link android.app.Dialog}, etc.</br>
290 * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
291 * <em>Properties:</em></br>
292 * <ul>
293 *   <li>{@link #getEventType()} - The type of the event.</li>
294 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
295 *   <li>{@link #getClassName()} - The class name of the source.</li>
296 *   <li>{@link #getPackageName()} - The package name of the source.</li>
297 *   <li>{@link #getEventTime()}  - The event time.</li>
298 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
299 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
300 * </ul>
301 * </p>
302 * <p>
303 * <b>Window content changed</b> - represents the event of change in the
304 * content of a window. This change can be adding/removing view, changing
305 * a view size, etc.</br>
306 * </p>
307 * <p>
308 * <strong>Note:</strong> This event is fired only for the window source of the
309 * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED}
310 * and its purpose is to notify clients that the content of the user interaction
311 * window has changed.</br>
312 * <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br>
313 * <em>Properties:</em></br>
314 * <ul>
315 *   <li>{@link #getEventType()} - The type of the event.</li>
316 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
317 *   <li>{@link #getClassName()} - The class name of the source.</li>
318 *   <li>{@link #getPackageName()} - The package name of the source.</li>
319 *   <li>{@link #getEventTime()}  - The event time.</li>
320 * </ul>
321 * <em>Note:</em> This event type is not dispatched to descendants though
322 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
323 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
324 * source {@link android.view.View} and the sub-tree rooted at it will not receive
325 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
326 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
327 * text content to such events is by setting the
328 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
329 * view.</br>
330 * </p>
331 * <p>
332 * <b>NOTIFICATION TYPES</b></br>
333 * </p>
334 * <p>
335 * <b>Notification state changed</b> - represents the event showing
336 * {@link android.app.Notification}.</br>
337 * <em>Type:</em> {@link #TYPE_NOTIFICATION_STATE_CHANGED}</br>
338 * <em>Properties:</em></br>
339 * <ul>
340 *   <li>{@link #getEventType()} - The type of the event.</li>
341 *   <li>{@link #getClassName()} - The class name of the source.</li>
342 *   <li>{@link #getPackageName()} - The package name of the source.</li>
343 *   <li>{@link #getEventTime()}  - The event time.</li>
344 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
345 *   <li>{@link #getParcelableData()} - The posted {@link android.app.Notification}.</li>
346 *   <li>{@link #getText()} - Text for providing more context.</li>
347 * </ul>
348 * <em>Note:</em> This event type is not dispatched to descendants though
349 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
350 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
351 * source {@link android.view.View} and the sub-tree rooted at it will not receive
352 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
353 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
354 * text content to such events is by setting the
355 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
356 * view.</br>
357 * </p>
358 * <p>
359 * <b>EXPLORATION TYPES</b></br>
360 * </p>
361 * <p>
362 * <b>View hover enter</b> - represents the event of beginning to hover
363 * over a {@link android.view.View}. The hover may be generated via
364 * exploring the screen by touch or via a pointing device.</br>
365 * <em>Type:</em> {@link #TYPE_VIEW_HOVER_ENTER}</br>
366 * <em>Properties:</em></br>
367 * <ul>
368 *   <li>{@link #getEventType()} - The type of the event.</li>
369 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
370 *   <li>{@link #getClassName()} - The class name of the source.</li>
371 *   <li>{@link #getPackageName()} - The package name of the source.</li>
372 *   <li>{@link #getEventTime()}  - The event time.</li>
373 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
374 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
375 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
376 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
377 *       (without descendants of AdapterView).</li>
378 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
379 *       (without descendants of AdapterView).</li>
380 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
381 *       inclusive (for descendants of AdapterView).</li>
382 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
383 *       inclusive (for descendants of AdapterView).</li>
384 *   <li>{@link #getItemCount()} - The total items of the source
385 *       (for descendants of AdapterView).</li>
386 * </ul>
387 * </p>
388 * <b>View hover exit</b> - represents the event of stopping to hover
389 * over a {@link android.view.View}. The hover may be generated via
390 * exploring the screen by touch or via a pointing device.</br>
391 * <em>Type:</em> {@link #TYPE_VIEW_HOVER_EXIT}</br>
392 * <em>Properties:</em></br>
393 * <ul>
394 *   <li>{@link #getEventType()} - The type of the event.</li>
395 *   <li>{@link #getSource()} - The source info (for registered clients).</li>
396 *   <li>{@link #getClassName()} - The class name of the source.</li>
397 *   <li>{@link #getPackageName()} - The package name of the source.</li>
398 *   <li>{@link #getEventTime()}  - The event time.</li>
399 *   <li>{@link #getText()} - The text of the source's sub-tree.</li>
400 *   <li>{@link #isEnabled()} - Whether the source is enabled.</li>
401 *   <li>{@link #getContentDescription()} - The content description of the source.</li>
402 *   <li>{@link #getScrollX()} - The offset of the source left edge in pixels
403 *       (without descendants of AdapterView).</li>
404 *   <li>{@link #getScrollY()} - The offset of the source top edge in pixels
405 *       (without descendants of AdapterView).</li>
406 *   <li>{@link #getFromIndex()} - The zero based index of the first visible item of the source,
407 *       inclusive (for descendants of AdapterView).</li>
408 *   <li>{@link #getToIndex()} - The zero based index of the last visible item of the source,
409 *       inclusive (for descendants of AdapterView).</li>
410 *   <li>{@link #getItemCount()} - The total items of the source
411 *       (for descendants of AdapterView).</li>
412 * </ul>
413 * </p>
414 * <p>
415 * <b>Touch exploration gesture start</b> - represents the event of starting a touch
416 * exploring gesture.</br>
417 * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_START}</br>
418 * <em>Properties:</em></br>
419 * <ul>
420 *   <li>{@link #getEventType()} - The type of the event.</li>
421 * </ul>
422 * <em>Note:</em> This event type is not dispatched to descendants though
423 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
424 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
425 * source {@link android.view.View} and the sub-tree rooted at it will not receive
426 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
427 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
428 * text content to such events is by setting the
429 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
430 * view.</br>
431 * </p>
432 * <p>
433 * <b>Touch exploration gesture end</b> - represents the event of ending a touch
434 * exploring gesture.</br>
435 * <em>Type:</em> {@link #TYPE_TOUCH_EXPLORATION_GESTURE_END}</br>
436 * <em>Properties:</em></br>
437 * <ul>
438 *   <li>{@link #getEventType()} - The type of the event.</li>
439 * </ul>
440 * <em>Note:</em> This event type is not dispatched to descendants though
441 * {@link android.view.View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
442 * View.dispatchPopulateAccessibilityEvent(AccessibilityEvent)}, hence the event
443 * source {@link android.view.View} and the sub-tree rooted at it will not receive
444 * calls to {@link android.view.View#onPopulateAccessibilityEvent(AccessibilityEvent)
445 * View.onPopulateAccessibilityEvent(AccessibilityEvent)}. The preferred way to add
446 * text content to such events is by setting the
447 * {@link android.R.styleable#View_contentDescription contentDescription} of the source
448 * view.</br>
449 * </p>
450 * <p>
451 * <b>Security note</b>
452 * <p>
453 * Since an event contains the text of its source privacy can be compromised by leaking
454 * sensitive information such as passwords. To address this issue any event fired in response
455 * to manipulation of a PASSWORD field does NOT CONTAIN the text of the password.
456 * </p>
457 *
458 * @see android.view.accessibility.AccessibilityManager
459 * @see android.accessibilityservice.AccessibilityService
460 * @see AccessibilityNodeInfo
461 */
462public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
463    private static final boolean DEBUG = false;
464
465    /**
466     * Invalid selection/focus position.
467     *
468     * @see #getCurrentItemIndex()
469     */
470    public static final int INVALID_POSITION = -1;
471
472    /**
473     * Maximum length of the text fields.
474     *
475     * @see #getBeforeText()
476     * @see #getText()
477     * </br>
478     * Note: This constant is no longer needed since there
479     *       is no limit on the length of text that is contained
480     *       in an accessibility event anymore.
481     */
482    @Deprecated
483    public static final int MAX_TEXT_LENGTH = 500;
484
485    /**
486     * Represents the event of clicking on a {@link android.view.View} like
487     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
488     */
489    public static final int TYPE_VIEW_CLICKED = 0x00000001;
490
491    /**
492     * Represents the event of long clicking on a {@link android.view.View} like
493     * {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.
494     */
495    public static final int TYPE_VIEW_LONG_CLICKED = 0x00000002;
496
497    /**
498     * Represents the event of selecting an item usually in the context of an
499     * {@link android.widget.AdapterView}.
500     */
501    public static final int TYPE_VIEW_SELECTED = 0x00000004;
502
503    /**
504     * Represents the event of focusing a {@link android.view.View}.
505     */
506    public static final int TYPE_VIEW_FOCUSED = 0x00000008;
507
508    /**
509     * Represents the event of changing the text of an {@link android.widget.EditText}.
510     */
511    public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010;
512
513    /**
514     * Represents the event of opening a {@link android.widget.PopupWindow},
515     * {@link android.view.Menu}, {@link android.app.Dialog}, etc.
516     */
517    public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020;
518
519    /**
520     * Represents the event showing a {@link android.app.Notification}.
521     */
522    public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
523
524    /**
525     * Represents the event of a hover enter over a {@link android.view.View}.
526     */
527    public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080;
528
529    /**
530     * Represents the event of a hover exit over a {@link android.view.View}.
531     */
532    public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100;
533
534    /**
535     * Represents the event of starting a touch exploration gesture.
536     */
537    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200;
538
539    /**
540     * Represents the event of ending a touch exploration gesture.
541     */
542    public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400;
543
544    /**
545     * Represents the event of changing the content of a window.
546     */
547    public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800;
548
549    /**
550     * Represents the event of scrolling a view.
551     */
552    public static final int TYPE_VIEW_SCROLLED = 0x00001000;
553
554    /**
555     * Represents the event of changing the selection in an {@link android.widget.EditText}.
556     */
557    public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000;
558
559    /**
560     * Mask for {@link AccessibilityEvent} all types.
561     *
562     * @see #TYPE_VIEW_CLICKED
563     * @see #TYPE_VIEW_LONG_CLICKED
564     * @see #TYPE_VIEW_SELECTED
565     * @see #TYPE_VIEW_FOCUSED
566     * @see #TYPE_VIEW_TEXT_CHANGED
567     * @see #TYPE_WINDOW_STATE_CHANGED
568     * @see #TYPE_NOTIFICATION_STATE_CHANGED
569     * @see #TYPE_VIEW_HOVER_ENTER
570     * @see #TYPE_VIEW_HOVER_EXIT
571     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START
572     * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END
573     * @see #TYPE_WINDOW_CONTENT_CHANGED
574     * @see #TYPE_VIEW_SCROLLED
575     * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED
576     */
577    public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
578
579    private static final int MAX_POOL_SIZE = 10;
580    private static final Object sPoolLock = new Object();
581    private static AccessibilityEvent sPool;
582    private static int sPoolSize;
583    private AccessibilityEvent mNext;
584    private boolean mIsInPool;
585
586    private int mEventType;
587    private CharSequence mPackageName;
588    private long mEventTime;
589
590    private final ArrayList<AccessibilityRecord> mRecords = new ArrayList<AccessibilityRecord>();
591
592    /*
593     * Hide constructor from clients.
594     */
595    private AccessibilityEvent() {
596    }
597
598    /**
599     * Initialize an event from another one.
600     *
601     * @param event The event to initialize from.
602     */
603    void init(AccessibilityEvent event) {
604        super.init(event);
605        mEventType = event.mEventType;
606        mEventTime = event.mEventTime;
607        mPackageName = event.mPackageName;
608    }
609
610    /**
611     * Sets the connection for interacting with the AccessibilityManagerService.
612     *
613     * @param connection The connection.
614     *
615     * @hide
616     */
617    @Override
618    public void setConnection(IAccessibilityServiceConnection connection) {
619        super.setConnection(connection);
620        List<AccessibilityRecord> records = mRecords;
621        final int recordCount = records.size();
622        for (int i = 0; i < recordCount; i++) {
623            AccessibilityRecord record = records.get(i);
624            record.setConnection(connection);
625        }
626    }
627
628    /**
629     * Sets if this instance is sealed.
630     *
631     * @param sealed Whether is sealed.
632     *
633     * @hide
634     */
635    @Override
636    public void setSealed(boolean sealed) {
637        super.setSealed(sealed);
638        List<AccessibilityRecord> records = mRecords;
639        final int recordCount = records.size();
640        for (int i = 0; i < recordCount; i++) {
641            AccessibilityRecord record = records.get(i);
642            record.setSealed(sealed);
643        }
644    }
645
646    /**
647     * Gets the number of records contained in the event.
648     *
649     * @return The number of records.
650     */
651    public int getRecordCount() {
652        return mRecords.size();
653    }
654
655    /**
656     * Appends an {@link AccessibilityRecord} to the end of event records.
657     *
658     * @param record The record to append.
659     *
660     * @throws IllegalStateException If called from an AccessibilityService.
661     */
662    public void appendRecord(AccessibilityRecord record) {
663        enforceNotSealed();
664        mRecords.add(record);
665    }
666
667    /**
668     * Gets the record at a given index.
669     *
670     * @param index The index.
671     * @return The record at the specified index.
672     */
673    public AccessibilityRecord getRecord(int index) {
674        return mRecords.get(index);
675    }
676
677    /**
678     * Gets the event type.
679     *
680     * @return The event type.
681     */
682    public int getEventType() {
683        return mEventType;
684    }
685
686    /**
687     * Sets the event type.
688     *
689     * @param eventType The event type.
690     *
691     * @throws IllegalStateException If called from an AccessibilityService.
692     */
693    public void setEventType(int eventType) {
694        enforceNotSealed();
695        mEventType = eventType;
696    }
697
698    /**
699     * Gets the time in which this event was sent.
700     *
701     * @return The event time.
702     */
703    public long getEventTime() {
704        return mEventTime;
705    }
706
707    /**
708     * Sets the time in which this event was sent.
709     *
710     * @param eventTime The event time.
711     *
712     * @throws IllegalStateException If called from an AccessibilityService.
713     */
714    public void setEventTime(long eventTime) {
715        enforceNotSealed();
716        mEventTime = eventTime;
717    }
718
719    /**
720     * Gets the package name of the source.
721     *
722     * @return The package name.
723     */
724    public CharSequence getPackageName() {
725        return mPackageName;
726    }
727
728    /**
729     * Sets the package name of the source.
730     *
731     * @param packageName The package name.
732     *
733     * @throws IllegalStateException If called from an AccessibilityService.
734     */
735    public void setPackageName(CharSequence packageName) {
736        enforceNotSealed();
737        mPackageName = packageName;
738    }
739
740    /**
741     * Returns a cached instance if such is available or a new one is
742     * instantiated with its type property set.
743     *
744     * @param eventType The event type.
745     * @return An instance.
746     */
747    public static AccessibilityEvent obtain(int eventType) {
748        AccessibilityEvent event = AccessibilityEvent.obtain();
749        event.setEventType(eventType);
750        return event;
751    }
752
753    /**
754     * Returns a cached instance if such is available or a new one is
755     * created. The returned instance is initialized from the given
756     * <code>event</code>.
757     *
758     * @param event The other event.
759     * @return An instance.
760     */
761    public static AccessibilityEvent obtain(AccessibilityEvent event) {
762        AccessibilityEvent eventClone = AccessibilityEvent.obtain();
763        eventClone.init(event);
764
765        final int recordCount = event.mRecords.size();
766        for (int i = 0; i < recordCount; i++) {
767            AccessibilityRecord record = event.mRecords.get(i);
768            AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
769            eventClone.mRecords.add(recordClone);
770        }
771
772        return eventClone;
773    }
774
775    /**
776     * Returns a cached instance if such is available or a new one is
777     * instantiated.
778     *
779     * @return An instance.
780     */
781    public static AccessibilityEvent obtain() {
782        synchronized (sPoolLock) {
783            if (sPool != null) {
784                AccessibilityEvent event = sPool;
785                sPool = sPool.mNext;
786                sPoolSize--;
787                event.mNext = null;
788                event.mIsInPool = false;
789                return event;
790            }
791            return new AccessibilityEvent();
792        }
793    }
794
795    /**
796     * Recycles an instance back to be reused.
797     * <p>
798     *   <b>Note: You must not touch the object after calling this function.</b>
799     * </p>
800     *
801     * @throws IllegalStateException If the event is already recycled.
802     */
803    @Override
804    public void recycle() {
805        if (mIsInPool) {
806            throw new IllegalStateException("Event already recycled!");
807        }
808        clear();
809        synchronized (sPoolLock) {
810            if (sPoolSize <= MAX_POOL_SIZE) {
811                mNext = sPool;
812                sPool = this;
813                mIsInPool = true;
814                sPoolSize++;
815            }
816        }
817    }
818
819    /**
820     * Clears the state of this instance.
821     *
822     * @hide
823     */
824    @Override
825    protected void clear() {
826        super.clear();
827        mEventType = 0;
828        mPackageName = null;
829        mEventTime = 0;
830        while (!mRecords.isEmpty()) {
831            AccessibilityRecord record = mRecords.remove(0);
832            record.recycle();
833        }
834    }
835
836    /**
837     * Creates a new instance from a {@link Parcel}.
838     *
839     * @param parcel A parcel containing the state of a {@link AccessibilityEvent}.
840     */
841    public void initFromParcel(Parcel parcel) {
842        if (parcel.readInt() == 1) {
843            mConnection = IAccessibilityServiceConnection.Stub.asInterface(
844                    parcel.readStrongBinder());
845        }
846        setSealed(parcel.readInt() == 1);
847        mEventType = parcel.readInt();
848        mPackageName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
849        mEventTime = parcel.readLong();
850        readAccessibilityRecordFromParcel(this, parcel);
851
852        // Read the records.
853        final int recordCount = parcel.readInt();
854        for (int i = 0; i < recordCount; i++) {
855            AccessibilityRecord record = AccessibilityRecord.obtain();
856            // Do this to write the connection only once.
857            record.setConnection(mConnection);
858            readAccessibilityRecordFromParcel(record, parcel);
859            mRecords.add(record);
860        }
861    }
862
863    /**
864     * Reads an {@link AccessibilityRecord} from a parcel.
865     *
866     * @param record The record to initialize.
867     * @param parcel The parcel to read from.
868     */
869    private void readAccessibilityRecordFromParcel(AccessibilityRecord record,
870            Parcel parcel) {
871        record.mBooleanProperties = parcel.readInt();
872        record.mCurrentItemIndex = parcel.readInt();
873        record.mItemCount = parcel.readInt();
874        record.mFromIndex = parcel.readInt();
875        record.mToIndex = parcel.readInt();
876        record.mScrollX = parcel.readInt();
877        record.mScrollY =  parcel.readInt();
878        record.mMaxScrollX = parcel.readInt();
879        record.mMaxScrollY =  parcel.readInt();
880        record.mAddedCount = parcel.readInt();
881        record.mRemovedCount = parcel.readInt();
882        record.mClassName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
883        record.mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
884        record.mBeforeText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
885        record.mParcelableData = parcel.readParcelable(null);
886        parcel.readList(record.mText, null);
887        record.mSourceWindowId = parcel.readInt();
888        record.mSourceViewId = parcel.readInt();
889        record.mSealed = (parcel.readInt() == 1);
890    }
891
892    /**
893     * {@inheritDoc}
894     */
895    public void writeToParcel(Parcel parcel, int flags) {
896        if (mConnection == null) {
897            parcel.writeInt(0);
898        } else {
899            parcel.writeInt(1);
900            parcel.writeStrongBinder(mConnection.asBinder());
901        }
902        parcel.writeInt(isSealed() ? 1 : 0);
903        parcel.writeInt(mEventType);
904        TextUtils.writeToParcel(mPackageName, parcel, 0);
905        parcel.writeLong(mEventTime);
906        writeAccessibilityRecordToParcel(this, parcel, flags);
907
908        // Write the records.
909        final int recordCount = getRecordCount();
910        parcel.writeInt(recordCount);
911        for (int i = 0; i < recordCount; i++) {
912            AccessibilityRecord record = mRecords.get(i);
913            writeAccessibilityRecordToParcel(record, parcel, flags);
914        }
915    }
916
917    /**
918     * Writes an {@link AccessibilityRecord} to a parcel.
919     *
920     * @param record The record to write.
921     * @param parcel The parcel to which to write.
922     */
923    private void writeAccessibilityRecordToParcel(AccessibilityRecord record, Parcel parcel,
924            int flags) {
925        parcel.writeInt(record.mBooleanProperties);
926        parcel.writeInt(record.mCurrentItemIndex);
927        parcel.writeInt(record.mItemCount);
928        parcel.writeInt(record.mFromIndex);
929        parcel.writeInt(record.mToIndex);
930        parcel.writeInt(record.mScrollX);
931        parcel.writeInt(record.mScrollY);
932        parcel.writeInt(record.mMaxScrollX);
933        parcel.writeInt(record.mMaxScrollY);
934        parcel.writeInt(record.mAddedCount);
935        parcel.writeInt(record.mRemovedCount);
936        TextUtils.writeToParcel(record.mClassName, parcel, flags);
937        TextUtils.writeToParcel(record.mContentDescription, parcel, flags);
938        TextUtils.writeToParcel(record.mBeforeText, parcel, flags);
939        parcel.writeParcelable(record.mParcelableData, flags);
940        parcel.writeList(record.mText);
941        parcel.writeInt(record.mSourceWindowId);
942        parcel.writeInt(record.mSourceViewId);
943        parcel.writeInt(record.mSealed ? 1 : 0);
944    }
945
946    /**
947     * {@inheritDoc}
948     */
949    public int describeContents() {
950        return 0;
951    }
952
953    @Override
954    public String toString() {
955        StringBuilder builder = new StringBuilder();
956        builder.append("EventType: ").append(eventTypeToString(mEventType));
957        builder.append("; EventTime: ").append(mEventTime);
958        builder.append("; PackageName: ").append(mPackageName);
959        builder.append(super.toString());
960        if (DEBUG) {
961            builder.append("\n");
962            builder.append("; sourceWindowId: ").append(mSourceWindowId);
963            builder.append("; sourceViewId: ").append(mSourceViewId);
964            for (int i = 0; i < mRecords.size(); i++) {
965                AccessibilityRecord record = mRecords.get(i);
966                builder.append("  Record ");
967                builder.append(i);
968                builder.append(":");
969                builder.append(" [ ClassName: " + record.mClassName);
970                builder.append("; Text: " + record.mText);
971                builder.append("; ContentDescription: " + record.mContentDescription);
972                builder.append("; ItemCount: " + record.mItemCount);
973                builder.append("; CurrentItemIndex: " + record.mCurrentItemIndex);
974                builder.append("; IsEnabled: " + record.isEnabled());
975                builder.append("; IsPassword: " + record.isPassword());
976                builder.append("; IsChecked: " + record.isChecked());
977                builder.append("; IsFullScreen: " + record.isFullScreen());
978                builder.append("; Scrollable: " + record.isScrollable());
979                builder.append("; BeforeText: " + record.mBeforeText);
980                builder.append("; FromIndex: " + record.mFromIndex);
981                builder.append("; ToIndex: " + record.mToIndex);
982                builder.append("; ScrollX: " + record.mScrollX);
983                builder.append("; ScrollY: " + record.mScrollY);
984                builder.append("; AddedCount: " + record.mAddedCount);
985                builder.append("; RemovedCount: " + record.mRemovedCount);
986                builder.append("; ParcelableData: " + record.mParcelableData);
987                builder.append(" ]");
988                builder.append("\n");
989            }
990        } else {
991            builder.append("; recordCount: ").append(getRecordCount());
992        }
993        return builder.toString();
994    }
995
996    /**
997     * Returns the string representation of an event type. For example,
998     * {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED.
999     *
1000     * @param eventType The event type
1001     * @return The string representation.
1002     */
1003    public static String eventTypeToString(int eventType) {
1004        switch (eventType) {
1005            case TYPE_VIEW_CLICKED:
1006                return "TYPE_VIEW_CLICKED";
1007            case TYPE_VIEW_LONG_CLICKED:
1008                return "TYPE_VIEW_LONG_CLICKED";
1009            case TYPE_VIEW_SELECTED:
1010                return "TYPE_VIEW_SELECTED";
1011            case TYPE_VIEW_FOCUSED:
1012                return "TYPE_VIEW_FOCUSED";
1013            case TYPE_VIEW_TEXT_CHANGED:
1014                return "TYPE_VIEW_TEXT_CHANGED";
1015            case TYPE_WINDOW_STATE_CHANGED:
1016                return "TYPE_WINDOW_STATE_CHANGED";
1017            case TYPE_VIEW_HOVER_ENTER:
1018                return "TYPE_VIEW_HOVER_ENTER";
1019            case TYPE_VIEW_HOVER_EXIT:
1020                return "TYPE_VIEW_HOVER_EXIT";
1021            case TYPE_NOTIFICATION_STATE_CHANGED:
1022                return "TYPE_NOTIFICATION_STATE_CHANGED";
1023            case TYPE_TOUCH_EXPLORATION_GESTURE_START:
1024                return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
1025            case TYPE_TOUCH_EXPLORATION_GESTURE_END:
1026                return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
1027            case TYPE_WINDOW_CONTENT_CHANGED:
1028                return "TYPE_WINDOW_CONTENT_CHANGED";
1029            case TYPE_VIEW_TEXT_SELECTION_CHANGED:
1030                return "TYPE_VIEW_TEXT_SELECTION_CHANGED";
1031            case TYPE_VIEW_SCROLLED:
1032                return "TYPE_VIEW_SCROLLED";
1033            default:
1034                return null;
1035        }
1036    }
1037
1038    /**
1039     * @see Parcelable.Creator
1040     */
1041    public static final Parcelable.Creator<AccessibilityEvent> CREATOR =
1042            new Parcelable.Creator<AccessibilityEvent>() {
1043        public AccessibilityEvent createFromParcel(Parcel parcel) {
1044            AccessibilityEvent event = AccessibilityEvent.obtain();
1045            event.initFromParcel(parcel);
1046            return event;
1047        }
1048
1049        public AccessibilityEvent[] newArray(int size) {
1050            return new AccessibilityEvent[size];
1051        }
1052    };
1053}
1054