1 /* 2 * Copyright (C) 2011 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 17 package android.support.v4.view.accessibility; 18 19 import android.os.Build; 20 import android.view.accessibility.AccessibilityEvent; 21 22 /** 23 * Helper for accessing features in {@link AccessibilityEvent} 24 * introduced after API level 4 in a backwards compatible fashion. 25 */ 26 public final class AccessibilityEventCompat { 27 28 static interface AccessibilityEventVersionImpl { getRecordCount(AccessibilityEvent event)29 int getRecordCount(AccessibilityEvent event); appendRecord(AccessibilityEvent event, Object record)30 void appendRecord(AccessibilityEvent event, Object record); getRecord(AccessibilityEvent event, int index)31 Object getRecord(AccessibilityEvent event, int index); setContentChangeTypes(AccessibilityEvent event, int types)32 void setContentChangeTypes(AccessibilityEvent event, int types); getContentChangeTypes(AccessibilityEvent event)33 int getContentChangeTypes(AccessibilityEvent event); setMovementGranularity(AccessibilityEvent event, int granularity)34 public void setMovementGranularity(AccessibilityEvent event, int granularity); getMovementGranularity(AccessibilityEvent event)35 public int getMovementGranularity(AccessibilityEvent event); setAction(AccessibilityEvent event, int action)36 public void setAction(AccessibilityEvent event, int action); getAction(AccessibilityEvent event)37 public int getAction(AccessibilityEvent event); 38 } 39 40 static class AccessibilityEventStubImpl implements AccessibilityEventVersionImpl { 41 42 @Override appendRecord(AccessibilityEvent event, Object record)43 public void appendRecord(AccessibilityEvent event, Object record) { 44 45 } 46 47 @Override getRecord(AccessibilityEvent event, int index)48 public Object getRecord(AccessibilityEvent event, int index) { 49 return null; 50 } 51 52 @Override setContentChangeTypes(AccessibilityEvent event, int types)53 public void setContentChangeTypes(AccessibilityEvent event, int types) { 54 55 } 56 57 @Override getRecordCount(AccessibilityEvent event)58 public int getRecordCount(AccessibilityEvent event) { 59 return 0; 60 } 61 62 @Override getContentChangeTypes(AccessibilityEvent event)63 public int getContentChangeTypes(AccessibilityEvent event) { 64 return 0; 65 } 66 67 @Override setMovementGranularity(AccessibilityEvent event, int granularity)68 public void setMovementGranularity(AccessibilityEvent event, int granularity) { 69 } 70 71 @Override getMovementGranularity(AccessibilityEvent event)72 public int getMovementGranularity(AccessibilityEvent event) { 73 return 0; 74 } 75 76 @Override setAction(AccessibilityEvent event, int action)77 public void setAction(AccessibilityEvent event, int action) { 78 } 79 80 @Override getAction(AccessibilityEvent event)81 public int getAction(AccessibilityEvent event) { 82 return 0; 83 } 84 } 85 86 static class AccessibilityEventIcsImpl extends AccessibilityEventStubImpl { 87 88 @Override appendRecord(AccessibilityEvent event, Object record)89 public void appendRecord(AccessibilityEvent event, Object record) { 90 AccessibilityEventCompatIcs.appendRecord(event, record); 91 } 92 93 @Override getRecord(AccessibilityEvent event, int index)94 public Object getRecord(AccessibilityEvent event, int index) { 95 return AccessibilityEventCompatIcs.getRecord(event, index); 96 } 97 98 @Override getRecordCount(AccessibilityEvent event)99 public int getRecordCount(AccessibilityEvent event) { 100 return AccessibilityEventCompatIcs.getRecordCount(event); 101 } 102 } 103 104 static class AccessibilityEventJellyBeanImpl extends AccessibilityEventIcsImpl { 105 @Override setMovementGranularity(AccessibilityEvent event, int granularity)106 public void setMovementGranularity(AccessibilityEvent event, int granularity) { 107 AccessibilityEventCompatJellyBean.setMovementGranularity(event, granularity); 108 } 109 110 @Override getMovementGranularity(AccessibilityEvent event)111 public int getMovementGranularity(AccessibilityEvent event) { 112 return AccessibilityEventCompatJellyBean.getMovementGranularity(event); 113 } 114 115 @Override setAction(AccessibilityEvent event, int action)116 public void setAction(AccessibilityEvent event, int action) { 117 AccessibilityEventCompatJellyBean.setAction(event, action); 118 } 119 120 @Override getAction(AccessibilityEvent event)121 public int getAction(AccessibilityEvent event) { 122 return AccessibilityEventCompatJellyBean.getAction(event); 123 } 124 } 125 126 static class AccessibilityEventKitKatImpl extends AccessibilityEventJellyBeanImpl { 127 128 @Override setContentChangeTypes(AccessibilityEvent event, int types)129 public void setContentChangeTypes(AccessibilityEvent event, int types) { 130 AccessibilityEventCompatKitKat.setContentChangeTypes(event, types); 131 } 132 133 @Override getContentChangeTypes(AccessibilityEvent event)134 public int getContentChangeTypes(AccessibilityEvent event) { 135 return AccessibilityEventCompatKitKat.getContentChangeTypes(event); 136 } 137 } 138 139 private final static AccessibilityEventVersionImpl IMPL; 140 141 static { 142 if (Build.VERSION.SDK_INT >= 19) { // KitKat 143 IMPL = new AccessibilityEventKitKatImpl(); 144 } else if (Build.VERSION.SDK_INT >= 16) { // Jellybean 145 IMPL = new AccessibilityEventJellyBeanImpl(); 146 } else if (Build.VERSION.SDK_INT >= 14) { // ICS 147 IMPL = new AccessibilityEventIcsImpl(); 148 } else { 149 IMPL = new AccessibilityEventStubImpl(); 150 } 151 } 152 153 /** 154 * Represents the event of a hover enter over a {@link android.view.View}. 155 */ 156 public static final int TYPE_VIEW_HOVER_ENTER = 0x00000080; 157 158 /** 159 * Represents the event of a hover exit over a {@link android.view.View}. 160 */ 161 public static final int TYPE_VIEW_HOVER_EXIT = 0x00000100; 162 163 /** 164 * Represents the event of starting a touch exploration gesture. 165 */ 166 public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 0x00000200; 167 168 /** 169 * Represents the event of ending a touch exploration gesture. 170 */ 171 public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 0x00000400; 172 173 /** 174 * Represents the event of changing the content of a window. 175 */ 176 public static final int TYPE_WINDOW_CONTENT_CHANGED = 0x00000800; 177 178 /** 179 * Represents the event of scrolling a view. 180 */ 181 public static final int TYPE_VIEW_SCROLLED = 0x00001000; 182 183 /** 184 * Represents the event of changing the selection in an {@link android.widget.EditText}. 185 */ 186 public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 0x00002000; 187 188 /** 189 * Represents the event of an application making an announcement. 190 */ 191 public static final int TYPE_ANNOUNCEMENT = 0x00004000; 192 193 /** 194 * Represents the event of gaining accessibility focus. 195 */ 196 public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 0x00008000; 197 198 /** 199 * Represents the event of clearing accessibility focus. 200 */ 201 public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 0x00010000; 202 203 /** 204 * Represents the event of traversing the text of a view at a given movement granularity. 205 */ 206 public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 0x00020000; 207 208 /** 209 * Represents the event of beginning gesture detection. 210 */ 211 public static final int TYPE_GESTURE_DETECTION_START = 0x00040000; 212 213 /** 214 * Represents the event of ending gesture detection. 215 */ 216 public static final int TYPE_GESTURE_DETECTION_END = 0x00080000; 217 218 /** 219 * Represents the event of the user starting to touch the screen. 220 */ 221 public static final int TYPE_TOUCH_INTERACTION_START = 0x00100000; 222 223 /** 224 * Represents the event of the user ending to touch the screen. 225 */ 226 public static final int TYPE_TOUCH_INTERACTION_END = 0x00200000; 227 228 /** 229 * Represents the event change in the windows shown on the screen. 230 */ 231 public static final int TYPE_WINDOWS_CHANGED = 0x00400000; 232 233 /** 234 * Represents the event of a context click on a {@link android.view.View}. 235 */ 236 public static final int TYPE_VIEW_CONTEXT_CLICKED = 0x00800000; 237 238 /** 239 * Represents the event of the assistant currently reading the users screen context. 240 */ 241 public static final int TYPE_ASSIST_READING_CONTEXT = 0x01000000; 242 243 /** 244 * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: 245 * The type of change is not defined. 246 */ 247 public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0x00000000; 248 249 /** 250 * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: 251 * A node in the subtree rooted at the source node was added or removed. 252 */ 253 public static final int CONTENT_CHANGE_TYPE_SUBTREE = 0x00000001; 254 255 /** 256 * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: 257 * The node's text changed. 258 */ 259 public static final int CONTENT_CHANGE_TYPE_TEXT = 0x00000002; 260 261 /** 262 * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: 263 * The node's content description changed. 264 */ 265 public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 0x00000004; 266 267 /** 268 * Mask for {@link AccessibilityEvent} all types. 269 * 270 * @see AccessibilityEvent#TYPE_VIEW_CLICKED 271 * @see AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 272 * @see AccessibilityEvent#TYPE_VIEW_SELECTED 273 * @see AccessibilityEvent#TYPE_VIEW_FOCUSED 274 * @see AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 275 * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 276 * @see AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 277 * @see #TYPE_VIEW_HOVER_ENTER 278 * @see #TYPE_VIEW_HOVER_EXIT 279 * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START 280 * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END 281 * @see #TYPE_WINDOW_CONTENT_CHANGED 282 * @see #TYPE_VIEW_SCROLLED 283 * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED 284 * @see #TYPE_ANNOUNCEMENT 285 * @see #TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 286 * @see #TYPE_GESTURE_DETECTION_START 287 * @see #TYPE_GESTURE_DETECTION_END 288 * @see #TYPE_TOUCH_INTERACTION_START 289 * @see #TYPE_TOUCH_INTERACTION_END 290 */ 291 public static final int TYPES_ALL_MASK = 0xFFFFFFFF; 292 293 /* 294 * Hide constructor from clients. 295 */ AccessibilityEventCompat()296 private AccessibilityEventCompat() { 297 298 } 299 300 /** 301 * Gets the number of records contained in the event. 302 * 303 * @return The number of records. 304 */ getRecordCount(AccessibilityEvent event)305 public static int getRecordCount(AccessibilityEvent event) { 306 return IMPL.getRecordCount(event); 307 } 308 309 /** 310 * Appends an {@link android.view.accessibility.AccessibilityRecord} to the end of 311 * event records. 312 * 313 * @param record The record to append. 314 * 315 * @throws IllegalStateException If called from an AccessibilityService. 316 */ appendRecord(AccessibilityEvent event, AccessibilityRecordCompat record)317 public static void appendRecord(AccessibilityEvent event, AccessibilityRecordCompat record) { 318 IMPL.appendRecord(event, record.getImpl()); 319 } 320 321 /** 322 * Gets the record at a given index. 323 * 324 * @param index The index. 325 * @return The record at the specified index. 326 */ getRecord(AccessibilityEvent event, int index)327 public static AccessibilityRecordCompat getRecord(AccessibilityEvent event, int index) { 328 return new AccessibilityRecordCompat(IMPL.getRecord(event, index)); 329 } 330 331 /** 332 * Creates an {@link AccessibilityRecordCompat} from an {@link AccessibilityEvent} 333 * that can be used to manipulate the event properties defined in 334 * {@link android.view.accessibility.AccessibilityRecord}. 335 * <p> 336 * <strong>Note:</strong> Do not call {@link AccessibilityRecordCompat#recycle()} on the 337 * returned {@link AccessibilityRecordCompat}. Call {@link AccessibilityEvent#recycle()} 338 * in case you want to recycle the event. 339 * </p> 340 * 341 * @param event The from which to create a record. 342 * @return An {@link AccessibilityRecordCompat}. 343 */ asRecord(AccessibilityEvent event)344 public static AccessibilityRecordCompat asRecord(AccessibilityEvent event) { 345 return new AccessibilityRecordCompat(event); 346 } 347 348 /** 349 * Sets the bit mask of node tree changes signaled by an 350 * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. 351 * 352 * @param changeTypes The bit mask of change types. 353 * @throws IllegalStateException If called from an AccessibilityService. 354 * @see #getContentChangeTypes(AccessibilityEvent) 355 */ setContentChangeTypes(AccessibilityEvent event, int changeTypes)356 public static void setContentChangeTypes(AccessibilityEvent event, int changeTypes) { 357 IMPL.setContentChangeTypes(event, changeTypes); 358 } 359 360 /** 361 * Gets the bit mask of change types signaled by an 362 * {@link #TYPE_WINDOW_CONTENT_CHANGED} event. A single event may represent 363 * multiple change types. 364 * 365 * @return The bit mask of change types. One or more of: 366 * <ul> 367 * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION} 368 * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE} 369 * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT} 370 * <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED} 371 * </ul> 372 */ getContentChangeTypes(AccessibilityEvent event)373 public static int getContentChangeTypes(AccessibilityEvent event) { 374 return IMPL.getContentChangeTypes(event); 375 } 376 377 /** 378 * Sets the movement granularity that was traversed. 379 * 380 * @param granularity The granularity. 381 * 382 * @throws IllegalStateException If called from an AccessibilityService. 383 */ setMovementGranularity(AccessibilityEvent event, int granularity)384 public void setMovementGranularity(AccessibilityEvent event, int granularity) { 385 IMPL.setMovementGranularity(event, granularity); 386 } 387 388 /** 389 * Gets the movement granularity that was traversed. 390 * 391 * @return The granularity. 392 */ getMovementGranularity(AccessibilityEvent event)393 public int getMovementGranularity(AccessibilityEvent event) { 394 return IMPL.getMovementGranularity(event); 395 } 396 397 /** 398 * Sets the performed action that triggered this event. 399 * <p> 400 * Valid actions are defined in {@link AccessibilityNodeInfoCompat}: 401 * <ul> 402 * <li>{@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS} 403 * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS} 404 * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_FOCUS} 405 * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLEAR_SELECTION} 406 * <li>{@link AccessibilityNodeInfoCompat#ACTION_CLICK} 407 * <li>etc. 408 * </ul> 409 * 410 * @param action The action. 411 * @throws IllegalStateException If called from an AccessibilityService. 412 * @see AccessibilityNodeInfoCompat#performAction(int) 413 */ setAction(AccessibilityEvent event, int action)414 public void setAction(AccessibilityEvent event, int action) { 415 IMPL.setAction(event, action); 416 } 417 418 /** 419 * Gets the performed action that triggered this event. 420 * 421 * @return The action. 422 */ getAction(AccessibilityEvent event)423 public int getAction(AccessibilityEvent event) { 424 return IMPL.getAction(event); 425 } 426 } 427