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