• 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.graphics.drawable.Drawable;
20 import android.util.AttributeSet;
21 import android.util.DisplayMetrics;
22 import android.util.Log;
23 import android.util.TypedValue;
24 
25 import com.android.internal.util.XmlUtils;
26 
27 import java.util.Arrays;
28 
29 /**
30  * Container for an array of values that were retrieved with
31  * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
32  * or {@link Resources#obtainAttributes}.  Be
33  * sure to call {@link #recycle} when done with them.
34  *
35  * The indices used to retrieve values from this structure correspond to
36  * the positions of the attributes given to obtainStyledAttributes.
37  */
38 public class TypedArray {
39     private final Resources mResources;
40     /*package*/ XmlBlock.Parser mXml;
41     /*package*/ int[] mRsrcs;
42     /*package*/ int[] mData;
43     /*package*/ int[] mIndices;
44     /*package*/ int mLength;
45     /*package*/ TypedValue mValue = new TypedValue();
46 
47     /**
48      * Return the number of values in this array.
49      */
length()50     public int length() {
51         return mLength;
52     }
53 
54     /**
55      * Return the number of indices in the array that actually have data.
56      */
getIndexCount()57     public int getIndexCount() {
58         return mIndices[0];
59     }
60 
61     /**
62      * Return an index in the array that has data.
63      *
64      * @param at The index you would like to returned, ranging from 0 to
65      * {@link #getIndexCount()}.
66      *
67      * @return The index at the given offset, which can be used with
68      * {@link #getValue} and related APIs.
69      */
getIndex(int at)70     public int getIndex(int at) {
71         return mIndices[1+at];
72     }
73 
74     /**
75      * Return the Resources object this array was loaded from.
76      */
getResources()77     public Resources getResources() {
78         return mResources;
79     }
80 
81     /**
82      * Retrieve the styled string value for the attribute at <var>index</var>.
83      *
84      * @param index Index of attribute to retrieve.
85      *
86      * @return CharSequence holding string data.  May be styled.  Returns
87      *         null if the attribute is not defined.
88      */
getText(int index)89     public CharSequence getText(int index) {
90         index *= AssetManager.STYLE_NUM_ENTRIES;
91         final int[] data = mData;
92         final int type = data[index+AssetManager.STYLE_TYPE];
93         if (type == TypedValue.TYPE_NULL) {
94             return null;
95         } else if (type == TypedValue.TYPE_STRING) {
96             return loadStringValueAt(index);
97         }
98 
99         TypedValue v = mValue;
100         if (getValueAt(index, v)) {
101             Log.w(Resources.TAG, "Converting to string: " + v);
102             return v.coerceToString();
103         }
104         Log.w(Resources.TAG, "getString of bad type: 0x"
105               + Integer.toHexString(type));
106         return null;
107     }
108 
109     /**
110      * Retrieve the string value for the attribute at <var>index</var>.
111      *
112      * @param index Index of attribute to retrieve.
113      *
114      * @return String holding string data.  Any styling information is
115      * removed.  Returns null if the attribute is not defined.
116      */
getString(int index)117     public String getString(int index) {
118         index *= AssetManager.STYLE_NUM_ENTRIES;
119         final int[] data = mData;
120         final int type = data[index+AssetManager.STYLE_TYPE];
121         if (type == TypedValue.TYPE_NULL) {
122             return null;
123         } else if (type == TypedValue.TYPE_STRING) {
124             return loadStringValueAt(index).toString();
125         }
126 
127         TypedValue v = mValue;
128         if (getValueAt(index, v)) {
129             Log.w(Resources.TAG, "Converting to string: " + v);
130             CharSequence cs = v.coerceToString();
131             return cs != null ? cs.toString() : null;
132         }
133         Log.w(Resources.TAG, "getString of bad type: 0x"
134               + Integer.toHexString(type));
135         return null;
136     }
137 
138     /**
139      * Retrieve the string value for the attribute at <var>index</var>, but
140      * only if that string comes from an immediate value in an XML file.  That
141      * is, this does not allow references to string resources, string
142      * attributes, or conversions from other types.  As such, this method
143      * will only return strings for TypedArray objects that come from
144      * attributes in an XML file.
145      *
146      * @param index Index of attribute to retrieve.
147      *
148      * @return String holding string data.  Any styling information is
149      * removed.  Returns null if the attribute is not defined or is not
150      * an immediate string value.
151      */
getNonResourceString(int index)152     public String getNonResourceString(int index) {
153         index *= AssetManager.STYLE_NUM_ENTRIES;
154         final int[] data = mData;
155         final int type = data[index+AssetManager.STYLE_TYPE];
156         if (type == TypedValue.TYPE_STRING) {
157             final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
158             if (cookie < 0) {
159                 return mXml.getPooledString(
160                     data[index+AssetManager.STYLE_DATA]).toString();
161             }
162         }
163         return null;
164     }
165 
166     /**
167      * @hide
168      * Retrieve the string value for the attribute at <var>index</var> that is
169      * not allowed to change with the given configurations.
170      *
171      * @param index Index of attribute to retrieve.
172      * @param allowedChangingConfigs Bit mask of configurations from
173      * ActivityInfo that are allowed to change.
174      *
175      * @return String holding string data.  Any styling information is
176      * removed.  Returns null if the attribute is not defined.
177      */
getNonConfigurationString(int index, int allowedChangingConfigs)178     public String getNonConfigurationString(int index, int allowedChangingConfigs) {
179         index *= AssetManager.STYLE_NUM_ENTRIES;
180         final int[] data = mData;
181         final int type = data[index+AssetManager.STYLE_TYPE];
182         if ((data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]&~allowedChangingConfigs) != 0) {
183             return null;
184         }
185         if (type == TypedValue.TYPE_NULL) {
186             return null;
187         } else if (type == TypedValue.TYPE_STRING) {
188             return loadStringValueAt(index).toString();
189         }
190 
191         TypedValue v = mValue;
192         if (getValueAt(index, v)) {
193             Log.w(Resources.TAG, "Converting to string: " + v);
194             CharSequence cs = v.coerceToString();
195             return cs != null ? cs.toString() : null;
196         }
197         Log.w(Resources.TAG, "getString of bad type: 0x"
198               + Integer.toHexString(type));
199         return null;
200     }
201 
202     /**
203      * Retrieve the boolean value for the attribute at <var>index</var>.
204      *
205      * @param index Index of attribute to retrieve.
206      * @param defValue Value to return if the attribute is not defined.
207      *
208      * @return Attribute boolean value, or defValue if not defined.
209      */
getBoolean(int index, boolean defValue)210     public boolean getBoolean(int index, boolean defValue) {
211         index *= AssetManager.STYLE_NUM_ENTRIES;
212         final int[] data = mData;
213         final int type = data[index+AssetManager.STYLE_TYPE];
214         if (type == TypedValue.TYPE_NULL) {
215             return defValue;
216         } else if (type >= TypedValue.TYPE_FIRST_INT
217             && type <= TypedValue.TYPE_LAST_INT) {
218             return data[index+AssetManager.STYLE_DATA] != 0;
219         }
220 
221         TypedValue v = mValue;
222         if (getValueAt(index, v)) {
223             Log.w(Resources.TAG, "Converting to boolean: " + v);
224             return XmlUtils.convertValueToBoolean(
225                 v.coerceToString(), defValue);
226         }
227         Log.w(Resources.TAG, "getBoolean of bad type: 0x"
228               + Integer.toHexString(type));
229         return defValue;
230     }
231 
232     /**
233      * Retrieve the integer value for the attribute at <var>index</var>.
234      *
235      * @param index Index of attribute to retrieve.
236      * @param defValue Value to return if the attribute is not defined.
237      *
238      * @return Attribute int value, or defValue if not defined.
239      */
getInt(int index, int defValue)240     public int getInt(int index, int defValue) {
241         index *= AssetManager.STYLE_NUM_ENTRIES;
242         final int[] data = mData;
243         final int type = data[index+AssetManager.STYLE_TYPE];
244         if (type == TypedValue.TYPE_NULL) {
245             return defValue;
246         } else if (type >= TypedValue.TYPE_FIRST_INT
247             && type <= TypedValue.TYPE_LAST_INT) {
248             return data[index+AssetManager.STYLE_DATA];
249         }
250 
251         TypedValue v = mValue;
252         if (getValueAt(index, v)) {
253             Log.w(Resources.TAG, "Converting to int: " + v);
254             return XmlUtils.convertValueToInt(
255                 v.coerceToString(), defValue);
256         }
257         Log.w(Resources.TAG, "getInt of bad type: 0x"
258               + Integer.toHexString(type));
259         return defValue;
260     }
261 
262     /**
263      * Retrieve the float value for the attribute at <var>index</var>.
264      *
265      * @param index Index of attribute to retrieve.
266      *
267      * @return Attribute float value, or defValue if not defined..
268      */
getFloat(int index, float defValue)269     public float getFloat(int index, float defValue) {
270         index *= AssetManager.STYLE_NUM_ENTRIES;
271         final int[] data = mData;
272         final int type = data[index+AssetManager.STYLE_TYPE];
273         if (type == TypedValue.TYPE_NULL) {
274             return defValue;
275         } else if (type == TypedValue.TYPE_FLOAT) {
276             return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
277         } else if (type >= TypedValue.TYPE_FIRST_INT
278             && type <= TypedValue.TYPE_LAST_INT) {
279             return data[index+AssetManager.STYLE_DATA];
280         }
281 
282         TypedValue v = mValue;
283         if (getValueAt(index, v)) {
284             Log.w(Resources.TAG, "Converting to float: " + v);
285             CharSequence str = v.coerceToString();
286             if (str != null) {
287                 return Float.parseFloat(str.toString());
288             }
289         }
290         Log.w(Resources.TAG, "getFloat of bad type: 0x"
291               + Integer.toHexString(type));
292         return defValue;
293     }
294 
295     /**
296      * Retrieve the color value for the attribute at <var>index</var>.  If
297      * the attribute references a color resource holding a complex
298      * {@link android.content.res.ColorStateList}, then the default color from
299      * the set is returned.
300      *
301      * @param index Index of attribute to retrieve.
302      * @param defValue Value to return if the attribute is not defined or
303      *                 not a resource.
304      *
305      * @return Attribute color value, or defValue if not defined.
306      */
getColor(int index, int defValue)307     public int getColor(int index, int defValue) {
308         index *= AssetManager.STYLE_NUM_ENTRIES;
309         final int[] data = mData;
310         final int type = data[index+AssetManager.STYLE_TYPE];
311         if (type == TypedValue.TYPE_NULL) {
312             return defValue;
313         } else if (type >= TypedValue.TYPE_FIRST_INT
314             && type <= TypedValue.TYPE_LAST_INT) {
315             return data[index+AssetManager.STYLE_DATA];
316         } else if (type == TypedValue.TYPE_STRING) {
317             final TypedValue value = mValue;
318             if (getValueAt(index, value)) {
319                 ColorStateList csl = mResources.loadColorStateList(
320                         value, value.resourceId);
321                 return csl.getDefaultColor();
322             }
323             return defValue;
324         }
325 
326         throw new UnsupportedOperationException("Can't convert to color: type=0x"
327                 + Integer.toHexString(type));
328     }
329 
330     /**
331      * Retrieve the ColorStateList for the attribute at <var>index</var>.
332      * The value may be either a single solid color or a reference to
333      * a color or complex {@link android.content.res.ColorStateList} description.
334      *
335      * @param index Index of attribute to retrieve.
336      *
337      * @return ColorStateList for the attribute, or null if not defined.
338      */
getColorStateList(int index)339     public ColorStateList getColorStateList(int index) {
340         final TypedValue value = mValue;
341         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
342             return mResources.loadColorStateList(value, value.resourceId);
343         }
344         return null;
345     }
346 
347     /**
348      * Retrieve the integer value for the attribute at <var>index</var>.
349      *
350      * @param index Index of attribute to retrieve.
351      * @param defValue Value to return if the attribute is not defined or
352      *                 not a resource.
353      *
354      * @return Attribute integer value, or defValue if not defined.
355      */
getInteger(int index, int defValue)356     public int getInteger(int index, int defValue) {
357         index *= AssetManager.STYLE_NUM_ENTRIES;
358         final int[] data = mData;
359         final int type = data[index+AssetManager.STYLE_TYPE];
360         if (type == TypedValue.TYPE_NULL) {
361             return defValue;
362         } else if (type >= TypedValue.TYPE_FIRST_INT
363             && type <= TypedValue.TYPE_LAST_INT) {
364             return data[index+AssetManager.STYLE_DATA];
365         }
366 
367         throw new UnsupportedOperationException("Can't convert to integer: type=0x"
368                 + Integer.toHexString(type));
369     }
370 
371     /**
372      * Retrieve a dimensional unit attribute at <var>index</var>.  Unit
373      * conversions are based on the current {@link DisplayMetrics}
374      * associated with the resources this {@link TypedArray} object
375      * came from.
376      *
377      * @param index Index of attribute to retrieve.
378      * @param defValue Value to return if the attribute is not defined or
379      *                 not a resource.
380      *
381      * @return Attribute dimension value multiplied by the appropriate
382      * metric, or defValue if not defined.
383      *
384      * @see #getDimensionPixelOffset
385      * @see #getDimensionPixelSize
386      */
getDimension(int index, float defValue)387     public float getDimension(int index, float defValue) {
388         index *= AssetManager.STYLE_NUM_ENTRIES;
389         final int[] data = mData;
390         final int type = data[index+AssetManager.STYLE_TYPE];
391         if (type == TypedValue.TYPE_NULL) {
392             return defValue;
393         } else if (type == TypedValue.TYPE_DIMENSION) {
394             return TypedValue.complexToDimension(
395                 data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
396         }
397 
398         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
399                 + Integer.toHexString(type));
400     }
401 
402     /**
403      * Retrieve a dimensional unit attribute at <var>index</var> for use
404      * as an offset in raw pixels.  This is the same as
405      * {@link #getDimension}, except the returned value is converted to
406      * integer pixels for you.  An offset conversion involves simply
407      * truncating the base value to an integer.
408      *
409      * @param index Index of attribute to retrieve.
410      * @param defValue Value to return if the attribute is not defined or
411      *                 not a resource.
412      *
413      * @return Attribute dimension value multiplied by the appropriate
414      * metric and truncated to integer pixels, or defValue if not defined.
415      *
416      * @see #getDimension
417      * @see #getDimensionPixelSize
418      */
getDimensionPixelOffset(int index, int defValue)419     public int getDimensionPixelOffset(int index, int defValue) {
420         index *= AssetManager.STYLE_NUM_ENTRIES;
421         final int[] data = mData;
422         final int type = data[index+AssetManager.STYLE_TYPE];
423         if (type == TypedValue.TYPE_NULL) {
424             return defValue;
425         } else if (type == TypedValue.TYPE_DIMENSION) {
426             return TypedValue.complexToDimensionPixelOffset(
427                 data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
428         }
429 
430         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
431                 + Integer.toHexString(type));
432     }
433 
434     /**
435      * Retrieve a dimensional unit attribute at <var>index</var> for use
436      * as a size in raw pixels.  This is the same as
437      * {@link #getDimension}, except the returned value is converted to
438      * integer pixels for use as a size.  A size conversion involves
439      * rounding the base value, and ensuring that a non-zero base value
440      * is at least one pixel in size.
441      *
442      * @param index Index of attribute to retrieve.
443      * @param defValue Value to return if the attribute is not defined or
444      *                 not a resource.
445      *
446      * @return Attribute dimension value multiplied by the appropriate
447      * metric and truncated to integer pixels, or defValue if not defined.
448      *
449      * @see #getDimension
450      * @see #getDimensionPixelOffset
451      */
getDimensionPixelSize(int index, int defValue)452     public int getDimensionPixelSize(int index, int defValue) {
453         index *= AssetManager.STYLE_NUM_ENTRIES;
454         final int[] data = mData;
455         final int type = data[index+AssetManager.STYLE_TYPE];
456         if (type == TypedValue.TYPE_NULL) {
457             return defValue;
458         } else if (type == TypedValue.TYPE_DIMENSION) {
459             return TypedValue.complexToDimensionPixelSize(
460                 data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
461         }
462 
463         throw new UnsupportedOperationException("Can't convert to dimension: type=0x"
464                 + Integer.toHexString(type));
465     }
466 
467     /**
468      * Special version of {@link #getDimensionPixelSize} for retrieving
469      * {@link android.view.ViewGroup}'s layout_width and layout_height
470      * attributes.  This is only here for performance reasons; applications
471      * should use {@link #getDimensionPixelSize}.
472      *
473      * @param index Index of the attribute to retrieve.
474      * @param name Textual name of attribute for error reporting.
475      *
476      * @return Attribute dimension value multiplied by the appropriate
477      * metric and truncated to integer pixels.
478      */
getLayoutDimension(int index, String name)479     public int getLayoutDimension(int index, String name) {
480         index *= AssetManager.STYLE_NUM_ENTRIES;
481         final int[] data = mData;
482         final int type = data[index+AssetManager.STYLE_TYPE];
483         if (type >= TypedValue.TYPE_FIRST_INT
484                 && type <= TypedValue.TYPE_LAST_INT) {
485             return data[index+AssetManager.STYLE_DATA];
486         } else if (type == TypedValue.TYPE_DIMENSION) {
487             return TypedValue.complexToDimensionPixelSize(
488                 data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
489         }
490 
491         throw new RuntimeException(getPositionDescription()
492                 + ": You must supply a " + name + " attribute.");
493     }
494 
495     /**
496      * Special version of {@link #getDimensionPixelSize} for retrieving
497      * {@link android.view.ViewGroup}'s layout_width and layout_height
498      * attributes.  This is only here for performance reasons; applications
499      * should use {@link #getDimensionPixelSize}.
500      *
501      * @param index Index of the attribute to retrieve.
502      * @param defValue The default value to return if this attribute is not
503      * default or contains the wrong type of data.
504      *
505      * @return Attribute dimension value multiplied by the appropriate
506      * metric and truncated to integer pixels.
507      */
getLayoutDimension(int index, int defValue)508     public int getLayoutDimension(int index, int defValue) {
509         index *= AssetManager.STYLE_NUM_ENTRIES;
510         final int[] data = mData;
511         final int type = data[index+AssetManager.STYLE_TYPE];
512         if (type >= TypedValue.TYPE_FIRST_INT
513                 && type <= TypedValue.TYPE_LAST_INT) {
514             return data[index+AssetManager.STYLE_DATA];
515         } else if (type == TypedValue.TYPE_DIMENSION) {
516             return TypedValue.complexToDimensionPixelSize(
517                 data[index+AssetManager.STYLE_DATA], mResources.mMetrics);
518         }
519 
520         return defValue;
521     }
522 
523     /**
524      * Retrieve a fractional unit attribute at <var>index</var>.
525      *
526      * @param index Index of attribute to retrieve.
527      * @param base The base value of this fraction.  In other words, a
528      *             standard fraction is multiplied by this value.
529      * @param pbase The parent base value of this fraction.  In other
530      *             words, a parent fraction (nn%p) is multiplied by this
531      *             value.
532      * @param defValue Value to return if the attribute is not defined or
533      *                 not a resource.
534      *
535      * @return Attribute fractional value multiplied by the appropriate
536      * base value, or defValue if not defined.
537      */
getFraction(int index, int base, int pbase, float defValue)538     public float getFraction(int index, int base, int pbase, float defValue) {
539         index *= AssetManager.STYLE_NUM_ENTRIES;
540         final int[] data = mData;
541         final int type = data[index+AssetManager.STYLE_TYPE];
542         if (type == TypedValue.TYPE_NULL) {
543             return defValue;
544         } else if (type == TypedValue.TYPE_FRACTION) {
545             return TypedValue.complexToFraction(
546                 data[index+AssetManager.STYLE_DATA], base, pbase);
547         }
548 
549         throw new UnsupportedOperationException("Can't convert to fraction: type=0x"
550                 + Integer.toHexString(type));
551     }
552 
553     /**
554      * Retrieve the resource identifier for the attribute at
555      * <var>index</var>.  Note that attribute resource as resolved when
556      * the overall {@link TypedArray} object is retrieved.  As a
557      * result, this function will return the resource identifier of the
558      * final resource value that was found, <em>not</em> necessarily the
559      * original resource that was specified by the attribute.
560      *
561      * @param index Index of attribute to retrieve.
562      * @param defValue Value to return if the attribute is not defined or
563      *                 not a resource.
564      *
565      * @return Attribute resource identifier, or defValue if not defined.
566      */
getResourceId(int index, int defValue)567     public int getResourceId(int index, int defValue) {
568         index *= AssetManager.STYLE_NUM_ENTRIES;
569         final int[] data = mData;
570         if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
571             final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
572             if (resid != 0) {
573                 return resid;
574             }
575         }
576         return defValue;
577     }
578 
579     /**
580      * Retrieve the Drawable for the attribute at <var>index</var>.  This
581      * gets the resource ID of the selected attribute, and uses
582      * {@link Resources#getDrawable Resources.getDrawable} of the owning
583      * Resources object to retrieve its Drawable.
584      *
585      * @param index Index of attribute to retrieve.
586      *
587      * @return Drawable for the attribute, or null if not defined.
588      */
getDrawable(int index)589     public Drawable getDrawable(int index) {
590         final TypedValue value = mValue;
591         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
592             if (false) {
593                 System.out.println("******************************************************************");
594                 System.out.println("Got drawable resource: type="
595                                    + value.type
596                                    + " str=" + value.string
597                                    + " int=0x" + Integer.toHexString(value.data)
598                                    + " cookie=" + value.assetCookie);
599                 System.out.println("******************************************************************");
600             }
601             return mResources.loadDrawable(value, value.resourceId);
602         }
603         return null;
604     }
605 
606     /**
607      * Retrieve the CharSequence[] for the attribute at <var>index</var>.
608      * This gets the resource ID of the selected attribute, and uses
609      * {@link Resources#getTextArray Resources.getTextArray} of the owning
610      * Resources object to retrieve its String[].
611      *
612      * @param index Index of attribute to retrieve.
613      *
614      * @return CharSequence[] for the attribute, or null if not defined.
615      */
getTextArray(int index)616     public CharSequence[] getTextArray(int index) {
617         final TypedValue value = mValue;
618         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
619             if (false) {
620                 System.out.println("******************************************************************");
621                 System.out.println("Got drawable resource: type="
622                                    + value.type
623                                    + " str=" + value.string
624                                    + " int=0x" + Integer.toHexString(value.data)
625                                    + " cookie=" + value.assetCookie);
626                 System.out.println("******************************************************************");
627             }
628             return mResources.getTextArray(value.resourceId);
629         }
630         return null;
631     }
632 
633     /**
634      * Retrieve the raw TypedValue for the attribute at <var>index</var>.
635      *
636      * @param index Index of attribute to retrieve.
637      * @param outValue TypedValue object in which to place the attribute's
638      *                 data.
639      *
640      * @return Returns true if the value was retrieved, else false.
641      */
getValue(int index, TypedValue outValue)642     public boolean getValue(int index, TypedValue outValue) {
643         return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
644     }
645 
646     /**
647      * Determines whether there is an attribute at <var>index</var>.
648      *
649      * @param index Index of attribute to retrieve.
650      *
651      * @return True if the attribute has a value, false otherwise.
652      */
hasValue(int index)653     public boolean hasValue(int index) {
654         index *= AssetManager.STYLE_NUM_ENTRIES;
655         final int[] data = mData;
656         final int type = data[index+AssetManager.STYLE_TYPE];
657         return type != TypedValue.TYPE_NULL;
658     }
659 
660     /**
661      * Retrieve the raw TypedValue for the attribute at <var>index</var>
662      * and return a temporary object holding its data.  This object is only
663      * valid until the next call on to {@link TypedArray}.
664      *
665      * @param index Index of attribute to retrieve.
666      *
667      * @return Returns a TypedValue object if the attribute is defined,
668      *         containing its data; otherwise returns null.  (You will not
669      *         receive a TypedValue whose type is TYPE_NULL.)
670      */
peekValue(int index)671     public TypedValue peekValue(int index) {
672         final TypedValue value = mValue;
673         if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
674             return value;
675         }
676         return null;
677     }
678 
679     /**
680      * Returns a message about the parser state suitable for printing error messages.
681      */
getPositionDescription()682     public String getPositionDescription() {
683         return mXml != null ? mXml.getPositionDescription() : "<internal>";
684     }
685 
686     /**
687      * Give back a previously retrieved StyledAttributes, for later re-use.
688      */
recycle()689     public void recycle() {
690         synchronized (mResources.mTmpValue) {
691             TypedArray cached = mResources.mCachedStyledAttributes;
692             if (cached == null || cached.mData.length < mData.length) {
693                 mXml = null;
694                 mResources.mCachedStyledAttributes = this;
695             }
696         }
697     }
698 
getValueAt(int index, TypedValue outValue)699     private boolean getValueAt(int index, TypedValue outValue) {
700         final int[] data = mData;
701         final int type = data[index+AssetManager.STYLE_TYPE];
702         if (type == TypedValue.TYPE_NULL) {
703             return false;
704         }
705         outValue.type = type;
706         outValue.data = data[index+AssetManager.STYLE_DATA];
707         outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
708         outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
709         outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS];
710         outValue.density = data[index+AssetManager.STYLE_DENSITY];
711         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
712         return true;
713     }
714 
loadStringValueAt(int index)715     private CharSequence loadStringValueAt(int index) {
716         final int[] data = mData;
717         final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
718         if (cookie < 0) {
719             if (mXml != null) {
720                 return mXml.getPooledString(
721                     data[index+AssetManager.STYLE_DATA]);
722             }
723             return null;
724         }
725         //System.out.println("Getting pooled from: " + v);
726         return mResources.mAssets.getPooledString(
727             cookie, data[index+AssetManager.STYLE_DATA]);
728     }
729 
TypedArray(Resources resources, int[] data, int[] indices, int len)730     /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
731         mResources = resources;
732         mData = data;
733         mIndices = indices;
734         mLength = len;
735     }
736 
toString()737     public String toString() {
738         return Arrays.toString(mData);
739     }
740 }
741