• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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 androidx.core.view;
18 
19 import android.os.Build;
20 import android.os.Bundle;
21 import android.view.View;
22 import android.view.View.AccessibilityDelegate;
23 import android.view.ViewGroup;
24 import android.view.accessibility.AccessibilityEvent;
25 import android.view.accessibility.AccessibilityNodeInfo;
26 import android.view.accessibility.AccessibilityNodeProvider;
27 
28 import androidx.annotation.RequiresApi;
29 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
30 import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
31 
32 /**
33  * Helper for accessing {@link AccessibilityDelegate}.
34  * <p>
35  * <strong>Note:</strong> On platform versions prior to
36  * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
37  * views in the {@code android.widget.*} package are called <i>before</i>
38  * host methods. This prevents certain properties such as class name from
39  * being modified by overriding
40  * {@link AccessibilityDelegateCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)},
41  * as any changes will be overwritten by the host class.
42  * <p>
43  * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
44  * methods are called <i>after</i> host methods, which all properties to be
45  * modified without being overwritten by the host class.
46  */
47 public class AccessibilityDelegateCompat {
48 
49     private static final class AccessibilityDelegateAdapter extends AccessibilityDelegate {
50         private final AccessibilityDelegateCompat mCompat;
51 
AccessibilityDelegateAdapter(AccessibilityDelegateCompat compat)52         AccessibilityDelegateAdapter(AccessibilityDelegateCompat compat) {
53             mCompat = compat;
54         }
55 
56         @Override
dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)57         public boolean dispatchPopulateAccessibilityEvent(View host,
58                 AccessibilityEvent event) {
59             return mCompat.dispatchPopulateAccessibilityEvent(host, event);
60         }
61 
62         @Override
onInitializeAccessibilityEvent(View host, AccessibilityEvent event)63         public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
64             mCompat.onInitializeAccessibilityEvent(host, event);
65         }
66 
67         @Override
onInitializeAccessibilityNodeInfo( View host, AccessibilityNodeInfo info)68         public void onInitializeAccessibilityNodeInfo(
69                 View host, AccessibilityNodeInfo info) {
70             mCompat.onInitializeAccessibilityNodeInfo(host,
71                     AccessibilityNodeInfoCompat.wrap(info));
72         }
73 
74         @Override
onPopulateAccessibilityEvent(View host, AccessibilityEvent event)75         public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
76             mCompat.onPopulateAccessibilityEvent(host, event);
77         }
78 
79         @Override
onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)80         public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
81                 AccessibilityEvent event) {
82             return mCompat.onRequestSendAccessibilityEvent(host, child, event);
83         }
84 
85         @Override
sendAccessibilityEvent(View host, int eventType)86         public void sendAccessibilityEvent(View host, int eventType) {
87             mCompat.sendAccessibilityEvent(host, eventType);
88         }
89 
90         @Override
sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)91         public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
92             mCompat.sendAccessibilityEventUnchecked(host, event);
93         }
94 
95         @Override
96         @RequiresApi(16)
getAccessibilityNodeProvider(View host)97         public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) {
98             AccessibilityNodeProviderCompat provider =
99                     mCompat.getAccessibilityNodeProvider(host);
100             return (provider != null)
101                     ? (AccessibilityNodeProvider) provider.getProvider() : null;
102         }
103 
104         @Override
performAccessibilityAction(View host, int action, Bundle args)105         public boolean performAccessibilityAction(View host, int action, Bundle args) {
106             return mCompat.performAccessibilityAction(host, action, args);
107         }
108     }
109 
110     private static final AccessibilityDelegate DEFAULT_DELEGATE = new AccessibilityDelegate();
111 
112     private final AccessibilityDelegate mBridge;
113 
114     /**
115      * Creates a new instance.
116      */
AccessibilityDelegateCompat()117     public AccessibilityDelegateCompat() {
118         mBridge = new AccessibilityDelegateAdapter(this);
119     }
120 
121     /**
122      * @return The wrapped bridge implementation.
123      */
getBridge()124     AccessibilityDelegate getBridge() {
125         return mBridge;
126     }
127 
128     /**
129      * Sends an accessibility event of the given type. If accessibility is not
130      * enabled this method has no effect.
131      * <p>
132      * The default implementation behaves as {@link View#sendAccessibilityEvent(int)
133      * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate
134      * been set.
135      * </p>
136      *
137      * @param host The View hosting the delegate.
138      * @param eventType The type of the event to send.
139      *
140      * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int)
141      */
sendAccessibilityEvent(View host, int eventType)142     public void sendAccessibilityEvent(View host, int eventType) {
143         DEFAULT_DELEGATE.sendAccessibilityEvent(host, eventType);
144     }
145 
146     /**
147      * Sends an accessibility event. This method behaves exactly as
148      * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an
149      * empty {@link AccessibilityEvent} and does not perform a check whether
150      * accessibility is enabled.
151      * <p>
152      * The default implementation behaves as
153      * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)
154      * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for
155      * the case of no accessibility delegate been set.
156      * </p>
157      *
158      * @param host The View hosting the delegate.
159      * @param event The event to send.
160      *
161      * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent)
162      *      View#sendAccessibilityEventUnchecked(AccessibilityEvent)
163      */
sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)164     public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) {
165         DEFAULT_DELEGATE.sendAccessibilityEventUnchecked(host, event);
166     }
167 
168     /**
169      * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then
170      * to its children for adding their text content to the event.
171      * <p>
172      * The default implementation behaves as
173      * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
174      * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for
175      * the case of no accessibility delegate been set.
176      * </p>
177      *
178      * @param host The View hosting the delegate.
179      * @param event The event.
180      * @return True if the event population was completed.
181      *
182      * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
183      *      View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
184      */
dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)185     public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
186         return DEFAULT_DELEGATE.dispatchPopulateAccessibilityEvent(host, event);
187     }
188 
189     /**
190      * Gives a chance to the host View to populate the accessibility event with its
191      * text content.
192      * <p>
193      * The default implementation behaves as
194      * {@link ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)
195      * ViewCompat#onPopulateAccessibilityEvent(AccessibilityEvent)} for
196      * the case of no accessibility delegate been set.
197      * </p>
198      *
199      * @param host The View hosting the delegate.
200      * @param event The accessibility event which to populate.
201      *
202      * @see ViewCompat#onPopulateAccessibilityEvent(View ,AccessibilityEvent)
203      *      ViewCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)
204      */
onPopulateAccessibilityEvent(View host, AccessibilityEvent event)205     public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
206         DEFAULT_DELEGATE.onPopulateAccessibilityEvent(host, event);
207     }
208 
209     /**
210      * Initializes an {@link AccessibilityEvent} with information about the
211      * the host View which is the event source.
212      * <p>
213      * The default implementation behaves as
214      * {@link ViewCompat#onInitializeAccessibilityEvent(View v, AccessibilityEvent event)
215      * ViewCompat#onInitalizeAccessibilityEvent(View v, AccessibilityEvent event)} for
216      * the case of no accessibility delegate been set.
217      * </p>
218      *
219      * @param host The View hosting the delegate.
220      * @param event The event to initialize.
221      *
222      * @see ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)
223      *      ViewCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)
224      */
onInitializeAccessibilityEvent(View host, AccessibilityEvent event)225     public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
226         DEFAULT_DELEGATE.onInitializeAccessibilityEvent(host, event);
227     }
228 
229     /**
230      * Initializes an {@link AccessibilityNodeInfoCompat} with information about the host view.
231      * <p>
232      * The default implementation behaves as
233      * {@link ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
234      * ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)} for
235      * the case of no accessibility delegate been set.
236      * </p>
237      *
238      * @param host The View hosting the delegate.
239      * @param info The instance to initialize.
240      *
241      * @see ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
242      *      ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)
243      */
onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info)244     public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
245         DEFAULT_DELEGATE.onInitializeAccessibilityNodeInfo(
246                 host, info.unwrap());
247     }
248 
249     /**
250      * Called when a child of the host View has requested sending an
251      * {@link AccessibilityEvent} and gives an opportunity to the parent (the host)
252      * to augment the event.
253      * <p>
254      * The default implementation behaves as
255      * {@link ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
256      * ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)} for
257      * the case of no accessibility delegate been set.
258      * </p>
259      *
260      * @param host The View hosting the delegate.
261      * @param child The child which requests sending the event.
262      * @param event The event to be sent.
263      * @return True if the event should be sent
264      *
265      * @see ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
266      *      ViewGroupCompat#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)
267      */
onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)268     public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
269             AccessibilityEvent event) {
270         return DEFAULT_DELEGATE.onRequestSendAccessibilityEvent(host, child, event);
271     }
272 
273     /**
274      * Gets the provider for managing a virtual view hierarchy rooted at this View
275      * and reported to {@link android.accessibilityservice.AccessibilityService}s
276      * that explore the window content.
277      * <p>
278      * The default implementation behaves as
279      * {@link ViewCompat#getAccessibilityNodeProvider(View) ViewCompat#getAccessibilityNodeProvider(View)}
280      * for the case of no accessibility delegate been set.
281      * </p>
282      *
283      * @return The provider.
284      *
285      * @see AccessibilityNodeProviderCompat
286      */
getAccessibilityNodeProvider(View host)287     public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
288         if (Build.VERSION.SDK_INT >= 16) {
289             Object provider = DEFAULT_DELEGATE.getAccessibilityNodeProvider(host);
290             if (provider != null) {
291                 return new AccessibilityNodeProviderCompat(provider);
292             }
293         }
294         return null;
295     }
296 
297     /**
298      * Performs the specified accessibility action on the view. For
299      * possible accessibility actions look at {@link AccessibilityNodeInfoCompat}.
300      * <p>
301      * The default implementation behaves as
302      * {@link View#performAccessibilityAction(int, Bundle)
303      *  View#performAccessibilityAction(int, Bundle)} for the case of
304      *  no accessibility delegate been set.
305      * </p>
306      *
307      * @param action The action to perform.
308      * @return Whether the action was performed.
309      *
310      * @see View#performAccessibilityAction(int, Bundle)
311      *      View#performAccessibilityAction(int, Bundle)
312      */
performAccessibilityAction(View host, int action, Bundle args)313     public boolean performAccessibilityAction(View host, int action, Bundle args) {
314         if (Build.VERSION.SDK_INT >= 16) {
315             return DEFAULT_DELEGATE.performAccessibilityAction(host, action, args);
316         }
317         return false;
318     }
319 }
320