AccessibilityDelegateCompat.java revision f3ed7c56e6c409d27c60f7d74c026906593c21d4
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        if (Build.VERSION.SDK_INT >= 16) { // JellyBean
273            IMPL = new AccessibilityDelegateJellyBeanImpl();
274        } else if (Build.VERSION.SDK_INT >= 14) { // ICS
275            IMPL = new AccessibilityDelegateIcsImpl();
276        } else {
277            IMPL = new AccessibilityDelegateStubImpl();
278        }
279        DEFAULT_DELEGATE = IMPL.newAccessiblityDelegateDefaultImpl();
280    }
281
282    final Object mBridge;
283
284    /**
285     * Creates a new instance.
286     */
287    public AccessibilityDelegateCompat() {
288        mBridge = IMPL.newAccessiblityDelegateBridge(this);
289    }
290
291    /**
292     * @return The wrapped bridge implementation.
293     */
294    Object getBridge() {
295        return mBridge;
296    }
297
298    /**
299     * Sends an accessibility event of the given type. If accessibility is not
300     * enabled this method has no effect.
301     * <p>
302     * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
303     * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
304     * been set.
305     * </p>
306     *
307     * @param host The View hosting the delegate.
308     * @param eventType The type of the event to send.
309     *
310     * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
311     */
312    public void sendAccessibilityEvent(View host, int eventType) {
313        IMPL.sendAccessibilityEvent(DEFAULT_DELEGATE, host, eventType);
314    }
315
316    /**
317     * Sends an accessibility event. This method behaves exactly as
318     * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
319     * empty {@link AccessibilityEvent} and does not perform a check whether
320     * accessibility is enabled.
321     * <p>
322     * The default implementation behaves as
323     * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
324     * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
325     * the case of no accessibility delegate been set.
326     * </p>
327     *
328     * @param host The View hosting the delegate.
329     * @param event The event to send.
330     *
331     * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
332     *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
333     */
334    public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
335        IMPL.sendAccessibilityEventUnchecked(DEFAULT_DELEGATE, host, event);
336    }
337
338    /**
339     * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
340     * to its children for adding their text content to the event.
341     * <p>
342     * The default implementation behaves as
343     * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
344     * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
345     * the case of no accessibility delegate been set.
346     * </p>
347     *
348     * @param host The View hosting the delegate.
349     * @param event The event.
350     * @return True if the event population was completed.
351     *
352     * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
353     *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
354     */
355    public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
356        return IMPL.dispatchPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event);
357    }
358
359    /**
360     * Gives a chance to the host View to populate the accessibility event with its
361     * text content.
362     * <p>
363     * The default implementation behaves as
364     * {@link ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)
365     * ViewCompat#onPopulateAccessibilityEvent(AccessibilityEvent)} for
366     * the case of no accessibility delegate been set.
367     * </p>
368     *
369     * @param host The View hosting the delegate.
370     * @param event The accessibility event which to populate.
371     *
372     * @see ViewCompat#onPopulateAccessibilityEvent(View ,AccessibilityEvent)
373     *      ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)
374     */
375    public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
376        IMPL.onPopulateAccessibilityEvent(DEFAULT_DELEGATE, host, event);
377    }
378
379    /**
380     * Initializes an {@link AccessibilityEvent} with information about the
381     * the host View which is the event source.
382     * <p>
383     * The default implementation behaves as
384     * {@link ViewCompat#onInitializeAccessibilityEvent(View v, AccessibilityEvent event)
385     * ViewCompat#onInitalizeAccessibilityEvent(View v, AccessibilityEvent event)} for
386     * the case of no accessibility delegate been set.
387     * </p>
388     *
389     * @param host The View hosting the delegate.
390     * @param event The event to initialize.
391     *
392     * @see ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)
393     *      ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)
394     */
395    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
396        IMPL.onInitializeAccessibilityEvent(DEFAULT_DELEGATE, host, event);
397    }
398
399    /**
400     * Initializes an {@link AccessibilityNodeInfoCompat} with information about the host view.
401     * <p>
402     * The default implementation behaves as
403     * {@link ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
404     * ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)} for
405     * the case of no accessibility delegate been set.
406     * </p>
407     *
408     * @param host The View hosting the delegate.
409     * @param info The instance to initialize.
410     *
411     * @see ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
412     *      ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
413     */
414    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
415        IMPL.onInitializeAccessibilityNodeInfo(DEFAULT_DELEGATE, host, info);
416    }
417
418    /**
419     * Called when a child of the host View has requested sending an
420     * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
421     * to augment the event.
422     * <p>
423     * The default implementation behaves as
424     * {@link ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
425     * ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)} for
426     * the case of no accessibility delegate been set.
427     * </p>
428     *
429     * @param host The View hosting the delegate.
430     * @param child The child which requests sending the event.
431     * @param event The event to be sent.
432     * @return True if the event should be sent
433     *
434     * @see ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
435     *      ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
436     */
437    public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
438            AccessibilityEvent event) {
439        return IMPL.onRequestSendAccessibilityEvent(DEFAULT_DELEGATE, host, child, event);
440    }
441
442    /**
443     * Gets the provider for managing a virtual view hierarchy rooted at this View
444     * and reported to {@link android.accessibilityservice.AccessibilityService}s
445     * that explore the window content.
446     * <p>
447     * The default implementation behaves as
448     * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for
449     * the case of no accessibility delegate been set.
450     * </p>
451     *
452     * @return The provider.
453     *
454     * @see AccessibilityNodeProviderCompat
455     */
456    public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
457        return IMPL.getAccessibilityNodeProvider(DEFAULT_DELEGATE, host);
458    }
459}
460