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