Home | History | Annotate | Download | only in res
      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     private TypedValue mValue = new TypedValue();
     46 
     47     /**
     48      * Return the number of values in this array.
     49      */
     50     public int length() {
     51         return mLength;
     52     }
     53 
     54     /**
     55      * Return the number of indices in the array that actually have data.
     56      */
     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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    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 
    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 
    737     public String toString() {
    738         return Arrays.toString(mData);
    739     }
    740 }
    741