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