• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package android.support.v4.content.res;
17 
18 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
19 
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.content.res.TypedArray;
23 import android.graphics.drawable.Drawable;
24 import android.support.annotation.AnyRes;
25 import android.support.annotation.ColorInt;
26 import android.support.annotation.NonNull;
27 import android.support.annotation.RestrictTo;
28 import android.support.annotation.StyleableRes;
29 import android.util.AttributeSet;
30 import android.util.TypedValue;
31 
32 import org.xmlpull.v1.XmlPullParser;
33 
34 /**
35  * Compat methods for accessing TypedArray values.
36  *
37  * All the getNamed*() functions added the attribute name match, to take care of potential ID
38  * collision between the private attributes in older OS version (OEM) and the attributes existed in
39  * the newer OS version.
40  * For example, if an private attribute named "abcdefg" in Kitkat has the
41  * same id value as "android:pathData" in Lollipop, we need to match the attribute's namefirst.
42  *
43  * @hide
44  */
45 @RestrictTo(LIBRARY_GROUP)
46 public class TypedArrayUtils {
47 
48     private static final String NAMESPACE = "http://schemas.android.com/apk/res/android";
49 
50     /**
51      * @return Whether the current node ofthe  {@link XmlPullParser} has an attribute with the
52      * specified {@code attrName}.
53      */
hasAttribute(@onNull XmlPullParser parser, @NonNull String attrName)54     public static boolean hasAttribute(@NonNull XmlPullParser parser, @NonNull String attrName) {
55         return parser.getAttributeValue(NAMESPACE, attrName) != null;
56     }
57 
58     /**
59      * Retrieves a float attribute value. In addition to the styleable resource ID, we also make
60      * sure that the attribute name matches.
61      *
62      * @return a float value in the {@link TypedArray} with the specified {@code resId}, or
63      * {@code defaultValue} if it does not exist.
64      */
getNamedFloat(@onNull TypedArray a, @NonNull XmlPullParser parser, @NonNull String attrName, @StyleableRes int resId, float defaultValue)65     public static float getNamedFloat(@NonNull TypedArray a, @NonNull XmlPullParser parser,
66             @NonNull String attrName, @StyleableRes int resId, float defaultValue) {
67         final boolean hasAttr = hasAttribute(parser, attrName);
68         if (!hasAttr) {
69             return defaultValue;
70         } else {
71             return a.getFloat(resId, defaultValue);
72         }
73     }
74 
75     /**
76      * Retrieves a boolean attribute value. In addition to the styleable resource ID, we also make
77      * sure that the attribute name matches.
78      *
79      * @return a boolean value in the {@link TypedArray} with the specified {@code resId}, or
80      * {@code defaultValue} if it does not exist.
81      */
getNamedBoolean(@onNull TypedArray a, @NonNull XmlPullParser parser, String attrName, @StyleableRes int resId, boolean defaultValue)82     public static boolean getNamedBoolean(@NonNull TypedArray a, @NonNull XmlPullParser parser,
83             String attrName, @StyleableRes int resId, boolean defaultValue) {
84         final boolean hasAttr = hasAttribute(parser, attrName);
85         if (!hasAttr) {
86             return defaultValue;
87         } else {
88             return a.getBoolean(resId, defaultValue);
89         }
90     }
91 
92     /**
93      * Retrieves an int attribute value. In addition to the styleable resource ID, we also make
94      * sure that the attribute name matches.
95      *
96      * @return an int value in the {@link TypedArray} with the specified {@code resId}, or
97      * {@code defaultValue} if it does not exist.
98      */
getNamedInt(@onNull TypedArray a, @NonNull XmlPullParser parser, String attrName, @StyleableRes int resId, int defaultValue)99     public static int getNamedInt(@NonNull TypedArray a, @NonNull XmlPullParser parser,
100             String attrName, @StyleableRes int resId, int defaultValue) {
101         final boolean hasAttr = hasAttribute(parser, attrName);
102         if (!hasAttr) {
103             return defaultValue;
104         } else {
105             return a.getInt(resId, defaultValue);
106         }
107     }
108 
109     /**
110      * Retrieves a color attribute value. In addition to the styleable resource ID, we also make
111      * sure that the attribute name matches.
112      *
113      * @return a color value in the {@link TypedArray} with the specified {@code resId}, or
114      * {@code defaultValue} if it does not exist.
115      */
116     @ColorInt
getNamedColor(@onNull TypedArray a, @NonNull XmlPullParser parser, String attrName, @StyleableRes int resId, @ColorInt int defaultValue)117     public static int getNamedColor(@NonNull TypedArray a, @NonNull XmlPullParser parser,
118             String attrName, @StyleableRes int resId, @ColorInt int defaultValue) {
119         final boolean hasAttr = hasAttribute(parser, attrName);
120         if (!hasAttr) {
121             return defaultValue;
122         } else {
123             return a.getColor(resId, defaultValue);
124         }
125     }
126 
127     /**
128      * Retrieves a resource ID attribute value. In addition to the styleable resource ID, we also
129      * make sure that the attribute name matches.
130      *
131      * @return a resource ID value in the {@link TypedArray} with the specified {@code resId}, or
132      * {@code defaultValue} if it does not exist.
133      */
134     @AnyRes
getNamedResourceId(@onNull TypedArray a, @NonNull XmlPullParser parser, String attrName, @StyleableRes int resId, @AnyRes int defaultValue)135     public static int getNamedResourceId(@NonNull TypedArray a, @NonNull XmlPullParser parser,
136             String attrName, @StyleableRes int resId, @AnyRes int defaultValue) {
137         final boolean hasAttr = hasAttribute(parser, attrName);
138         if (!hasAttr) {
139             return defaultValue;
140         } else {
141             return a.getResourceId(resId, defaultValue);
142         }
143     }
144 
145     /**
146      * Retrieves a string attribute value. In addition to the styleable resource ID, we also
147      * make sure that the attribute name matches.
148      *
149      * @return a string value in the {@link TypedArray} with the specified {@code resId}, or
150      * null if it does not exist.
151      */
getNamedString(@onNull TypedArray a, @NonNull XmlPullParser parser, String attrName, @StyleableRes int resId)152     public static String getNamedString(@NonNull TypedArray a, @NonNull XmlPullParser parser,
153             String attrName, @StyleableRes int resId) {
154         final boolean hasAttr = hasAttribute(parser, attrName);
155         if (!hasAttr) {
156             return null;
157         } else {
158             return a.getString(resId);
159         }
160     }
161 
162     /**
163      * Retrieve the raw TypedValue for the attribute at <var>index</var>
164      * and return a temporary object holding its data.  This object is only
165      * valid until the next call on to {@link TypedArray}.
166      */
peekNamedValue(TypedArray a, XmlPullParser parser, String attrName, int resId)167     public static TypedValue peekNamedValue(TypedArray a, XmlPullParser parser, String attrName,
168             int resId) {
169         final boolean hasAttr = hasAttribute(parser, attrName);
170         if (!hasAttr) {
171             return null;
172         } else {
173             return a.peekValue(resId);
174         }
175     }
176 
177     /**
178      * Obtains styled attributes from the theme, if available, or unstyled
179      * resources if the theme is null.
180      */
obtainAttributes( Resources res, Resources.Theme theme, AttributeSet set, int[] attrs)181     public static TypedArray obtainAttributes(
182             Resources res, Resources.Theme theme, AttributeSet set, int[] attrs) {
183         if (theme == null) {
184             return res.obtainAttributes(set, attrs);
185         }
186         return theme.obtainStyledAttributes(set, attrs, 0, 0);
187     }
188 
189     /**
190      * @return a boolean value of {@code index}. If it does not exist, a boolean value of
191      * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
192      */
getBoolean(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex, boolean defaultValue)193     public static boolean getBoolean(TypedArray a, @StyleableRes int index,
194             @StyleableRes int fallbackIndex, boolean defaultValue) {
195         boolean val = a.getBoolean(fallbackIndex, defaultValue);
196         return a.getBoolean(index, val);
197     }
198 
199     /**
200      * @return a drawable value of {@code index}. If it does not exist, a drawable value of
201      * {@code fallbackIndex}. If it still does not exist, {@code null}.
202      */
getDrawable(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex)203     public static Drawable getDrawable(TypedArray a, @StyleableRes int index,
204             @StyleableRes int fallbackIndex) {
205         Drawable val = a.getDrawable(index);
206         if (val == null) {
207             val = a.getDrawable(fallbackIndex);
208         }
209         return val;
210     }
211 
212     /**
213      * @return an int value of {@code index}. If it does not exist, an int value of
214      * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
215      */
getInt(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex, int defaultValue)216     public static int getInt(TypedArray a, @StyleableRes int index,
217             @StyleableRes int fallbackIndex, int defaultValue) {
218         int val = a.getInt(fallbackIndex, defaultValue);
219         return a.getInt(index, val);
220     }
221 
222     /**
223      * @return a resource ID value of {@code index}. If it does not exist, a resource ID value of
224      * {@code fallbackIndex}. If it still does not exist, {@code defaultValue}.
225      */
226     @AnyRes
getResourceId(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex, @AnyRes int defaultValue)227     public static int getResourceId(TypedArray a, @StyleableRes int index,
228             @StyleableRes int fallbackIndex, @AnyRes int defaultValue) {
229         int val = a.getResourceId(fallbackIndex, defaultValue);
230         return a.getResourceId(index, val);
231     }
232 
233     /**
234      * @return a string value of {@code index}. If it does not exist, a string value of
235      * {@code fallbackIndex}. If it still does not exist, {@code null}.
236      */
getString(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex)237     public static String getString(TypedArray a, @StyleableRes int index,
238             @StyleableRes int fallbackIndex) {
239         String val = a.getString(index);
240         if (val == null) {
241             val = a.getString(fallbackIndex);
242         }
243         return val;
244     }
245 
246     /**
247      * Retrieves a text attribute value with the specified fallback ID.
248      *
249      * @return a text value of {@code index}. If it does not exist, a text value of
250      * {@code fallbackIndex}. If it still does not exist, {@code null}.
251      */
getText(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex)252     public static CharSequence getText(TypedArray a, @StyleableRes int index,
253             @StyleableRes int fallbackIndex) {
254         CharSequence val = a.getText(index);
255         if (val == null) {
256             val = a.getText(fallbackIndex);
257         }
258         return val;
259     }
260 
261     /**
262      * Retrieves a string array attribute value with the specified fallback ID.
263      *
264      * @return a string array value of {@code index}. If it does not exist, a string array value
265      * of {@code fallbackIndex}. If it still does not exist, {@code null}.
266      */
getTextArray(TypedArray a, @StyleableRes int index, @StyleableRes int fallbackIndex)267     public static CharSequence[] getTextArray(TypedArray a, @StyleableRes int index,
268             @StyleableRes int fallbackIndex) {
269         CharSequence[] val = a.getTextArray(index);
270         if (val == null) {
271             val = a.getTextArray(fallbackIndex);
272         }
273         return val;
274     }
275 
276     /**
277      * @return The resource ID value in the {@code context} specified by {@code attr}. If it does
278      * not exist, {@code fallbackAttr}.
279      */
getAttr(Context context, int attr, int fallbackAttr)280     public static int getAttr(Context context, int attr, int fallbackAttr) {
281         TypedValue value = new TypedValue();
282         context.getTheme().resolveAttribute(attr, value, true);
283         if (value.resourceId != 0) {
284             return attr;
285         }
286         return fallbackAttr;
287     }
288 }
289