ViewCompat.java revision 0574ca37da4619afe4e26753f5a1b4de314b6565
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.graphics.Rect;
20import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
21import android.view.View;
22import android.view.accessibility.AccessibilityEvent;
23
24/**
25 * Helper for accessing features in {@link View} introduced after API
26 * level 4 in a backwards compatible fashion.
27 */
28public class ViewCompat {
29    /**
30     * Always allow a user to over-scroll this view, provided it is a
31     * view that can scroll.
32     */
33    public static final int OVER_SCROLL_ALWAYS = 0;
34
35    /**
36     * Allow a user to over-scroll this view only if the content is large
37     * enough to meaningfully scroll, provided it is a view that can scroll.
38     */
39    public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;
40
41    /**
42     * Never allow a user to over-scroll this view.
43     */
44    public static final int OVER_SCROLL_NEVER = 2;
45
46    interface ViewCompatImpl {
47        public boolean canScrollHorizontally(View v, int direction);
48        public boolean canScrollVertically(View v, int direction);
49        public int getOverScrollMode(View v);
50        public void setOverScrollMode(View v, int mode);
51        public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event);
52        public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event);
53        public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info);
54        public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate);
55    }
56
57    static class BaseViewCompatImpl implements ViewCompatImpl {
58        public boolean canScrollHorizontally(View v, int direction) {
59            return false;
60        }
61        public boolean canScrollVertically(View v, int direction) {
62            return false;
63        }
64        public int getOverScrollMode(View v) {
65            return OVER_SCROLL_NEVER;
66        }
67        public void setOverScrollMode(View v, int mode) {
68            // Do nothing; API doesn't exist
69        }
70        public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
71            // Do nothing; API doesn't exist
72        }
73        public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
74            // Do nothing; API doesn't exist
75        }
76        public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
77         // Do nothing; API doesn't exist
78        }
79        public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
80            // Do nothing; API doesn't exist
81        }
82    }
83
84    static class GBViewCompatImpl extends BaseViewCompatImpl {
85        @Override
86        public int getOverScrollMode(View v) {
87            return ViewCompatGingerbread.getOverScrollMode(v);
88        }
89        @Override
90        public void setOverScrollMode(View v, int mode) {
91            ViewCompatGingerbread.setOverScrollMode(v, mode);
92        }
93    }
94
95    static class ICSViewCompatImpl extends GBViewCompatImpl {
96        @Override
97        public boolean canScrollHorizontally(View v, int direction) {
98            return ViewCompatICS.canScrollHorizontally(v, direction);
99        }
100        @Override
101        public boolean canScrollVertically(View v, int direction) {
102            return ViewCompatICS.canScrollVertically(v, direction);
103        }
104        @Override
105        public void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
106            ViewCompatICS.onPopulateAccessibilityEvent(v, event);
107        }
108        @Override
109        public void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
110            ViewCompatICS.onInitializeAccessibilityEvent(v, event);
111        }
112        @Override
113        public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
114            ViewCompatICS.onInitializeAccessibilityNodeInfo(v, info.getImpl());
115        }
116        @Override
117        public void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
118            ViewCompatICS.setAccessibilityDelegate(v, delegate.getBridge());
119        }
120    }
121
122    static final ViewCompatImpl IMPL;
123    static {
124        final int version = android.os.Build.VERSION.SDK_INT;
125        if (version >= 14) {
126            IMPL = new ICSViewCompatImpl();
127        } else if (version >= 9) {
128            IMPL = new GBViewCompatImpl();
129        } else {
130            IMPL = new BaseViewCompatImpl();
131        }
132    }
133
134    /**
135     * Check if this view can be scrolled horizontally in a certain direction.
136     *
137     * @param v The View against which to invoke the method.
138     * @param direction Negative to check scrolling left, positive to check scrolling right.
139     * @return true if this view can be scrolled in the specified direction, false otherwise.
140     */
141    public static boolean canScrollHorizontally(View v, int direction) {
142        return IMPL.canScrollHorizontally(v, direction);
143    }
144
145    /**
146     * Check if this view can be scrolled vertically in a certain direction.
147     *
148     * @param v The View against which to invoke the method.
149     * @param direction Negative to check scrolling up, positive to check scrolling down.
150     * @return true if this view can be scrolled in the specified direction, false otherwise.
151     */
152    public static boolean canScrollVertically(View v, int direction) {
153        return IMPL.canScrollVertically(v, direction);
154    }
155
156    /**
157     * Returns the over-scroll mode for this view. The result will be
158     * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
159     * (allow over-scrolling only if the view content is larger than the container),
160     * or {@link #OVER_SCROLL_NEVER}.
161     *
162     * @param v The View against which to invoke the method.
163     * @return This view's over-scroll mode.
164     */
165    public static int getOverScrollMode(View v) {
166        return IMPL.getOverScrollMode(v);
167    }
168
169    /**
170     * Set the over-scroll mode for this view. Valid over-scroll modes are
171     * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
172     * (allow over-scrolling only if the view content is larger than the container),
173     * or {@link #OVER_SCROLL_NEVER}.
174     *
175     * Setting the over-scroll mode of a view will have an effect only if the
176     * view is capable of scrolling.
177     *
178     * @param v The View against which to invoke the method.
179     * @param overScrollMode The new over-scroll mode for this view.
180     */
181    public static void setOverScrollMode(View v, int overScrollMode) {
182        IMPL.setOverScrollMode(v, overScrollMode);
183    }
184
185    /**
186     * Called from {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
187     * giving a chance to this View to populate the accessibility event with its
188     * text content. While this method is free to modify event
189     * attributes other than text content, doing so should normally be performed in
190     * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)}.
191     * <p>
192     * Example: Adding formatted date string to an accessibility event in addition
193     *          to the text added by the super implementation:
194     * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
195     *     super.onPopulateAccessibilityEvent(event);
196     *     final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
197     *     String selectedDateUtterance = DateUtils.formatDateTime(mContext,
198     *         mCurrentDate.getTimeInMillis(), flags);
199     *     event.getText().add(selectedDateUtterance);
200     * }</pre>
201     * <p>
202     * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
203     * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
204     * {@link android.view.View.AccessibilityDelegate#onPopulateAccessibilityEvent(View,
205     *  AccessibilityEvent)}
206     * is responsible for handling this call.
207     * </p>
208     * <p class="note"><strong>Note:</strong> Always call the super implementation before adding
209     * information to the event, in case the default implementation has basic information to add.
210     * </p>
211     *
212     * @param v The View against which to invoke the method.
213     * @param event The accessibility event which to populate.
214     *
215     * @see View#sendAccessibilityEvent(int)
216     * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
217     */
218    public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
219        IMPL.onPopulateAccessibilityEvent(v, event);
220    }
221
222    /**
223     * Initializes an {@link AccessibilityEvent} with information about
224     * this View which is the event source. In other words, the source of
225     * an accessibility event is the view whose state change triggered firing
226     * the event.
227     * <p>
228     * Example: Setting the password property of an event in addition
229     *          to properties set by the super implementation:
230     * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
231     *     super.onInitializeAccessibilityEvent(event);
232     *     event.setPassword(true);
233     * }</pre>
234     * <p>
235     * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
236     * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
237     * {@link android.view.View.AccessibilityDelegate#onInitializeAccessibilityEvent(View,
238     *  AccessibilityEvent)}
239     * is responsible for handling this call.
240     * </p>
241     * <p class="note"><strong>Note:</strong> Always call the super implementation before adding
242     * information to the event, in case the default implementation has basic information to add.
243     * </p>
244     *
245     * @param v The View against which to invoke the method.
246     * @param event The event to initialize.
247     *
248     * @see View#sendAccessibilityEvent(int)
249     * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
250     */
251    public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
252        IMPL.onInitializeAccessibilityEvent(v, event);
253    }
254
255    /**
256     * Initializes an {@link android.view.accessibility.AccessibilityNodeInfo} with information
257     * about this view. The base implementation sets:
258     * <ul>
259     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setParent(View)},</li>
260     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setBoundsInParent(Rect)},</li>
261     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li>
262     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setPackageName(CharSequence)},</li>
263     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setClassName(CharSequence)},</li>
264     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setContentDescription(CharSequence)},</li>
265     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setEnabled(boolean)},</li>
266     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setClickable(boolean)},</li>
267     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setFocusable(boolean)},</li>
268     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setFocused(boolean)},</li>
269     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setLongClickable(boolean)},</li>
270     * <li>{@link android.view.accessibility.AccessibilityNodeInfo#setSelected(boolean)},</li>
271     * </ul>
272     * <p>
273     * Subclasses should override this method, call the super implementation,
274     * and set additional attributes.
275     * </p>
276     * <p>
277     * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
278     * {@link View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
279     * {@link android.view.View.AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View,
280     *  android.view.accessibility.AccessibilityNodeInfo)}
281     * is responsible for handling this call.
282     * </p>
283     *
284     * @param v The View against which to invoke the method.
285     * @param info The instance to initialize.
286     */
287    public static void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfoCompat info) {
288        IMPL.onInitializeAccessibilityNodeInfo(v, info);
289    }
290
291    /**
292     * Sets a delegate for implementing accessibility support via compositon as
293     * opposed to inheritance. The delegate's primary use is for implementing
294     * backwards compatible widgets. For more details see
295     * {@link android.view.View.AccessibilityDelegate}.
296     *
297     * @param v The View against which to invoke the method.
298     * @param delegate The delegate instance.
299     *
300     * @see android.view.View.AccessibilityDelegate
301     */
302    public static void setAccessibilityDelegate(View v, AccessibilityDelegateCompat delegate) {
303        IMPL.setAccessibilityDelegate(v, delegate);
304    }
305}
306