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