• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 android.content.res;
18 
19 import android.annotation.AnyRes;
20 import android.annotation.ColorInt;
21 import android.annotation.Nullable;
22 import android.annotation.StyleableRes;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.ActivityInfo.Config;
25 import android.graphics.Typeface;
26 import android.graphics.drawable.Drawable;
27 import android.os.StrictMode;
28 import android.util.AttributeSet;
29 import android.util.DisplayMetrics;
30 import android.util.TypedValue;
31 
32 import com.android.internal.util.XmlUtils;
33 
34 import dalvik.system.VMRuntime;
35 
36 import java.util.Arrays;
37 
38 /**
39  * Container for an array of values that were retrieved with
40  * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
41  * or {@link Resources#obtainAttributes}.  Be
42  * sure to call {@link #recycle} when done with them.
43  *
44  * The indices used to retrieve values from this structure correspond to
45  * the positions of the attributes given to obtainStyledAttributes.
46  */
47 public class TypedArray {
48 
obtain(Resources res, int len)49     static TypedArray obtain(Resources res, int len) {
50         TypedArray attrs = res.mTypedArrayPool.acquire();
51         if (attrs == null) {
52             attrs = new TypedArray(res);
53         }
54 
55         attrs.mRecycled = false;
56         // Reset the assets, which may have changed due to configuration changes
57         // or further resource loading.
58         attrs.mAssets = res.getAssets();
59         attrs.mMetrics = res.getDisplayMetrics();
60         attrs.resize(len);
61         return attrs;
62     }
63 
64     private final Resources mResources;
65     private DisplayMetrics mMetrics;
66     private AssetManager mAssets;
67 
68     private boolean mRecycled;
69 
70     /*package*/ XmlBlock.Parser mXml;
71     /*package*/ Resources.Theme mTheme;
72     /*package*/ int[] mData;
73     /*package*/ long mDataAddress;
74     /*package*/ int[] mIndices;
75     /*package*/ long mIndicesAddress;
76     /*package*/ int mLength;
77     /*package*/ TypedValue mValue = new TypedValue();
78 
resize(int len)79     private void resize(int len) {
80         mLength = len;
81         final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
82         final int indicesLen = len + 1;
83         final VMRuntime runtime = VMRuntime.getRuntime();
84         if (mDataAddress == 0 || mData.length < dataLen) {
85             mData = (int[]) runtime.newNonMovableArray(int.class, dataLen);
86             mDataAddress = runtime.addressOf(mData);
87             mIndices = (int[]) runtime.newNonMovableArray(int.class, indicesLen);
88             mIndicesAddress = runtime.addressOf(mIndices);
89         }
90     }
91 
92     /**
93      * Returns the number of values in this array.
94      *
95      * @throws RuntimeException if the TypedArray has already been recycled.
96      */
length()97     public int length() {
98         if (mRecycled) {
99             throw new RuntimeException("Cannot make calls to a recycled instance!");
100         }
101 
102         return mLength;
103     }
104 
105     /**
106      * Returns the number of indices in the array that actually have data. Attributes with a value
107      * of @empty are included, as this is an explicit indicator.
108      *
109      * @throws RuntimeException if the TypedArray has already been recycled.
110      */
getIndexCount()111     public int getIndexCount() {
112         if (mRecycled) {
113             throw new RuntimeException("Cannot make calls to a recycled instance!");
114         }
115 
116         return mIndices[0];
117     }
118 
119     /**
120      * Returns an index in the array that has data. Attributes with a value of @empty are included,
121      * as this is an explicit indicator.
122      *
123      * @param at The index you would like to returned, ranging from 0 to
124      *           {@link #getIndexCount()}.
125      *
126      * @return The index at the given offset, which can be used with
127      *         {@link #getValue} and related APIs.
128      * @throws RuntimeException if the TypedArray has already been recycled.
129      */
getIndex(int at)130     public int getIndex(int at) {
131         if (mRecycled) {
132             throw new RuntimeException("Cannot make calls to a recycled instance!");
133         }
134 
135         return mIndices[1+at];
136     }
137 
138     /**
139      * Returns the Resources object this array was loaded from.
140      *
141      * @throws RuntimeException if the TypedArray has already been recycled.
142      */
getResources()143     public Resources getResources() {
144         if (mRecycled) {
145             throw new RuntimeException("Cannot make calls to a recycled instance!");
146         }
147 
148         return mResources;
149     }
150 
151     /**
152      * Retrieves the styled string value for the attribute at <var>index</var>.
153      * <p>
154      * If the attribute is not a string, this method will attempt to coerce
155      * it to a string.
156      *
157      * @param index Index of attribute to retrieve.
158      *
159      * @return CharSequence holding string data. May be styled. Returns
160      *         {@code null} if the attribute is not defined or could not be
161      *         coerced to a string.
162      * @throws RuntimeException if the TypedArray has already been recycled.
163      */
getText(@tyleableRes int index)164     public CharSequence getText(@StyleableRes int index) {
165         if (mRecycled) {
166             throw new RuntimeException("Cannot make calls to a recycled instance!");
167         }
168 
169         index *= AssetManager.STYLE_NUM_ENTRIES;
170         final int[] data = mData;
171         final int type = data[index+AssetManager.STYLE_TYPE];
172         if (type == TypedValue.TYPE_NULL) {
173             return null;
174         } else if (type == TypedValue.TYPE_STRING) {
175             return loadStringValueAt(index);
176         }
177 
178         final TypedValue v = mValue;
179         if (getValueAt(index, v)) {
180             return v.coerceToString();
181         }
182 
183         // We already checked for TYPE_NULL. This should never happen.
184         throw new RuntimeException("getText of bad type: 0x" + Integer.toHexString(type));
185     }
186 
187     /**
188      * Retrieves the string value for the attribute at <var>index</var>.
189      * <p>
190      * If the attribute is not a string, this method will attempt to coerce
191      * it to a string.
192      *
193      * @param index Index of attribute to retrieve.
194      *
195      * @return String holding string data. Any styling information is removed.
196      *         Returns {@code null} if the attribute is not defined or could
197      *         not be coerced to a string.
198      * @throws RuntimeException if the TypedArray has already been recycled.
199      */
200     @Nullable
getString(@tyleableRes int index)201     public String getString(@StyleableRes int index) {
202         if (mRecycled) {
203             throw new RuntimeException("Cannot make calls to a recycled instance!");
204         }
205 
206         index *= AssetManager.STYLE_NUM_ENTRIES;
207         final int[] data = mData;
208         final int type = data[index+AssetManager.STYLE_TYPE];
209         if (type == TypedValue.TYPE_NULL) {
210             return null;
211         } else if (type == TypedValue.TYPE_STRING) {
212             return loadStringValueAt(index).toString();
213         }
214 
215         final TypedValue v = mValue;
216         if (getValueAt(index, v)) {
217             final CharSequence cs = v.coerceToString();
218             return cs != null ? cs.toString() : null;
219         }
220 
221         // We already checked for TYPE_NULL. This should never happen.
222         throw new RuntimeException("getString of bad type: 0x" + Integer.toHexString(type));
223     }
224 
225     /**
226      * Retrieves the string value for the attribute at <var>index</var>, but
227      * only if that string comes from an immediate value in an XML file.  That
228      * is, this does not allow references to string resources, string
229      * attributes, or conversions from other types.  As such, this method
230      * will only return strings for TypedArray objects that come from
231      * attributes in an XML file.
232      *
233      * @param index Index of attribute to retrieve.
234      *
235      * @return String holding string data. Any styling information is removed.
236      *         Returns {@code null} if the attribute is not defined or is not
237      *         an immediate string value.
238      * @throws RuntimeException if the TypedArray has already been recycled.
239      */
getNonResourceString(@tyleableRes int index)240     public String getNonResourceString(@StyleableRes int index) {
241         if (mRecycled) {
242             throw new RuntimeException("Cannot make calls to a recycled instance!");
243         }
244 
245         index *= AssetManager.STYLE_NUM_ENTRIES;
246         final int[] data = mData;
247         final int type = data[index+AssetManager.STYLE_TYPE];
248         if (type == TypedValue.TYPE_STRING) {
249             final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
250             if (cookie < 0) {
251                 return mXml.getPooledString(
252                     data[index+AssetManager.STYLE_DATA]).toString();
253             }
254         }
255         return null;
256     }
257 
258     /**
259      * Retrieves the string value for the attribute at <var>index</var> that is
260      * not allowed to change with the given configurations.
261      *
262      * @param index Index of attribute to retrieve.
263      * @param allowedChangingConfigs Bit mask of configurations from
264      *        {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
265      *
266      * @return String holding string data. Any styling information is removed.
267      *         Returns {@code null} if the attribute is not defined.
268      * @throws RuntimeException if the TypedArray has already been recycled.
269      * @hide
270      */
getNonConfigurationString(@tyleableRes int index, @Config int allowedChangingConfigs)271     public String getNonConfigurationString(@StyleableRes int index,
272             @Config int allowedChangingConfigs) {
273         if (mRecycled) {
274             throw new RuntimeException("Cannot make calls to a recycled instance!");
275         }
276 
277         index *= AssetManager.STYLE_NUM_ENTRIES;
278         final int[] data = mData;
279         final int type = data[index+AssetManager.STYLE_TYPE];
280         final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
281                 data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
282         if ((changingConfigs & ~allowedChangingConfigs) != 0) {
283             return null;
284         }
285         if (type == TypedValue.TYPE_NULL) {
286             return null;
287         } else if (type == TypedValue.TYPE_STRING) {
288             return loadStringValueAt(index).toString();
289         }
290 
291         final TypedValue v = mValue;
292         if (getValueAt(index, v)) {
293             final CharSequence cs = v.coerceToString();
294             return cs != null ? cs.toString() : null;
295         }
296 
297         // We already checked for TYPE_NULL. This should never happen.
298         throw new RuntimeException("getNonConfigurationString of bad type: 0x"
299                 + Integer.toHexString(type));
300     }
301 
302     /**
303      * Retrieve the boolean value for the attribute at <var>index</var>.
304      * <p>
305      * If the attribute is an integer value, this method will return whether
306      * it is equal to zero. If the attribute is not a boolean or integer value,
307      * this method will attempt to coerce it to an integer using
308      * {@link Integer#decode(String)} and return whether it is equal to zero.
309      *
310      * @param index Index of attribute to retrieve.
311      * @param defValue Value to return if the attribute is not defined or
312      *                 cannot be coerced to an integer.
313      *
314      * @return Boolean value of the attribute, or defValue if the attribute was
315      *         not defined or could not be coerced to an integer.
316      * @throws RuntimeException if the TypedArray has already been recycled.
317      */
getBoolean(@tyleableRes int index, boolean defValue)318     public boolean getBoolean(@StyleableRes int index, boolean defValue) {
319         if (mRecycled) {
320             throw new RuntimeException("Cannot make calls to a recycled instance!");
321         }
322 
323         index *= AssetManager.STYLE_NUM_ENTRIES;
324         final int[] data = mData;
325         final int type = data[index+AssetManager.STYLE_TYPE];
326         if (type == TypedValue.TYPE_NULL) {
327             return defValue;
328         } else if (type >= TypedValue.TYPE_FIRST_INT
329                 && type <= TypedValue.TYPE_LAST_INT) {
330             return data[index+AssetManager.STYLE_DATA] != 0;
331         }
332 
333         final TypedValue v = mValue;
334         if (getValueAt(index, v)) {
335             StrictMode.noteResourceMismatch(v);
336             return XmlUtils.convertValueToBoolean(v.coerceToString(), defValue);
337         }
338 
339         // We already checked for TYPE_NULL. This should never happen.
340         throw new RuntimeException("getBoolean of bad type: 0x" + Integer.toHexString(type));
341     }
342 
343     /**
344      * Retrieve the integer value for the attribute at <var>index</var>.
345      * <p>
346      * If the attribute is not an integer, this method will attempt to coerce
347      * it to an integer using {@link Integer#decode(String)}.
348      *
349      * @param index Index of attribute to retrieve.
350      * @param defValue Value to return if the attribute is not defined or
351      *                 cannot be coerced to an integer.
352      *
353      * @return Integer value of the attribute, or defValue if the attribute was
354      *         not defined or could not be coerced to an integer.
355      * @throws RuntimeException if the TypedArray has already been recycled.
356      */
getInt(@tyleableRes int index, int defValue)357     public int getInt(@StyleableRes int index, int defValue) {
358         if (mRecycled) {
359             throw new RuntimeException("Cannot make calls to a recycled instance!");
360         }
361 
362         index *= AssetManager.STYLE_NUM_ENTRIES;
363         final int[] data = mData;
364         final int type = data[index+AssetManager.STYLE_TYPE];
365         if (type == TypedValue.TYPE_NULL) {
366             return defValue;
367         } else if (type >= TypedValue.TYPE_FIRST_INT
368                 && type <= TypedValue.TYPE_LAST_INT) {
369             return data[index+AssetManager.STYLE_DATA];
370         }
371 
372         final TypedValue v = mValue;
373         if (getValueAt(index, v)) {
374             StrictMode.noteResourceMismatch(v);
375             return XmlUtils.convertValueToInt(v.coerceToString(), defValue);
376         }
377 
378         // We already checked for TYPE_NULL. This should never happen.
379         throw new RuntimeException("getInt of bad type: 0x" + Integer.toHexString(type));
380     }
381 
382     /**
383      * Retrieve the float value for the attribute at <var>index</var>.
384      * <p>
385      * If the attribute is not a float or an integer, this method will attempt
386      * to coerce it to a float using {@link Float#parseFloat(String)}.
387      *
388      * @param index Index of attribute to retrieve.
389      *
390      * @return Attribute float value, or defValue if the attribute was
391      *         not defined or could not be coerced to a float.
392      * @throws RuntimeException if the TypedArray has already been recycled.
393      */
getFloat(@tyleableRes int index, float defValue)394     public float getFloat(@StyleableRes int index, float defValue) {
395         if (mRecycled) {
396             throw new RuntimeException("Cannot make calls to a recycled instance!");
397         }
398 
399         index *= AssetManager.STYLE_NUM_ENTRIES;
400         final int[] data = mData;
401         final int type = data[index+AssetManager.STYLE_TYPE];
402         if (type == TypedValue.TYPE_NULL) {
403             return defValue;
404         } else if (type == TypedValue.TYPE_FLOAT) {
405             return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
406         } else if (type >= TypedValue.TYPE_FIRST_INT
407                 && type <= TypedValue.TYPE_LAST_INT) {
408             return data[index+AssetManager.STYLE_DATA];
409         }
410 
411         final TypedValue v = mValue;
412         if (getValueAt(index, v)) {
413             final CharSequence str = v.coerceToString();
414             if (str != null) {
415                 StrictMode.noteResourceMismatch(v);
416                 return Float.parseFloat(str.toString());
417             }
418         }
419 
420         // We already checked for TYPE_NULL. This should never happen.
421         throw new RuntimeException("getFloat of bad type: 0x" + Integer.toHexString(type));
422     }
423 
424     /**
425      * Retrieve the color value for the attribute at <var>index</var>.  If
426      * the attribute references a color resource holding a complex
427      * {@link android.content.res.ColorStateList}, then the default color from
428      * the set is returned.
429      * <p>
430      * This method will throw an exception if the attribute is defined but is
431      * not an integer color or color state list.
432      *
433      * @param index Index of attribute to retrieve.
434      * @param defValue Value to return if the attribute is not defined or
435      *                 not a resource.
436      *
437      * @return Attribute color value, or defValue if not defined.
438      * @throws RuntimeException if the TypedArray has already been recycled.
439      * @throws UnsupportedOperationException if the attribute is defined but is
440      *         not an integer color or color state list.
441      */
442     @ColorInt
getColor(@tyleableRes int index, @ColorInt int defValue)443     public int getColor(@StyleableRes int index, @ColorInt int defValue) {
444         if (mRecycled) {
445             throw new RuntimeException("Cannot make calls to a recycled instance!");
446         }
447 
448         final int attrIndex = index;
449         index *= AssetManager.STYLE_NUM_ENTRIES;
450 
451         final int[] data = mData;
452         final int type = data[index+AssetManager.STYLE_TYPE];
453         if (type == TypedValue.TYPE_NULL) {
454             return defValue;
455         } else if (type >= TypedValue.TYPE_FIRST_INT
456                 && type <= TypedValue.TYPE_LAST_INT) {
457             return data[index+AssetManager.STYLE_DATA];
458         } else if (type == TypedValue.TYPE_STRING) {
459             final TypedValue value = mValue;
460             if (getValueAt(index, value)) {
461                 final ColorStateList csl = mResources.loadColorStateList(
462                         value, value.resourceId, mTheme);
463                 return csl.getDefaultColor();
464             }
465             return defValue;
466         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
467             final TypedValue value = mValue;
468             getValueAt(index, value);
469             throw new UnsupportedOperationException(
470                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
471         }
472 
473         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
474                 + " to color: type=0x" + Integer.toHexString(type));
475     }
476 
477     /**
478      * Retrieve the ComplexColor for the attribute at <var>index</var>.
479      * The value may be either a {@link android.content.res.ColorStateList} which can wrap a simple
480      * color value or a {@link android.content.res.GradientColor}
481      * <p>
482      * This method will return {@code null} if the attribute is not defined or
483      * is not an integer color, color state list or GradientColor.
484      *
485      * @param index Index of attribute to retrieve.
486      *
487      * @return ComplexColor for the attribute, or {@code null} if not defined.
488      * @throws RuntimeException if the attribute if the TypedArray has already
489      *         been recycled.
490      * @throws UnsupportedOperationException if the attribute is defined but is
491      *         not an integer color, color state list or GradientColor.
492      * @hide
493      */
494     @Nullable
getComplexColor(@tyleableRes int index)495     public ComplexColor getComplexColor(@StyleableRes int index) {
496         if (mRecycled) {
497             throw new RuntimeException("Cannot make calls to a recycled instance!");
498         }
499 
500         final TypedValue value = mValue;
501         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
502             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
503                 throw new UnsupportedOperationException(
504                         "Failed to resolve attribute at index " + index + ": " + value);
505             }
506             return mResources.loadComplexColor(value, value.resourceId, mTheme);
507         }
508         return null;
509     }
510 
511     /**
512      * Retrieve the ColorStateList for the attribute at <var>index</var>.
513      * The value may be either a single solid color or a reference to
514      * a color or complex {@link android.content.res.ColorStateList}
515      * description.
516      * <p>
517      * This method will return {@code null} if the attribute is not defined or
518      * is not an integer color or color state list.
519      *
520      * @param index Index of attribute to retrieve.
521      *
522      * @return ColorStateList for the attribute, or {@code null} if not
523      *         defined.
524      * @throws RuntimeException if the attribute if the TypedArray has already
525      *         been recycled.
526      * @throws UnsupportedOperationException if the attribute is defined but is
527      *         not an integer color or color state list.
528      */
529     @Nullable
getColorStateList(@tyleableRes int index)530     public ColorStateList getColorStateList(@StyleableRes int index) {
531         if (mRecycled) {
532             throw new RuntimeException("Cannot make calls to a recycled instance!");
533         }
534 
535         final TypedValue value = mValue;
536         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
537             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
538                 throw new UnsupportedOperationException(
539                         "Failed to resolve attribute at index " + index + ": " + value);
540             }
541             return mResources.loadColorStateList(value, value.resourceId, mTheme);
542         }
543         return null;
544     }
545 
546     /**
547      * Retrieve the integer value for the attribute at <var>index</var>.
548      * <p>
549      * Unlike {@link #getInt(int, int)}, this method will throw an exception if
550      * the attribute is defined but is not an integer.
551      *
552      * @param index Index of attribute to retrieve.
553      * @param defValue Value to return if the attribute is not defined or
554      *                 not a resource.
555      *
556      * @return Attribute integer value, or defValue if not defined.
557      * @throws RuntimeException if the TypedArray has already been recycled.
558      * @throws UnsupportedOperationException if the attribute is defined but is
559      *         not an integer.
560      */
getInteger(@tyleableRes int index, int defValue)561     public int getInteger(@StyleableRes int index, int defValue) {
562         if (mRecycled) {
563             throw new RuntimeException("Cannot make calls to a recycled instance!");
564         }
565 
566         final int attrIndex = index;
567         index *= AssetManager.STYLE_NUM_ENTRIES;
568 
569         final int[] data = mData;
570         final int type = data[index+AssetManager.STYLE_TYPE];
571         if (type == TypedValue.TYPE_NULL) {
572             return defValue;
573         } else if (type >= TypedValue.TYPE_FIRST_INT
574                 && type <= TypedValue.TYPE_LAST_INT) {
575             return data[index+AssetManager.STYLE_DATA];
576         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
577             final TypedValue value = mValue;
578             getValueAt(index, value);
579             throw new UnsupportedOperationException(
580                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
581         }
582 
583         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
584                 + " to integer: type=0x" + Integer.toHexString(type));
585     }
586 
587     /**
588      * Retrieve a dimensional unit attribute at <var>index</var>. Unit
589      * conversions are based on the current {@link DisplayMetrics}
590      * associated with the resources this {@link TypedArray} object
591      * came from.
592      * <p>
593      * This method will throw an exception if the attribute is defined but is
594      * not a dimension.
595      *
596      * @param index Index of attribute to retrieve.
597      * @param defValue Value to return if the attribute is not defined or
598      *                 not a resource.
599      *
600      * @return Attribute dimension value multiplied by the appropriate
601      *         metric, or defValue if not defined.
602      * @throws RuntimeException if the TypedArray has already been recycled.
603      * @throws UnsupportedOperationException if the attribute is defined but is
604      *         not an integer.
605      *
606      * @see #getDimensionPixelOffset
607      * @see #getDimensionPixelSize
608      */
getDimension(@tyleableRes int index, float defValue)609     public float getDimension(@StyleableRes int index, float defValue) {
610         if (mRecycled) {
611             throw new RuntimeException("Cannot make calls to a recycled instance!");
612         }
613 
614         final int attrIndex = index;
615         index *= AssetManager.STYLE_NUM_ENTRIES;
616 
617         final int[] data = mData;
618         final int type = data[index+AssetManager.STYLE_TYPE];
619         if (type == TypedValue.TYPE_NULL) {
620             return defValue;
621         } else if (type == TypedValue.TYPE_DIMENSION) {
622             return TypedValue.complexToDimension(
623                     data[index + AssetManager.STYLE_DATA], mMetrics);
624         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
625             final TypedValue value = mValue;
626             getValueAt(index, value);
627             throw new UnsupportedOperationException(
628                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
629         }
630 
631         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
632                 + " to dimension: type=0x" + Integer.toHexString(type));
633     }
634 
635     /**
636      * Retrieve a dimensional unit attribute at <var>index</var> for use
637      * as an offset in raw pixels.  This is the same as
638      * {@link #getDimension}, except the returned value is converted to
639      * integer pixels for you.  An offset conversion involves simply
640      * truncating the base value to an integer.
641      * <p>
642      * This method will throw an exception if the attribute is defined but is
643      * not a dimension.
644      *
645      * @param index Index of attribute to retrieve.
646      * @param defValue Value to return if the attribute is not defined or
647      *                 not a resource.
648      *
649      * @return Attribute dimension value multiplied by the appropriate
650      *         metric and truncated to integer pixels, or defValue if not defined.
651      * @throws RuntimeException if the TypedArray has already been recycled.
652      * @throws UnsupportedOperationException if the attribute is defined but is
653      *         not an integer.
654      *
655      * @see #getDimension
656      * @see #getDimensionPixelSize
657      */
getDimensionPixelOffset(@tyleableRes int index, int defValue)658     public int getDimensionPixelOffset(@StyleableRes int index, int defValue) {
659         if (mRecycled) {
660             throw new RuntimeException("Cannot make calls to a recycled instance!");
661         }
662 
663         final int attrIndex = index;
664         index *= AssetManager.STYLE_NUM_ENTRIES;
665 
666         final int[] data = mData;
667         final int type = data[index+AssetManager.STYLE_TYPE];
668         if (type == TypedValue.TYPE_NULL) {
669             return defValue;
670         } else if (type == TypedValue.TYPE_DIMENSION) {
671             return TypedValue.complexToDimensionPixelOffset(
672                     data[index + AssetManager.STYLE_DATA], mMetrics);
673         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
674             final TypedValue value = mValue;
675             getValueAt(index, value);
676             throw new UnsupportedOperationException(
677                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
678         }
679 
680         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
681                 + " to dimension: type=0x" + Integer.toHexString(type));
682     }
683 
684     /**
685      * Retrieve a dimensional unit attribute at <var>index</var> for use
686      * as a size in raw pixels.  This is the same as
687      * {@link #getDimension}, except the returned value is converted to
688      * integer pixels for use as a size.  A size conversion involves
689      * rounding the base value, and ensuring that a non-zero base value
690      * is at least one pixel in size.
691      * <p>
692      * This method will throw an exception if the attribute is defined but is
693      * not a dimension.
694      *
695      * @param index Index of attribute to retrieve.
696      * @param defValue Value to return if the attribute is not defined or
697      *                 not a resource.
698      *
699      * @return Attribute dimension value multiplied by the appropriate
700      *         metric and truncated to integer pixels, or defValue if not defined.
701      * @throws RuntimeException if the TypedArray has already been recycled.
702      * @throws UnsupportedOperationException if the attribute is defined but is
703      *         not a dimension.
704      *
705      * @see #getDimension
706      * @see #getDimensionPixelOffset
707      */
getDimensionPixelSize(@tyleableRes int index, int defValue)708     public int getDimensionPixelSize(@StyleableRes int index, int defValue) {
709         if (mRecycled) {
710             throw new RuntimeException("Cannot make calls to a recycled instance!");
711         }
712 
713         final int attrIndex = index;
714         index *= AssetManager.STYLE_NUM_ENTRIES;
715 
716         final int[] data = mData;
717         final int type = data[index+AssetManager.STYLE_TYPE];
718         if (type == TypedValue.TYPE_NULL) {
719             return defValue;
720         } else if (type == TypedValue.TYPE_DIMENSION) {
721             return TypedValue.complexToDimensionPixelSize(
722                 data[index+AssetManager.STYLE_DATA], mMetrics);
723         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
724             final TypedValue value = mValue;
725             getValueAt(index, value);
726             throw new UnsupportedOperationException(
727                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
728         }
729 
730         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
731                 + " to dimension: type=0x" + Integer.toHexString(type));
732     }
733 
734     /**
735      * Special version of {@link #getDimensionPixelSize} for retrieving
736      * {@link android.view.ViewGroup}'s layout_width and layout_height
737      * attributes.  This is only here for performance reasons; applications
738      * should use {@link #getDimensionPixelSize}.
739      * <p>
740      * This method will throw an exception if the attribute is defined but is
741      * not a dimension or integer (enum).
742      *
743      * @param index Index of the attribute to retrieve.
744      * @param name Textual name of attribute for error reporting.
745      *
746      * @return Attribute dimension value multiplied by the appropriate
747      *         metric and truncated to integer pixels.
748      * @throws RuntimeException if the TypedArray has already been recycled.
749      * @throws UnsupportedOperationException if the attribute is defined but is
750      *         not a dimension or integer (enum).
751      */
getLayoutDimension(@tyleableRes int index, String name)752     public int getLayoutDimension(@StyleableRes int index, String name) {
753         if (mRecycled) {
754             throw new RuntimeException("Cannot make calls to a recycled instance!");
755         }
756 
757         final int attrIndex = index;
758         index *= AssetManager.STYLE_NUM_ENTRIES;
759 
760         final int[] data = mData;
761         final int type = data[index+AssetManager.STYLE_TYPE];
762         if (type >= TypedValue.TYPE_FIRST_INT
763                 && type <= TypedValue.TYPE_LAST_INT) {
764             return data[index+AssetManager.STYLE_DATA];
765         } else if (type == TypedValue.TYPE_DIMENSION) {
766             return TypedValue.complexToDimensionPixelSize(
767                 data[index+AssetManager.STYLE_DATA], mMetrics);
768         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
769             final TypedValue value = mValue;
770             getValueAt(index, value);
771             throw new UnsupportedOperationException(
772                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
773         }
774 
775         throw new UnsupportedOperationException(getPositionDescription()
776                 + ": You must supply a " + name + " attribute.");
777     }
778 
779     /**
780      * Special version of {@link #getDimensionPixelSize} for retrieving
781      * {@link android.view.ViewGroup}'s layout_width and layout_height
782      * attributes.  This is only here for performance reasons; applications
783      * should use {@link #getDimensionPixelSize}.
784      *
785      * @param index Index of the attribute to retrieve.
786      * @param defValue The default value to return if this attribute is not
787      *                 default or contains the wrong type of data.
788      *
789      * @return Attribute dimension value multiplied by the appropriate
790      *         metric and truncated to integer pixels.
791      * @throws RuntimeException if the TypedArray has already been recycled.
792      */
getLayoutDimension(@tyleableRes int index, int defValue)793     public int getLayoutDimension(@StyleableRes int index, int defValue) {
794         if (mRecycled) {
795             throw new RuntimeException("Cannot make calls to a recycled instance!");
796         }
797 
798         index *= AssetManager.STYLE_NUM_ENTRIES;
799         final int[] data = mData;
800         final int type = data[index+AssetManager.STYLE_TYPE];
801         if (type >= TypedValue.TYPE_FIRST_INT
802                 && type <= TypedValue.TYPE_LAST_INT) {
803             return data[index+AssetManager.STYLE_DATA];
804         } else if (type == TypedValue.TYPE_DIMENSION) {
805             return TypedValue.complexToDimensionPixelSize(
806                     data[index + AssetManager.STYLE_DATA], mMetrics);
807         }
808 
809         return defValue;
810     }
811 
812     /**
813      * Retrieves a fractional unit attribute at <var>index</var>.
814      *
815      * @param index Index of attribute to retrieve.
816      * @param base The base value of this fraction.  In other words, a
817      *             standard fraction is multiplied by this value.
818      * @param pbase The parent base value of this fraction.  In other
819      *             words, a parent fraction (nn%p) is multiplied by this
820      *             value.
821      * @param defValue Value to return if the attribute is not defined or
822      *                 not a resource.
823      *
824      * @return Attribute fractional value multiplied by the appropriate
825      *         base value, or defValue if not defined.
826      * @throws RuntimeException if the TypedArray has already been recycled.
827      * @throws UnsupportedOperationException if the attribute is defined but is
828      *         not a fraction.
829      */
getFraction(@tyleableRes int index, int base, int pbase, float defValue)830     public float getFraction(@StyleableRes int index, int base, int pbase, float defValue) {
831         if (mRecycled) {
832             throw new RuntimeException("Cannot make calls to a recycled instance!");
833         }
834 
835         final int attrIndex = index;
836         index *= AssetManager.STYLE_NUM_ENTRIES;
837 
838         final int[] data = mData;
839         final int type = data[index+AssetManager.STYLE_TYPE];
840         if (type == TypedValue.TYPE_NULL) {
841             return defValue;
842         } else if (type == TypedValue.TYPE_FRACTION) {
843             return TypedValue.complexToFraction(
844                 data[index+AssetManager.STYLE_DATA], base, pbase);
845         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
846             final TypedValue value = mValue;
847             getValueAt(index, value);
848             throw new UnsupportedOperationException(
849                     "Failed to resolve attribute at index " + attrIndex + ": " + value);
850         }
851 
852         throw new UnsupportedOperationException("Can't convert value at index " + attrIndex
853                 + " to fraction: type=0x" + Integer.toHexString(type));
854     }
855 
856     /**
857      * Retrieves the resource identifier for the attribute at
858      * <var>index</var>.  Note that attribute resource as resolved when
859      * the overall {@link TypedArray} object is retrieved.  As a
860      * result, this function will return the resource identifier of the
861      * final resource value that was found, <em>not</em> necessarily the
862      * original resource that was specified by the attribute.
863      *
864      * @param index Index of attribute to retrieve.
865      * @param defValue Value to return if the attribute is not defined or
866      *                 not a resource.
867      *
868      * @return Attribute resource identifier, or defValue if not defined.
869      * @throws RuntimeException if the TypedArray has already been recycled.
870      */
871     @AnyRes
getResourceId(@tyleableRes int index, int defValue)872     public int getResourceId(@StyleableRes int index, int defValue) {
873         if (mRecycled) {
874             throw new RuntimeException("Cannot make calls to a recycled instance!");
875         }
876 
877         index *= AssetManager.STYLE_NUM_ENTRIES;
878         final int[] data = mData;
879         if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
880             final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
881             if (resid != 0) {
882                 return resid;
883             }
884         }
885         return defValue;
886     }
887 
888     /**
889      * Retrieves the theme attribute resource identifier for the attribute at
890      * <var>index</var>.
891      *
892      * @param index Index of attribute to retrieve.
893      * @param defValue Value to return if the attribute is not defined or not a
894      *                 resource.
895      *
896      * @return Theme attribute resource identifier, or defValue if not defined.
897      * @throws RuntimeException if the TypedArray has already been recycled.
898      * @hide
899      */
getThemeAttributeId(@tyleableRes int index, int defValue)900     public int getThemeAttributeId(@StyleableRes int index, int defValue) {
901         if (mRecycled) {
902             throw new RuntimeException("Cannot make calls to a recycled instance!");
903         }
904 
905         index *= AssetManager.STYLE_NUM_ENTRIES;
906         final int[] data = mData;
907         if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
908             return data[index + AssetManager.STYLE_DATA];
909         }
910         return defValue;
911     }
912 
913     /**
914      * Retrieve the Drawable for the attribute at <var>index</var>.
915      * <p>
916      * This method will throw an exception if the attribute is defined but is
917      * not a color or drawable resource.
918      *
919      * @param index Index of attribute to retrieve.
920      *
921      * @return Drawable for the attribute, or {@code null} if not defined.
922      * @throws RuntimeException if the TypedArray has already been recycled.
923      * @throws UnsupportedOperationException if the attribute is defined but is
924      *         not a color or drawable resource.
925      */
926     @Nullable
getDrawable(@tyleableRes int index)927     public Drawable getDrawable(@StyleableRes int index) {
928         return getDrawableForDensity(index, 0);
929     }
930 
931     /**
932      * Version of {@link #getDrawable(int)} that accepts an override density.
933      * @hide
934      */
935     @Nullable
getDrawableForDensity(@tyleableRes int index, int density)936     public Drawable getDrawableForDensity(@StyleableRes int index, int density) {
937         if (mRecycled) {
938             throw new RuntimeException("Cannot make calls to a recycled instance!");
939         }
940 
941         final TypedValue value = mValue;
942         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
943             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
944                 throw new UnsupportedOperationException(
945                         "Failed to resolve attribute at index " + index + ": " + value);
946             }
947 
948             if (density > 0) {
949                 // If the density is overridden, the value in the TypedArray will not reflect this.
950                 // Do a separate lookup of the resourceId with the density override.
951                 mResources.getValueForDensity(value.resourceId, density, value, true);
952             }
953             return mResources.loadDrawable(value, value.resourceId, density, mTheme);
954         }
955         return null;
956     }
957 
958     /**
959      * Retrieve the Typeface for the attribute at <var>index</var>.
960      * <p>
961      * This method will throw an exception if the attribute is defined but is
962      * not a font.
963      *
964      * @param index Index of attribute to retrieve.
965      *
966      * @return Typeface for the attribute, or {@code null} if not defined.
967      * @throws RuntimeException if the TypedArray has already been recycled.
968      * @throws UnsupportedOperationException if the attribute is defined but is
969      *         not a font resource.
970      */
971     @Nullable
getFont(@tyleableRes int index)972     public Typeface getFont(@StyleableRes int index) {
973         if (mRecycled) {
974             throw new RuntimeException("Cannot make calls to a recycled instance!");
975         }
976 
977         final TypedValue value = mValue;
978         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
979             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
980                 throw new UnsupportedOperationException(
981                         "Failed to resolve attribute at index " + index + ": " + value);
982             }
983             return mResources.getFont(value, value.resourceId);
984         }
985         return null;
986     }
987 
988     /**
989      * Retrieve the CharSequence[] for the attribute at <var>index</var>.
990      * This gets the resource ID of the selected attribute, and uses
991      * {@link Resources#getTextArray Resources.getTextArray} of the owning
992      * Resources object to retrieve its String[].
993      * <p>
994      * This method will throw an exception if the attribute is defined but is
995      * not a text array resource.
996      *
997      * @param index Index of attribute to retrieve.
998      *
999      * @return CharSequence[] for the attribute, or {@code null} if not
1000      *         defined.
1001      * @throws RuntimeException if the TypedArray has already been recycled.
1002      */
getTextArray(@tyleableRes int index)1003     public CharSequence[] getTextArray(@StyleableRes int index) {
1004         if (mRecycled) {
1005             throw new RuntimeException("Cannot make calls to a recycled instance!");
1006         }
1007 
1008         final TypedValue value = mValue;
1009         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
1010             return mResources.getTextArray(value.resourceId);
1011         }
1012         return null;
1013     }
1014 
1015     /**
1016      * Retrieve the raw TypedValue for the attribute at <var>index</var>.
1017      *
1018      * @param index Index of attribute to retrieve.
1019      * @param outValue TypedValue object in which to place the attribute's
1020      *                 data.
1021      *
1022      * @return {@code true} if the value was retrieved and not @empty, {@code false} otherwise.
1023      * @throws RuntimeException if the TypedArray has already been recycled.
1024      */
getValue(@tyleableRes int index, TypedValue outValue)1025     public boolean getValue(@StyleableRes int index, TypedValue outValue) {
1026         if (mRecycled) {
1027             throw new RuntimeException("Cannot make calls to a recycled instance!");
1028         }
1029 
1030         return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
1031     }
1032 
1033     /**
1034      * Returns the type of attribute at the specified index.
1035      *
1036      * @param index Index of attribute whose type to retrieve.
1037      *
1038      * @return Attribute type.
1039      * @throws RuntimeException if the TypedArray has already been recycled.
1040      */
getType(@tyleableRes int index)1041     public int getType(@StyleableRes int index) {
1042         if (mRecycled) {
1043             throw new RuntimeException("Cannot make calls to a recycled instance!");
1044         }
1045 
1046         index *= AssetManager.STYLE_NUM_ENTRIES;
1047         return mData[index + AssetManager.STYLE_TYPE];
1048     }
1049 
1050     /**
1051      * Determines whether there is an attribute at <var>index</var>.
1052      * <p>
1053      * <strong>Note:</strong> If the attribute was set to {@code @empty} or
1054      * {@code @undefined}, this method returns {@code false}.
1055      *
1056      * @param index Index of attribute to retrieve.
1057      *
1058      * @return True if the attribute has a value, false otherwise.
1059      * @throws RuntimeException if the TypedArray has already been recycled.
1060      */
hasValue(@tyleableRes int index)1061     public boolean hasValue(@StyleableRes int index) {
1062         if (mRecycled) {
1063             throw new RuntimeException("Cannot make calls to a recycled instance!");
1064         }
1065 
1066         index *= AssetManager.STYLE_NUM_ENTRIES;
1067         final int[] data = mData;
1068         final int type = data[index+AssetManager.STYLE_TYPE];
1069         return type != TypedValue.TYPE_NULL;
1070     }
1071 
1072     /**
1073      * Determines whether there is an attribute at <var>index</var>, returning
1074      * {@code true} if the attribute was explicitly set to {@code @empty} and
1075      * {@code false} only if the attribute was undefined.
1076      *
1077      * @param index Index of attribute to retrieve.
1078      *
1079      * @return True if the attribute has a value or is empty, false otherwise.
1080      * @throws RuntimeException if the TypedArray has already been recycled.
1081      */
hasValueOrEmpty(@tyleableRes int index)1082     public boolean hasValueOrEmpty(@StyleableRes int index) {
1083         if (mRecycled) {
1084             throw new RuntimeException("Cannot make calls to a recycled instance!");
1085         }
1086 
1087         index *= AssetManager.STYLE_NUM_ENTRIES;
1088         final int[] data = mData;
1089         final int type = data[index+AssetManager.STYLE_TYPE];
1090         return type != TypedValue.TYPE_NULL
1091                 || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
1092     }
1093 
1094     /**
1095      * Retrieve the raw TypedValue for the attribute at <var>index</var>
1096      * and return a temporary object holding its data.  This object is only
1097      * valid until the next call on to {@link TypedArray}.
1098      *
1099      * @param index Index of attribute to retrieve.
1100      *
1101      * @return Returns a TypedValue object if the attribute is defined,
1102      *         containing its data; otherwise returns null.  (You will not
1103      *         receive a TypedValue whose type is TYPE_NULL.)
1104      * @throws RuntimeException if the TypedArray has already been recycled.
1105      */
peekValue(@tyleableRes int index)1106     public TypedValue peekValue(@StyleableRes int index) {
1107         if (mRecycled) {
1108             throw new RuntimeException("Cannot make calls to a recycled instance!");
1109         }
1110 
1111         final TypedValue value = mValue;
1112         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
1113             return value;
1114         }
1115         return null;
1116     }
1117 
1118     /**
1119      * Returns a message about the parser state suitable for printing error messages.
1120      *
1121      * @return Human-readable description of current parser state.
1122      * @throws RuntimeException if the TypedArray has already been recycled.
1123      */
getPositionDescription()1124     public String getPositionDescription() {
1125         if (mRecycled) {
1126             throw new RuntimeException("Cannot make calls to a recycled instance!");
1127         }
1128 
1129         return mXml != null ? mXml.getPositionDescription() : "<internal>";
1130     }
1131 
1132     /**
1133      * Recycles the TypedArray, to be re-used by a later caller. After calling
1134      * this function you must not ever touch the typed array again.
1135      *
1136      * @throws RuntimeException if the TypedArray has already been recycled.
1137      */
recycle()1138     public void recycle() {
1139         if (mRecycled) {
1140             throw new RuntimeException(toString() + " recycled twice!");
1141         }
1142 
1143         mRecycled = true;
1144 
1145         // These may have been set by the client.
1146         mXml = null;
1147         mTheme = null;
1148         mAssets = null;
1149 
1150         mResources.mTypedArrayPool.release(this);
1151     }
1152 
1153     /**
1154      * Extracts theme attributes from a typed array for later resolution using
1155      * {@link android.content.res.Resources.Theme#resolveAttributes(int[], int[])}.
1156      * Removes the entries from the typed array so that subsequent calls to typed
1157      * getters will return the default value without crashing.
1158      *
1159      * @return an array of length {@link #getIndexCount()} populated with theme
1160      *         attributes, or null if there are no theme attributes in the typed
1161      *         array
1162      * @throws RuntimeException if the TypedArray has already been recycled.
1163      * @hide
1164      */
1165     @Nullable
extractThemeAttrs()1166     public int[] extractThemeAttrs() {
1167         return extractThemeAttrs(null);
1168     }
1169 
1170     /**
1171      * @hide
1172      */
1173     @Nullable
extractThemeAttrs(@ullable int[] scrap)1174     public int[] extractThemeAttrs(@Nullable int[] scrap) {
1175         if (mRecycled) {
1176             throw new RuntimeException("Cannot make calls to a recycled instance!");
1177         }
1178 
1179         int[] attrs = null;
1180 
1181         final int[] data = mData;
1182         final int N = length();
1183         for (int i = 0; i < N; i++) {
1184             final int index = i * AssetManager.STYLE_NUM_ENTRIES;
1185             if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
1186                 // Not an attribute, ignore.
1187                 continue;
1188             }
1189 
1190             // Null the entry so that we can safely call getZzz().
1191             data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
1192 
1193             final int attr = data[index + AssetManager.STYLE_DATA];
1194             if (attr == 0) {
1195                 // Useless data, ignore.
1196                 continue;
1197             }
1198 
1199             // Ensure we have a usable attribute array.
1200             if (attrs == null) {
1201                 if (scrap != null && scrap.length == N) {
1202                     attrs = scrap;
1203                     Arrays.fill(attrs, 0);
1204                 } else {
1205                     attrs = new int[N];
1206                 }
1207             }
1208 
1209             attrs[i] = attr;
1210         }
1211 
1212         return attrs;
1213     }
1214 
1215     /**
1216      * Return a mask of the configuration parameters for which the values in
1217      * this typed array may change.
1218      *
1219      * @return Returns a mask of the changing configuration parameters, as
1220      *         defined by {@link android.content.pm.ActivityInfo}.
1221      * @throws RuntimeException if the TypedArray has already been recycled.
1222      * @see android.content.pm.ActivityInfo
1223      */
getChangingConfigurations()1224     public @Config int getChangingConfigurations() {
1225         if (mRecycled) {
1226             throw new RuntimeException("Cannot make calls to a recycled instance!");
1227         }
1228 
1229         @Config int changingConfig = 0;
1230 
1231         final int[] data = mData;
1232         final int N = length();
1233         for (int i = 0; i < N; i++) {
1234             final int index = i * AssetManager.STYLE_NUM_ENTRIES;
1235             final int type = data[index + AssetManager.STYLE_TYPE];
1236             if (type == TypedValue.TYPE_NULL) {
1237                 continue;
1238             }
1239             changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
1240                     data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
1241         }
1242         return changingConfig;
1243     }
1244 
getValueAt(int index, TypedValue outValue)1245     private boolean getValueAt(int index, TypedValue outValue) {
1246         final int[] data = mData;
1247         final int type = data[index+AssetManager.STYLE_TYPE];
1248         if (type == TypedValue.TYPE_NULL) {
1249             return false;
1250         }
1251         outValue.type = type;
1252         outValue.data = data[index+AssetManager.STYLE_DATA];
1253         outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
1254         outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
1255         outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
1256                 data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
1257         outValue.density = data[index+AssetManager.STYLE_DENSITY];
1258         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
1259         return true;
1260     }
1261 
loadStringValueAt(int index)1262     private CharSequence loadStringValueAt(int index) {
1263         final int[] data = mData;
1264         final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
1265         if (cookie < 0) {
1266             if (mXml != null) {
1267                 return mXml.getPooledString(
1268                     data[index+AssetManager.STYLE_DATA]);
1269             }
1270             return null;
1271         }
1272         return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
1273     }
1274 
1275     /** @hide */
TypedArray(Resources resources)1276     protected TypedArray(Resources resources) {
1277         mResources = resources;
1278         mMetrics = mResources.getDisplayMetrics();
1279         mAssets = mResources.getAssets();
1280     }
1281 
1282     @Override
toString()1283     public String toString() {
1284         return Arrays.toString(mData);
1285     }
1286 }
1287