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