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