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; 18 19 import android.os.Build; 20 import android.os.Bundle; 21 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 22 import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.view.accessibility.AccessibilityEvent; 26 27 /** 28 * Helper for accessing {@link View.AccessibilityDelegate} introduced after 29 * API level 4 in a backwards compatible fashion. 30 */ 31 public class AccessibilityDelegateCompat { 32 33 static interface AccessibilityDelegateImpl { newAccessiblityDelegateDefaultImpl()34 public Object newAccessiblityDelegateDefaultImpl(); newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener)35 public Object newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener); dispatchPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)36 public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host, 37 AccessibilityEvent event); onInitializeAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)38 public void onInitializeAccessibilityEvent(Object delegate, View host, 39 AccessibilityEvent event); onInitializeAccessibilityNodeInfo(Object delegate, View host, AccessibilityNodeInfoCompat info)40 public void onInitializeAccessibilityNodeInfo(Object delegate, View host, 41 AccessibilityNodeInfoCompat info); onPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)42 public void onPopulateAccessibilityEvent(Object delegate, View host, 43 AccessibilityEvent event); onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, AccessibilityEvent event)44 public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, 45 AccessibilityEvent event); sendAccessibilityEvent(Object delegate, View host, int eventType)46 public void sendAccessibilityEvent(Object delegate, View host, int eventType); sendAccessibilityEventUnchecked(Object delegate, View host, AccessibilityEvent event)47 public void sendAccessibilityEventUnchecked(Object delegate, View host, 48 AccessibilityEvent event); getAccessibilityNodeProvider(Object delegate, View host)49 public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate, 50 View host); performAccessibilityAction(Object delegate, View host, int action, Bundle args)51 public boolean performAccessibilityAction(Object delegate, View host, int action, 52 Bundle args); 53 } 54 55 static class AccessibilityDelegateStubImpl implements AccessibilityDelegateImpl { newAccessiblityDelegateDefaultImpl()56 public Object newAccessiblityDelegateDefaultImpl() { 57 return null; 58 } 59 60 @Override newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener)61 public Object newAccessiblityDelegateBridge(AccessibilityDelegateCompat listener) { 62 return null; 63 } 64 65 @Override dispatchPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)66 public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host, 67 AccessibilityEvent event) { 68 return false; 69 } 70 71 @Override onInitializeAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)72 public void onInitializeAccessibilityEvent(Object delegate, View host, 73 AccessibilityEvent event) { 74 75 } 76 77 @Override onInitializeAccessibilityNodeInfo(Object delegate, View host, AccessibilityNodeInfoCompat info)78 public void onInitializeAccessibilityNodeInfo(Object delegate, View host, 79 AccessibilityNodeInfoCompat info) { 80 81 } 82 83 @Override onPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)84 public void onPopulateAccessibilityEvent(Object delegate, View host, 85 AccessibilityEvent event) { 86 87 } 88 89 @Override onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, AccessibilityEvent event)90 public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, 91 AccessibilityEvent event) { 92 return true; 93 } 94 95 @Override sendAccessibilityEvent(Object delegate, View host, int eventType)96 public void sendAccessibilityEvent(Object delegate, View host, int eventType) { 97 98 } 99 100 @Override sendAccessibilityEventUnchecked(Object delegate, View host, AccessibilityEvent event)101 public void sendAccessibilityEventUnchecked(Object delegate, View host, 102 AccessibilityEvent event) { 103 104 } 105 106 @Override getAccessibilityNodeProvider(Object delegate, View host)107 public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate, 108 View host) { 109 return null; 110 } 111 112 @Override performAccessibilityAction(Object delegate, View host, int action, Bundle args)113 public boolean performAccessibilityAction(Object delegate, View host, int action, 114 Bundle args) { 115 return false; 116 } 117 } 118 119 static class AccessibilityDelegateIcsImpl extends AccessibilityDelegateStubImpl { 120 @Override newAccessiblityDelegateDefaultImpl()121 public Object newAccessiblityDelegateDefaultImpl() { 122 return AccessibilityDelegateCompatIcs.newAccessibilityDelegateDefaultImpl(); 123 } 124 125 @Override newAccessiblityDelegateBridge(final AccessibilityDelegateCompat compat)126 public Object newAccessiblityDelegateBridge(final AccessibilityDelegateCompat compat) { 127 return AccessibilityDelegateCompatIcs.newAccessibilityDelegateBridge( 128 new AccessibilityDelegateCompatIcs.AccessibilityDelegateBridge() { 129 @Override 130 public boolean dispatchPopulateAccessibilityEvent(View host, 131 AccessibilityEvent event) { 132 return compat.dispatchPopulateAccessibilityEvent(host, event); 133 } 134 135 @Override 136 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 137 compat.onInitializeAccessibilityEvent(host, event); 138 } 139 140 @Override 141 public void onInitializeAccessibilityNodeInfo(View host, Object info) { 142 compat.onInitializeAccessibilityNodeInfo(host, 143 new AccessibilityNodeInfoCompat(info)); 144 } 145 146 @Override 147 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 148 compat.onPopulateAccessibilityEvent(host, event); 149 } 150 151 @Override 152 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 153 AccessibilityEvent event) { 154 return compat.onRequestSendAccessibilityEvent(host, child, event); 155 } 156 157 @Override 158 public void sendAccessibilityEvent(View host, int eventType) { 159 compat.sendAccessibilityEvent(host, eventType); 160 } 161 162 @Override 163 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 164 compat.sendAccessibilityEventUnchecked(host, event); 165 } 166 }); 167 } 168 169 @Override dispatchPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)170 public boolean dispatchPopulateAccessibilityEvent(Object delegate, View host, 171 AccessibilityEvent event) { 172 return AccessibilityDelegateCompatIcs.dispatchPopulateAccessibilityEvent(delegate, 173 host, event); 174 } 175 176 @Override onInitializeAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)177 public void onInitializeAccessibilityEvent(Object delegate, View host, 178 AccessibilityEvent event) { 179 AccessibilityDelegateCompatIcs.onInitializeAccessibilityEvent(delegate, host, event); 180 } 181 182 @Override onInitializeAccessibilityNodeInfo(Object delegate, View host, AccessibilityNodeInfoCompat info)183 public void onInitializeAccessibilityNodeInfo(Object delegate, View host, 184 AccessibilityNodeInfoCompat info) { 185 AccessibilityDelegateCompatIcs.onInitializeAccessibilityNodeInfo(delegate, host, 186 info.getInfo()); 187 } 188 189 @Override onPopulateAccessibilityEvent(Object delegate, View host, AccessibilityEvent event)190 public void onPopulateAccessibilityEvent(Object delegate, View host, 191 AccessibilityEvent event) { 192 AccessibilityDelegateCompatIcs.onPopulateAccessibilityEvent(delegate, host, event); 193 } 194 195 @Override onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, AccessibilityEvent event)196 public boolean onRequestSendAccessibilityEvent(Object delegate, ViewGroup host, View child, 197 AccessibilityEvent event) { 198 return AccessibilityDelegateCompatIcs.onRequestSendAccessibilityEvent(delegate, host, 199 child, event); 200 } 201 202 @Override sendAccessibilityEvent(Object delegate, View host, int eventType)203 public void sendAccessibilityEvent(Object delegate, View host, int eventType) { 204 AccessibilityDelegateCompatIcs.sendAccessibilityEvent(delegate, host, eventType); 205 } 206 207 @Override sendAccessibilityEventUnchecked(Object delegate, View host, AccessibilityEvent event)208 public void sendAccessibilityEventUnchecked(Object delegate, View host, 209 AccessibilityEvent event) { 210 AccessibilityDelegateCompatIcs.sendAccessibilityEventUnchecked(delegate, host, event); 211 } 212 } 213 214 static class AccessibilityDelegateJellyBeanImpl extends AccessibilityDelegateIcsImpl { 215 @Override 216 public Object newAccessiblityDelegateBridge(final AccessibilityDelegateCompat compat) { 217 return AccessibilityDelegateCompatJellyBean.newAccessibilityDelegateBridge( 218 new AccessibilityDelegateCompatJellyBean 219 .AccessibilityDelegateBridgeJellyBean() { 220 @Override 221 public boolean dispatchPopulateAccessibilityEvent(View host, 222 AccessibilityEvent event) { 223 return compat.dispatchPopulateAccessibilityEvent(host, event); 224 } 225 226 @Override 227 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 228 compat.onInitializeAccessibilityEvent(host, event); 229 } 230 231 @Override 232 public void onInitializeAccessibilityNodeInfo(View host, Object info) { 233 compat.onInitializeAccessibilityNodeInfo(host, 234 new AccessibilityNodeInfoCompat(info)); 235 } 236 237 @Override 238 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 239 compat.onPopulateAccessibilityEvent(host, event); 240 } 241 242 @Override 243 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 244 AccessibilityEvent event) { 245 return compat.onRequestSendAccessibilityEvent(host, child, event); 246 } 247 248 @Override 249 public void sendAccessibilityEvent(View host, int eventType) { 250 compat.sendAccessibilityEvent(host, eventType); 251 } 252 253 @Override 254 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 255 compat.sendAccessibilityEventUnchecked(host, event); 256 } 257 258 @Override 259 public Object getAccessibilityNodeProvider(View host) { 260 AccessibilityNodeProviderCompat provider = 261 compat.getAccessibilityNodeProvider(host); 262 return (provider != null) ? provider.getProvider() : null; 263 } 264 265 @Override 266 public boolean performAccessibilityAction(View host, int action, Bundle args) { 267 return compat.performAccessibilityAction(host, action, args); 268 } 269 }); 270 } 271 272 @Override 273 public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(Object delegate, 274 View host) { 275 Object provider = AccessibilityDelegateCompatJellyBean.getAccessibilityNodeProvider( 276 delegate, host); 277 if (provider != null) { 278 return new AccessibilityNodeProviderCompat(provider); 279 } 280 return null; 281 } 282 283 @Override 284 public boolean performAccessibilityAction(Object delegate, View host, int action, 285 Bundle args) { 286 return AccessibilityDelegateCompatJellyBean.performAccessibilityAction(delegate, 287 host, action, args); 288 } 289 } 290 291 private static final AccessibilityDelegateImpl IMPL; 292 private static final Object DEFAULT_DELEGATE; 293 294 static { 295 if (Build.VERSION.SDK_INT >= 16) { // JellyBean 296 IMPL = new AccessibilityDelegateJellyBeanImpl(); 297 } else if (Build.VERSION.SDK_INT >= 14) { // ICS 298 IMPL = new AccessibilityDelegateIcsImpl(); 299 } else { 300 IMPL = new AccessibilityDelegateStubImpl(); 301 } 302 DEFAULT_DELEGATE = IMPL.newAccessiblityDelegateDefaultImpl(); 303 } 304 305 final Object mBridge; 306 307 /** 308 * Creates a new instance. 309 */ 310 public AccessibilityDelegateCompat() { 311 mBridge = IMPL.newAccessiblityDelegateBridge(this); 312 } 313 314 /** 315 * @return The wrapped bridge implementation. 316 */ 317 Object getBridge() { 318 return mBridge; 319 } 320 321 /** 322 * Sends an accessibility event of the given type. If accessibility is not 323 * enabled this method has no effect. 324 * <p> 325 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 326 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 327 * been set. 328 * </p> 329 * 330 * @param host The View hosting the delegate. 331 * @param eventType The type of the event to send. 332 * 333 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 334 */ 335 public void sendAccessibilityEvent(View host, int eventType) { 336 IMPL.sendAccessibilityEvent(DEFAULT_DELEGATE, host, eventType); 337 } 338 339 /** 340 * Sends an accessibility event. This method behaves exactly as 341 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 342 * empty {@link AccessibilityEvent} and does not perform a check whether 343 * accessibility is enabled. 344 * <p> 345 * The default implementation behaves as 346 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 347 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 348 * the case of no accessibility delegate been set. 349 * </p> 350 * 351 * @param host The View hosting the delegate. 352 * @param event The event to send. 353 * 354 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 355 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 356 */ 357 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 358 IMPL.sendAccessibilityEventUnchecked(DEFAULT_DELEGATE, host, event); 359 } 360 361 /** 362 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 363 * to its children for adding their text content to the event. 364 * <p> 365 * The default implementation behaves as 366 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 367 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 368 * the case of no accessibility delegate been set. 369 * </p> 370 * 371 * @param host The View hosting the delegate. 372 * @param event The event. 373 * @return True if the event population was completed. 374 * 375 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 376 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 377 */ 378 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 379 return IMPL.dispatchPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event); 380 } 381 382 /** 383 * Gives a chance to the host View to populate the accessibility event with its 384 * text content. 385 * <p> 386 * The default implementation behaves as 387 * {@link ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent) 388 * ViewCompat#onPopulateAccessibilityEvent(AccessibilityEvent)} for 389 * the case of no accessibility delegate been set. 390 * </p> 391 * 392 * @param host The View hosting the delegate. 393 * @param event The accessibility event which to populate. 394 * 395 * @see ViewCompat#onPopulateAccessibilityEvent(View ,AccessibilityEvent) 396 * ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent) 397 */ 398 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 399 IMPL.onPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event); 400 } 401 402 /** 403 * Initializes an {@link AccessibilityEvent} with information about the 404 * the host View which is the event source. 405 * <p> 406 * The default implementation behaves as 407 * {@link ViewCompat#onInitializeAccessibilityEvent(View v, AccessibilityEvent event) 408 * ViewCompat#onInitalizeAccessibilityEvent(View v, AccessibilityEvent event)} for 409 * the case of no accessibility delegate been set. 410 * </p> 411 * 412 * @param host The View hosting the delegate. 413 * @param event The event to initialize. 414 * 415 * @see ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent) 416 * ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent) 417 */ 418 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 419 IMPL.onInitializeAccessibilityEvent(DEFAULT_DELEGATE, host, event); 420 } 421 422 /** 423 * Initializes an {@link AccessibilityNodeInfoCompat} with information about the host view. 424 * <p> 425 * The default implementation behaves as 426 * {@link ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat) 427 * ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)} for 428 * the case of no accessibility delegate been set. 429 * </p> 430 * 431 * @param host The View hosting the delegate. 432 * @param info The instance to initialize. 433 * 434 * @see ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat) 435 * ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat) 436 */ 437 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { 438 IMPL.onInitializeAccessibilityNodeInfo(DEFAULT_DELEGATE, host, info); 439 } 440 441 /** 442 * Called when a child of the host View has requested sending an 443 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 444 * to augment the event. 445 * <p> 446 * The default implementation behaves as 447 * {@link ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent) 448 * ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)} for 449 * the case of no accessibility delegate been set. 450 * </p> 451 * 452 * @param host The View hosting the delegate. 453 * @param child The child which requests sending the event. 454 * @param event The event to be sent. 455 * @return True if the event should be sent 456 * 457 * @see ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent) 458 * ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent) 459 */ 460 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 461 AccessibilityEvent event) { 462 return IMPL.onRequestSendAccessibilityEvent(DEFAULT_DELEGATE, host, child, event); 463 } 464 465 /** 466 * Gets the provider for managing a virtual view hierarchy rooted at this View 467 * and reported to {@link android.accessibilityservice.AccessibilityService}s 468 * that explore the window content. 469 * <p> 470 * The default implementation behaves as 471 * {@link ViewCompat#getAccessibilityNodeProvider(View) ViewCompat#getAccessibilityNodeProvider(View)} 472 * for the case of no accessibility delegate been set. 473 * </p> 474 * 475 * @return The provider. 476 * 477 * @see AccessibilityNodeProviderCompat 478 */ 479 public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) { 480 return IMPL.getAccessibilityNodeProvider(DEFAULT_DELEGATE, host); 481 } 482 483 /** 484 * Performs the specified accessibility action on the view. For 485 * possible accessibility actions look at {@link AccessibilityNodeInfoCompat}. 486 * <p> 487 * The default implementation behaves as 488 * {@link View#performAccessibilityAction(int, Bundle) 489 * View#performAccessibilityAction(int, Bundle)} for the case of 490 * no accessibility delegate been set. 491 * </p> 492 * 493 * @param action The action to perform. 494 * @return Whether the action was performed. 495 * 496 * @see View#performAccessibilityAction(int, Bundle) 497 * View#performAccessibilityAction(int, Bundle) 498 */ 499 public boolean performAccessibilityAction(View host, int action, Bundle args) { 500 return IMPL.performAccessibilityAction(DEFAULT_DELEGATE, host, action, args); 501 } 502 } 503