1/*
2 * Copyright (C) 2015 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.widget;
18
19import android.graphics.drawable.Drawable;
20import android.os.Build;
21import android.support.annotation.DrawableRes;
22import android.support.annotation.IdRes;
23import android.support.annotation.NonNull;
24import android.support.annotation.Nullable;
25import android.support.annotation.StyleRes;
26import android.widget.TextView;
27
28/**
29 * Helper for accessing features in {@link TextView} introduced after API level
30 * 4 in a backwards compatible fashion.
31 */
32public final class TextViewCompat {
33
34    // Hide constructor
35    private TextViewCompat() {}
36
37    interface TextViewCompatImpl {
38        void setCompoundDrawablesRelative(@NonNull TextView textView,
39                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
40                @Nullable Drawable bottom);
41        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
42                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
43                @Nullable Drawable bottom);
44        void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
45                @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
46                @DrawableRes int bottom);
47        int getMaxLines(TextView textView);
48        int getMinLines(TextView textView);
49        void setTextAppearance(@NonNull TextView textView, @StyleRes int resId);
50    }
51
52    static class BaseTextViewCompatImpl implements TextViewCompatImpl {
53        @Override
54        public void setCompoundDrawablesRelative(@NonNull TextView textView,
55                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
56                @Nullable Drawable bottom) {
57            textView.setCompoundDrawables(start, top, end, bottom);
58        }
59
60        @Override
61        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
62                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
63                @Nullable Drawable bottom) {
64            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
65        }
66
67        @Override
68        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
69                @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
70                @DrawableRes int bottom) {
71            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
72        }
73
74        @Override
75        public int getMaxLines(TextView textView) {
76            return TextViewCompatDonut.getMaxLines(textView);
77        }
78
79        @Override
80        public int getMinLines(TextView textView) {
81            return TextViewCompatDonut.getMinLines(textView);
82        }
83
84        @Override
85        public void setTextAppearance(TextView textView, @StyleRes int resId) {
86            TextViewCompatDonut.setTextAppearance(textView, resId);
87        }
88    }
89
90    static class JbTextViewCompatImpl extends BaseTextViewCompatImpl {
91        @Override
92        public int getMaxLines(TextView textView) {
93            return TextViewCompatJb.getMaxLines(textView);
94        }
95
96        @Override
97        public int getMinLines(TextView textView) {
98            return TextViewCompatJb.getMinLines(textView);
99        }
100    }
101
102    static class JbMr1TextViewCompatImpl extends JbTextViewCompatImpl {
103        @Override
104        public void setCompoundDrawablesRelative(@NonNull TextView textView,
105                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
106                @Nullable Drawable bottom) {
107            TextViewCompatJbMr1.setCompoundDrawablesRelative(textView, start, top, end, bottom);
108        }
109
110        @Override
111        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
112                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
113                @Nullable Drawable bottom) {
114            TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
115                    start, top, end, bottom);
116        }
117
118        @Override
119        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
120                @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
121                @DrawableRes int bottom) {
122            TextViewCompatJbMr1.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
123                    start, top, end, bottom);
124        }
125    }
126
127    static class JbMr2TextViewCompatImpl extends JbMr1TextViewCompatImpl {
128        @Override
129        public void setCompoundDrawablesRelative(@NonNull TextView textView,
130                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
131                @Nullable Drawable bottom) {
132            TextViewCompatJbMr2.setCompoundDrawablesRelative(textView, start, top, end, bottom);
133        }
134
135        @Override
136        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
137                @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
138                @Nullable Drawable bottom) {
139            TextViewCompatJbMr2
140                    .setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end,
141                            bottom);
142        }
143
144        @Override
145        public void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
146                @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
147                @DrawableRes int bottom) {
148            TextViewCompatJbMr2.setCompoundDrawablesRelativeWithIntrinsicBounds(textView,
149                    start, top, end, bottom);
150        }
151    }
152
153    static class Api23TextViewCompatImpl extends JbMr2TextViewCompatImpl {
154        @Override
155        public void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
156            TextViewCompatApi23.setTextAppearance(textView, resId);
157        }
158    }
159
160    static final TextViewCompatImpl IMPL;
161
162    static {
163        final int version = Build.VERSION.SDK_INT;
164        if (version >= 23) {
165            IMPL = new Api23TextViewCompatImpl();
166        } else if (version >= 18) {
167            IMPL = new JbMr2TextViewCompatImpl();
168        } else if (version >= 17) {
169            IMPL = new JbMr1TextViewCompatImpl();
170        } else if (version >= 16) {
171            IMPL = new JbTextViewCompatImpl();
172        } else {
173            IMPL = new BaseTextViewCompatImpl();
174        }
175    }
176
177    /**
178     * Sets the Drawables (if any) to appear to the start of, above, to the end
179     * of, and below the text. Use {@code null} if you do not want a Drawable
180     * there. The Drawables must already have had {@link Drawable#setBounds}
181     * called.
182     * <p/>
183     * Calling this method will overwrite any Drawables previously set using
184     * {@link TextView#setCompoundDrawables} or related methods.
185     *
186     * @param textView The TextView against which to invoke the method.
187     * @attr name android:drawableStart
188     * @attr name android:drawableTop
189     * @attr name android:drawableEnd
190     * @attr name android:drawableBottom
191     */
192    public static void setCompoundDrawablesRelative(@NonNull TextView textView,
193            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
194            @Nullable Drawable bottom) {
195        IMPL.setCompoundDrawablesRelative(textView, start, top, end, bottom);
196    }
197
198    /**
199     * Sets the Drawables (if any) to appear to the start of, above, to the end
200     * of, and below the text. Use {@code null} if you do not want a Drawable
201     * there. The Drawables' bounds will be set to their intrinsic bounds.
202     * <p/>
203     * Calling this method will overwrite any Drawables previously set using
204     * {@link TextView#setCompoundDrawables} or related methods.
205     *
206     * @param textView The TextView against which to invoke the method.
207     * @attr name android:drawableStart
208     * @attr name android:drawableTop
209     * @attr name android:drawableEnd
210     * @attr name android:drawableBottom
211     */
212    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
213            @Nullable Drawable start, @Nullable Drawable top, @Nullable Drawable end,
214            @Nullable Drawable bottom) {
215        IMPL.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end, bottom);
216    }
217
218    /**
219     * Sets the Drawables (if any) to appear to the start of, above, to the end
220     * of, and below the text. Use 0 if you do not want a Drawable there. The
221     * Drawables' bounds will be set to their intrinsic bounds.
222     * <p/>
223     * Calling this method will overwrite any Drawables previously set using
224     * {@link TextView#setCompoundDrawables} or related methods.
225     *
226     * @param textView The TextView against which to invoke the method.
227     * @param start    Resource identifier of the start Drawable.
228     * @param top      Resource identifier of the top Drawable.
229     * @param end      Resource identifier of the end Drawable.
230     * @param bottom   Resource identifier of the bottom Drawable.
231     * @attr name android:drawableStart
232     * @attr name android:drawableTop
233     * @attr name android:drawableEnd
234     * @attr name android:drawableBottom
235     */
236    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(@NonNull TextView textView,
237            @DrawableRes int start, @DrawableRes int top, @DrawableRes int end,
238            @DrawableRes int bottom) {
239        IMPL.setCompoundDrawablesRelativeWithIntrinsicBounds(textView, start, top, end, bottom);
240    }
241
242    /**
243     * Returns the maximum number of lines displayed in the given TextView, or -1 if the maximum
244     * height was set in pixels instead.
245     */
246    public static int getMaxLines(@NonNull TextView textView) {
247        return IMPL.getMaxLines(textView);
248    }
249
250    /**
251     * Returns the minimum number of lines displayed in the given TextView, or -1 if the minimum
252     * height was set in pixels instead.
253     */
254    public static int getMinLines(@NonNull TextView textView) {
255        return IMPL.getMinLines(textView);
256    }
257
258    /**
259     * Sets the text appearance from the specified style resource.
260     * <p>
261     * Use a framework-defined {@code TextAppearance} style like
262     * {@link android.R.style#TextAppearance_Material_Body1 @android:style/TextAppearance.Material.Body1}
263     * or see {@link android.R.styleable#TextAppearance TextAppearance} for the
264     * set of attributes that can be used in a custom style.
265     *
266     * @param textView The TextView against which to invoke the method.
267     * @param resId    The resource identifier of the style to apply.
268     */
269    public static void setTextAppearance(@NonNull TextView textView, @StyleRes int resId) {
270        IMPL.setTextAppearance(textView, resId);
271    }
272}
273