Home | History | Annotate | Download | only in res
      1 /*
      2  * Copyright (C) 2006 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.animation.Animator;
     20 import android.animation.StateListAnimator;
     21 import android.annotation.AnimRes;
     22 import android.annotation.AnyRes;
     23 import android.annotation.ArrayRes;
     24 import android.annotation.AttrRes;
     25 import android.annotation.BoolRes;
     26 import android.annotation.ColorInt;
     27 import android.annotation.ColorRes;
     28 import android.annotation.DimenRes;
     29 import android.annotation.DrawableRes;
     30 import android.annotation.FractionRes;
     31 import android.annotation.IntegerRes;
     32 import android.annotation.LayoutRes;
     33 import android.annotation.NonNull;
     34 import android.annotation.Nullable;
     35 import android.annotation.PluralsRes;
     36 import android.annotation.RawRes;
     37 import android.annotation.StringRes;
     38 import android.annotation.StyleRes;
     39 import android.annotation.StyleableRes;
     40 import android.annotation.XmlRes;
     41 import android.content.pm.ActivityInfo;
     42 import android.graphics.Movie;
     43 import android.graphics.drawable.Drawable;
     44 import android.graphics.drawable.Drawable.ConstantState;
     45 import android.graphics.drawable.DrawableInflater;
     46 import android.os.Build;
     47 import android.os.Bundle;
     48 import android.util.AttributeSet;
     49 import android.util.DisplayMetrics;
     50 import android.util.Log;
     51 import android.util.LongSparseArray;
     52 import android.util.Pools.SynchronizedPool;
     53 import android.util.TypedValue;
     54 import android.view.DisplayAdjustments;
     55 import android.view.ViewDebug;
     56 import android.view.ViewHierarchyEncoder;
     57 
     58 import com.android.internal.annotations.VisibleForTesting;
     59 import com.android.internal.util.GrowingArrayUtils;
     60 import com.android.internal.util.XmlUtils;
     61 
     62 import org.xmlpull.v1.XmlPullParser;
     63 import org.xmlpull.v1.XmlPullParserException;
     64 
     65 import java.io.IOException;
     66 import java.io.InputStream;
     67 import java.lang.ref.WeakReference;
     68 import java.util.ArrayList;
     69 
     70 /**
     71  * Class for accessing an application's resources.  This sits on top of the
     72  * asset manager of the application (accessible through {@link #getAssets}) and
     73  * provides a high-level API for getting typed data from the assets.
     74  *
     75  * <p>The Android resource system keeps track of all non-code assets associated with an
     76  * application. You can use this class to access your application's resources. You can generally
     77  * acquire the {@link android.content.res.Resources} instance associated with your application
     78  * with {@link android.content.Context#getResources getResources()}.</p>
     79  *
     80  * <p>The Android SDK tools compile your application's resources into the application binary
     81  * at build time.  To use a resource, you must install it correctly in the source tree (inside
     82  * your project's {@code res/} directory) and build your application.  As part of the build
     83  * process, the SDK tools generate symbols for each resource, which you can use in your application
     84  * code to access the resources.</p>
     85  *
     86  * <p>Using application resources makes it easy to update various characteristics of your
     87  * application without modifying code, and&mdash;by providing sets of alternative
     88  * resources&mdash;enables you to optimize your application for a variety of device configurations
     89  * (such as for different languages and screen sizes). This is an important aspect of developing
     90  * Android applications that are compatible on different types of devices.</p>
     91  *
     92  * <p>For more information about using resources, see the documentation about <a
     93  * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
     94  */
     95 public class Resources {
     96     static final String TAG = "Resources";
     97 
     98     private static final Object sSync = new Object();
     99 
    100     // Used by BridgeResources in layoutlib
    101     static Resources mSystem = null;
    102 
    103     private ResourcesImpl mResourcesImpl;
    104 
    105     // Pool of TypedArrays targeted to this Resources object.
    106     final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
    107 
    108     /** Used to inflate drawable objects from XML. */
    109     private DrawableInflater mDrawableInflater;
    110 
    111     /** Lock object used to protect access to {@link #mTmpValue}. */
    112     private final Object mTmpValueLock = new Object();
    113 
    114     /** Single-item pool used to minimize TypedValue allocations. */
    115     private TypedValue mTmpValue = new TypedValue();
    116 
    117     final ClassLoader mClassLoader;
    118 
    119     /**
    120      * WeakReferences to Themes that were constructed from this Resources object.
    121      * We keep track of these in case our underlying implementation is changed, in which case
    122      * the Themes must also get updated ThemeImpls.
    123      */
    124     private final ArrayList<WeakReference<Theme>> mThemeRefs = new ArrayList<>();
    125 
    126     /**
    127      * Returns the most appropriate default theme for the specified target SDK version.
    128      * <ul>
    129      * <li>Below API 11: Gingerbread
    130      * <li>APIs 12 thru 14: Holo
    131      * <li>APIs 15 thru 23: Device default dark
    132      * <li>APIs 24 and above: Device default light with dark action bar
    133      * </ul>
    134      *
    135      * @param curTheme The current theme, or 0 if not specified.
    136      * @param targetSdkVersion The target SDK version.
    137      * @return A theme resource identifier
    138      * @hide
    139      */
    140     public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
    141         return selectSystemTheme(curTheme, targetSdkVersion,
    142                 com.android.internal.R.style.Theme,
    143                 com.android.internal.R.style.Theme_Holo,
    144                 com.android.internal.R.style.Theme_DeviceDefault,
    145                 com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
    146     }
    147 
    148     /** @hide */
    149     public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
    150             int dark, int deviceDefault) {
    151         if (curTheme != 0) {
    152             return curTheme;
    153         }
    154         if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
    155             return orig;
    156         }
    157         if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    158             return holo;
    159         }
    160         if (targetSdkVersion < Build.VERSION_CODES.N) {
    161             return dark;
    162         }
    163         return deviceDefault;
    164     }
    165 
    166     /**
    167      * Return a global shared Resources object that provides access to only
    168      * system resources (no application resources), and is not configured for
    169      * the current screen (can not use dimension units, does not change based
    170      * on orientation, etc).
    171      */
    172     public static Resources getSystem() {
    173         synchronized (sSync) {
    174             Resources ret = mSystem;
    175             if (ret == null) {
    176                 ret = new Resources();
    177                 mSystem = ret;
    178             }
    179             return ret;
    180         }
    181     }
    182 
    183     /**
    184      * This exception is thrown by the resource APIs when a requested resource
    185      * can not be found.
    186      */
    187     public static class NotFoundException extends RuntimeException {
    188         public NotFoundException() {
    189         }
    190 
    191         public NotFoundException(String name) {
    192             super(name);
    193         }
    194 
    195         public NotFoundException(String name, Exception cause) {
    196             super(name, cause);
    197         }
    198     }
    199 
    200     /**
    201      * Create a new Resources object on top of an existing set of assets in an
    202      * AssetManager.
    203      *
    204      * @deprecated Resources should not be constructed by apps.
    205      * See {@link android.content.Context#createConfigurationContext(Configuration)}.
    206      *
    207      * @param assets Previously created AssetManager.
    208      * @param metrics Current display metrics to consider when
    209      *                selecting/computing resource values.
    210      * @param config Desired device configuration to consider when
    211      *               selecting/computing resource values (optional).
    212      */
    213     @Deprecated
    214     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
    215         this(null);
    216         mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments());
    217     }
    218 
    219     /**
    220      * Creates a new Resources object with CompatibilityInfo.
    221      *
    222      * @param classLoader class loader for the package used to load custom
    223      *                    resource classes, may be {@code null} to use system
    224      *                    class loader
    225      * @hide
    226      */
    227     public Resources(@Nullable ClassLoader classLoader) {
    228         mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
    229     }
    230 
    231     /**
    232      * Only for creating the System resources.
    233      */
    234     private Resources() {
    235         this(null);
    236 
    237         final DisplayMetrics metrics = new DisplayMetrics();
    238         metrics.setToDefaults();
    239 
    240         final Configuration config = new Configuration();
    241         config.setToDefaults();
    242 
    243         mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
    244                 new DisplayAdjustments());
    245     }
    246 
    247     /**
    248      * Set the underlying implementation (containing all the resources and caches)
    249      * and updates all Theme references to new implementations as well.
    250      * @hide
    251      */
    252     public void setImpl(ResourcesImpl impl) {
    253         if (impl == mResourcesImpl) {
    254             return;
    255         }
    256 
    257         mResourcesImpl = impl;
    258 
    259         // Create new ThemeImpls that are identical to the ones we have.
    260         synchronized (mThemeRefs) {
    261             final int count = mThemeRefs.size();
    262             for (int i = 0; i < count; i++) {
    263                 WeakReference<Theme> weakThemeRef = mThemeRefs.get(i);
    264                 Theme theme = weakThemeRef != null ? weakThemeRef.get() : null;
    265                 if (theme != null) {
    266                     theme.setImpl(mResourcesImpl.newThemeImpl(theme.getKey()));
    267                 }
    268             }
    269         }
    270     }
    271 
    272     /**
    273      * @hide
    274      */
    275     public ResourcesImpl getImpl() {
    276         return mResourcesImpl;
    277     }
    278 
    279     /**
    280      * @hide
    281      */
    282     public ClassLoader getClassLoader() {
    283         return mClassLoader;
    284     }
    285 
    286     /**
    287      * @return the inflater used to create drawable objects
    288      * @hide Pending API finalization.
    289      */
    290     public final DrawableInflater getDrawableInflater() {
    291         if (mDrawableInflater == null) {
    292             mDrawableInflater = new DrawableInflater(this, mClassLoader);
    293         }
    294         return mDrawableInflater;
    295     }
    296 
    297     /**
    298      * Used by AnimatorInflater.
    299      *
    300      * @hide
    301      */
    302     public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
    303         return mResourcesImpl.getAnimatorCache();
    304     }
    305 
    306     /**
    307      * Used by AnimatorInflater.
    308      *
    309      * @hide
    310      */
    311     public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
    312         return mResourcesImpl.getStateListAnimatorCache();
    313     }
    314 
    315     /**
    316      * Return the string value associated with a particular resource ID.  The
    317      * returned object will be a String if this is a plain string; it will be
    318      * some other type of CharSequence if it is styled.
    319      * {@more}
    320      *
    321      * @param id The desired resource identifier, as generated by the aapt
    322      *           tool. This integer encodes the package, type, and resource
    323      *           entry. The value 0 is an invalid identifier.
    324      *
    325      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    326      *
    327      * @return CharSequence The string data associated with the resource, plus
    328      *         possibly styled text information.
    329      */
    330     @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
    331         CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
    332         if (res != null) {
    333             return res;
    334         }
    335         throw new NotFoundException("String resource ID #0x"
    336                                     + Integer.toHexString(id));
    337     }
    338 
    339     /**
    340      * Returns the character sequence necessary for grammatically correct pluralization
    341      * of the given resource ID for the given quantity.
    342      * Note that the character sequence is selected based solely on grammatical necessity,
    343      * and that such rules differ between languages. Do not assume you know which string
    344      * will be returned for a given quantity. See
    345      * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
    346      * for more detail.
    347      *
    348      * @param id The desired resource identifier, as generated by the aapt
    349      *           tool. This integer encodes the package, type, and resource
    350      *           entry. The value 0 is an invalid identifier.
    351      * @param quantity The number used to get the correct string for the current language's
    352      *           plural rules.
    353      *
    354      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    355      *
    356      * @return CharSequence The string data associated with the resource, plus
    357      *         possibly styled text information.
    358      */
    359     @NonNull
    360     public CharSequence getQuantityText(@PluralsRes int id, int quantity)
    361             throws NotFoundException {
    362         return mResourcesImpl.getQuantityText(id, quantity);
    363     }
    364 
    365     /**
    366      * Return the string value associated with a particular resource ID.  It
    367      * will be stripped of any styled text information.
    368      * {@more}
    369      *
    370      * @param id The desired resource identifier, as generated by the aapt
    371      *           tool. This integer encodes the package, type, and resource
    372      *           entry. The value 0 is an invalid identifier.
    373      *
    374      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    375      *
    376      * @return String The string data associated with the resource,
    377      *         stripped of styled text information.
    378      */
    379     @NonNull
    380     public String getString(@StringRes int id) throws NotFoundException {
    381         return getText(id).toString();
    382     }
    383 
    384 
    385     /**
    386      * Return the string value associated with a particular resource ID,
    387      * substituting the format arguments as defined in {@link java.util.Formatter}
    388      * and {@link java.lang.String#format}. It will be stripped of any styled text
    389      * information.
    390      * {@more}
    391      *
    392      * @param id The desired resource identifier, as generated by the aapt
    393      *           tool. This integer encodes the package, type, and resource
    394      *           entry. The value 0 is an invalid identifier.
    395      *
    396      * @param formatArgs The format arguments that will be used for substitution.
    397      *
    398      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    399      *
    400      * @return String The string data associated with the resource,
    401      *         stripped of styled text information.
    402      */
    403     @NonNull
    404     public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
    405         final String raw = getString(id);
    406         return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
    407                 formatArgs);
    408     }
    409 
    410     /**
    411      * Formats the string necessary for grammatically correct pluralization
    412      * of the given resource ID for the given quantity, using the given arguments.
    413      * Note that the string is selected based solely on grammatical necessity,
    414      * and that such rules differ between languages. Do not assume you know which string
    415      * will be returned for a given quantity. See
    416      * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
    417      * for more detail.
    418      *
    419      * <p>Substitution of format arguments works as if using
    420      * {@link java.util.Formatter} and {@link java.lang.String#format}.
    421      * The resulting string will be stripped of any styled text information.
    422      *
    423      * @param id The desired resource identifier, as generated by the aapt
    424      *           tool. This integer encodes the package, type, and resource
    425      *           entry. The value 0 is an invalid identifier.
    426      * @param quantity The number used to get the correct string for the current language's
    427      *           plural rules.
    428      * @param formatArgs The format arguments that will be used for substitution.
    429      *
    430      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    431      *
    432      * @return String The string data associated with the resource,
    433      * stripped of styled text information.
    434      */
    435     @NonNull
    436     public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
    437             throws NotFoundException {
    438         String raw = getQuantityText(id, quantity).toString();
    439         return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
    440                 formatArgs);
    441     }
    442 
    443     /**
    444      * Returns the string necessary for grammatically correct pluralization
    445      * of the given resource ID for the given quantity.
    446      * Note that the string is selected based solely on grammatical necessity,
    447      * and that such rules differ between languages. Do not assume you know which string
    448      * will be returned for a given quantity. See
    449      * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
    450      * for more detail.
    451      *
    452      * @param id The desired resource identifier, as generated by the aapt
    453      *           tool. This integer encodes the package, type, and resource
    454      *           entry. The value 0 is an invalid identifier.
    455      * @param quantity The number used to get the correct string for the current language's
    456      *           plural rules.
    457      *
    458      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    459      *
    460      * @return String The string data associated with the resource,
    461      * stripped of styled text information.
    462      */
    463     @NonNull
    464     public String getQuantityString(@PluralsRes int id, int quantity) throws NotFoundException {
    465         return getQuantityText(id, quantity).toString();
    466     }
    467 
    468     /**
    469      * Return the string value associated with a particular resource ID.  The
    470      * returned object will be a String if this is a plain string; it will be
    471      * some other type of CharSequence if it is styled.
    472      *
    473      * @param id The desired resource identifier, as generated by the aapt
    474      *           tool. This integer encodes the package, type, and resource
    475      *           entry. The value 0 is an invalid identifier.
    476      *
    477      * @param def The default CharSequence to return.
    478      *
    479      * @return CharSequence The string data associated with the resource, plus
    480      *         possibly styled text information, or def if id is 0 or not found.
    481      */
    482     public CharSequence getText(@StringRes int id, CharSequence def) {
    483         CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null;
    484         return res != null ? res : def;
    485     }
    486 
    487     /**
    488      * Return the styled text array associated with a particular resource ID.
    489      *
    490      * @param id The desired resource identifier, as generated by the aapt
    491      *           tool. This integer encodes the package, type, and resource
    492      *           entry. The value 0 is an invalid identifier.
    493      *
    494      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    495      *
    496      * @return The styled text array associated with the resource.
    497      */
    498     @NonNull
    499     public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
    500         CharSequence[] res = mResourcesImpl.getAssets().getResourceTextArray(id);
    501         if (res != null) {
    502             return res;
    503         }
    504         throw new NotFoundException("Text array resource ID #0x" + Integer.toHexString(id));
    505     }
    506 
    507     /**
    508      * Return the string array associated with a particular resource ID.
    509      *
    510      * @param id The desired resource identifier, as generated by the aapt
    511      *           tool. This integer encodes the package, type, and resource
    512      *           entry. The value 0 is an invalid identifier.
    513      *
    514      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    515      *
    516      * @return The string array associated with the resource.
    517      */
    518     @NonNull
    519     public String[] getStringArray(@ArrayRes int id)
    520             throws NotFoundException {
    521         String[] res = mResourcesImpl.getAssets().getResourceStringArray(id);
    522         if (res != null) {
    523             return res;
    524         }
    525         throw new NotFoundException("String array resource ID #0x" + Integer.toHexString(id));
    526     }
    527 
    528     /**
    529      * Return the int array associated with a particular resource ID.
    530      *
    531      * @param id The desired resource identifier, as generated by the aapt
    532      *           tool. This integer encodes the package, type, and resource
    533      *           entry. The value 0 is an invalid identifier.
    534      *
    535      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    536      *
    537      * @return The int array associated with the resource.
    538      */
    539     @NonNull
    540     public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
    541         int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
    542         if (res != null) {
    543             return res;
    544         }
    545         throw new NotFoundException("Int array resource ID #0x" + Integer.toHexString(id));
    546     }
    547 
    548     /**
    549      * Return an array of heterogeneous values.
    550      *
    551      * @param id The desired resource identifier, as generated by the aapt
    552      *           tool. This integer encodes the package, type, and resource
    553      *           entry. The value 0 is an invalid identifier.
    554      *
    555      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    556      *
    557      * @return Returns a TypedArray holding an array of the array values.
    558      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
    559      * when done with it.
    560      */
    561     @NonNull
    562     public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
    563         final ResourcesImpl impl = mResourcesImpl;
    564         int len = impl.getAssets().getArraySize(id);
    565         if (len < 0) {
    566             throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
    567         }
    568 
    569         TypedArray array = TypedArray.obtain(this, len);
    570         array.mLength = impl.getAssets().retrieveArray(id, array.mData);
    571         array.mIndices[0] = 0;
    572 
    573         return array;
    574     }
    575 
    576     /**
    577      * Retrieve a dimensional for a particular resource ID.  Unit
    578      * conversions are based on the current {@link DisplayMetrics} associated
    579      * with the resources.
    580      *
    581      * @param id The desired resource identifier, as generated by the aapt
    582      *           tool. This integer encodes the package, type, and resource
    583      *           entry. The value 0 is an invalid identifier.
    584      *
    585      * @return Resource dimension value multiplied by the appropriate
    586      * metric.
    587      *
    588      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    589      *
    590      * @see #getDimensionPixelOffset
    591      * @see #getDimensionPixelSize
    592      */
    593     public float getDimension(@DimenRes int id) throws NotFoundException {
    594         final TypedValue value = obtainTempTypedValue();
    595         try {
    596             final ResourcesImpl impl = mResourcesImpl;
    597             impl.getValue(id, value, true);
    598             if (value.type == TypedValue.TYPE_DIMENSION) {
    599                 return TypedValue.complexToDimension(value.data, impl.getDisplayMetrics());
    600             }
    601             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
    602                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
    603         } finally {
    604             releaseTempTypedValue(value);
    605         }
    606     }
    607 
    608     /**
    609      * Retrieve a dimensional for a particular resource ID for use
    610      * as an offset in raw pixels.  This is the same as
    611      * {@link #getDimension}, except the returned value is converted to
    612      * integer pixels for you.  An offset conversion involves simply
    613      * truncating the base value to an integer.
    614      *
    615      * @param id The desired resource identifier, as generated by the aapt
    616      *           tool. This integer encodes the package, type, and resource
    617      *           entry. The value 0 is an invalid identifier.
    618      *
    619      * @return Resource dimension value multiplied by the appropriate
    620      * metric and truncated to integer pixels.
    621      *
    622      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    623      *
    624      * @see #getDimension
    625      * @see #getDimensionPixelSize
    626      */
    627     public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
    628         final TypedValue value = obtainTempTypedValue();
    629         try {
    630             final ResourcesImpl impl = mResourcesImpl;
    631             impl.getValue(id, value, true);
    632             if (value.type == TypedValue.TYPE_DIMENSION) {
    633                 return TypedValue.complexToDimensionPixelOffset(value.data,
    634                         impl.getDisplayMetrics());
    635             }
    636             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
    637                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
    638         } finally {
    639             releaseTempTypedValue(value);
    640         }
    641     }
    642 
    643     /**
    644      * Retrieve a dimensional for a particular resource ID for use
    645      * as a size in raw pixels.  This is the same as
    646      * {@link #getDimension}, except the returned value is converted to
    647      * integer pixels for use as a size.  A size conversion involves
    648      * rounding the base value, and ensuring that a non-zero base value
    649      * is at least one pixel in size.
    650      *
    651      * @param id The desired resource identifier, as generated by the aapt
    652      *           tool. This integer encodes the package, type, and resource
    653      *           entry. The value 0 is an invalid identifier.
    654      *
    655      * @return Resource dimension value multiplied by the appropriate
    656      * metric and truncated to integer pixels.
    657      *
    658      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    659      *
    660      * @see #getDimension
    661      * @see #getDimensionPixelOffset
    662      */
    663     public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
    664         final TypedValue value = obtainTempTypedValue();
    665         try {
    666             final ResourcesImpl impl = mResourcesImpl;
    667             impl.getValue(id, value, true);
    668             if (value.type == TypedValue.TYPE_DIMENSION) {
    669                 return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics());
    670             }
    671             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
    672                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
    673         } finally {
    674             releaseTempTypedValue(value);
    675         }
    676     }
    677 
    678     /**
    679      * Retrieve a fractional unit for a particular resource ID.
    680      *
    681      * @param id The desired resource identifier, as generated by the aapt
    682      *           tool. This integer encodes the package, type, and resource
    683      *           entry. The value 0 is an invalid identifier.
    684      * @param base The base value of this fraction.  In other words, a
    685      *             standard fraction is multiplied by this value.
    686      * @param pbase The parent base value of this fraction.  In other
    687      *             words, a parent fraction (nn%p) is multiplied by this
    688      *             value.
    689      *
    690      * @return Attribute fractional value multiplied by the appropriate
    691      * base value.
    692      *
    693      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    694      */
    695     public float getFraction(@FractionRes int id, int base, int pbase) {
    696         final TypedValue value = obtainTempTypedValue();
    697         try {
    698             mResourcesImpl.getValue(id, value, true);
    699             if (value.type == TypedValue.TYPE_FRACTION) {
    700                 return TypedValue.complexToFraction(value.data, base, pbase);
    701             }
    702             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
    703                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
    704         } finally {
    705             releaseTempTypedValue(value);
    706         }
    707     }
    708 
    709     /**
    710      * Return a drawable object associated with a particular resource ID.
    711      * Various types of objects will be returned depending on the underlying
    712      * resource -- for example, a solid color, PNG image, scalable image, etc.
    713      * The Drawable API hides these implementation details.
    714      *
    715      * <p class="note"><strong>Note:</strong> Prior to
    716      * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function
    717      * would not correctly retrieve the final configuration density when
    718      * the resource ID passed here is an alias to another Drawable resource.
    719      * This means that if the density configuration of the alias resource
    720      * is different than the actual resource, the density of the returned
    721      * Drawable would be incorrect, resulting in bad scaling. To work
    722      * around this, you can instead manually resolve the aliased reference
    723      * by using {@link #getValue(int, TypedValue, boolean)} and passing
    724      * {@code true} for {@code resolveRefs}. The resulting
    725      * {@link TypedValue#resourceId} value may be passed to this method.</p>
    726      *
    727      * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
    728      * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
    729      * or {@link #getDrawable(int, Theme)} passing the desired theme.</p>
    730      *
    731      * @param id The desired resource identifier, as generated by the aapt
    732      *           tool. This integer encodes the package, type, and resource
    733      *           entry. The value 0 is an invalid identifier.
    734      * @return Drawable An object that can be used to draw this resource.
    735      * @throws NotFoundException Throws NotFoundException if the given ID does
    736      *         not exist.
    737      * @see #getDrawable(int, Theme)
    738      * @deprecated Use {@link #getDrawable(int, Theme)} instead.
    739      */
    740     @Deprecated
    741     public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
    742         final Drawable d = getDrawable(id, null);
    743         if (d != null && d.canApplyTheme()) {
    744             Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
    745                     + "attributes! Consider using Resources.getDrawable(int, Theme) or "
    746                     + "Context.getDrawable(int).", new RuntimeException());
    747         }
    748         return d;
    749     }
    750 
    751     /**
    752      * Return a drawable object associated with a particular resource ID and
    753      * styled for the specified theme. Various types of objects will be
    754      * returned depending on the underlying resource -- for example, a solid
    755      * color, PNG image, scalable image, etc.
    756      *
    757      * @param id The desired resource identifier, as generated by the aapt
    758      *           tool. This integer encodes the package, type, and resource
    759      *           entry. The value 0 is an invalid identifier.
    760      * @param theme The theme used to style the drawable attributes, may be {@code null}.
    761      * @return Drawable An object that can be used to draw this resource.
    762      * @throws NotFoundException Throws NotFoundException if the given ID does
    763      *         not exist.
    764      */
    765     public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
    766             throws NotFoundException {
    767         final TypedValue value = obtainTempTypedValue();
    768         try {
    769             final ResourcesImpl impl = mResourcesImpl;
    770             impl.getValue(id, value, true);
    771             return impl.loadDrawable(this, value, id, theme, true);
    772         } finally {
    773             releaseTempTypedValue(value);
    774         }
    775     }
    776 
    777     /**
    778      * Return a drawable object associated with a particular resource ID for the
    779      * given screen density in DPI. This will set the drawable's density to be
    780      * the device's density multiplied by the ratio of actual drawable density
    781      * to requested density. This allows the drawable to be scaled up to the
    782      * correct size if needed. Various types of objects will be returned
    783      * depending on the underlying resource -- for example, a solid color, PNG
    784      * image, scalable image, etc. The Drawable API hides these implementation
    785      * details.
    786      *
    787      * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
    788      * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
    789      * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired
    790      * theme.</p>
    791      *
    792      * @param id The desired resource identifier, as generated by the aapt tool.
    793      *            This integer encodes the package, type, and resource entry.
    794      *            The value 0 is an invalid identifier.
    795      * @param density the desired screen density indicated by the resource as
    796      *            found in {@link DisplayMetrics}.
    797      * @return Drawable An object that can be used to draw this resource.
    798      * @throws NotFoundException Throws NotFoundException if the given ID does
    799      *             not exist.
    800      * @see #getDrawableForDensity(int, int, Theme)
    801      * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
    802      */
    803     @Deprecated
    804     public Drawable getDrawableForDensity(@DrawableRes int id, int density)
    805             throws NotFoundException {
    806         return getDrawableForDensity(id, density, null);
    807     }
    808 
    809     /**
    810      * Return a drawable object associated with a particular resource ID for the
    811      * given screen density in DPI and styled for the specified theme.
    812      *
    813      * @param id The desired resource identifier, as generated by the aapt tool.
    814      *            This integer encodes the package, type, and resource entry.
    815      *            The value 0 is an invalid identifier.
    816      * @param density The desired screen density indicated by the resource as
    817      *            found in {@link DisplayMetrics}.
    818      * @param theme The theme used to style the drawable attributes, may be {@code null}.
    819      * @return Drawable An object that can be used to draw this resource.
    820      * @throws NotFoundException Throws NotFoundException if the given ID does
    821      *             not exist.
    822      */
    823     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
    824         final TypedValue value = obtainTempTypedValue();
    825         try {
    826             final ResourcesImpl impl = mResourcesImpl;
    827             impl.getValueForDensity(id, density, value, true);
    828 
    829             // If the drawable's XML lives in our current density qualifier,
    830             // it's okay to use a scaled version from the cache. Otherwise, we
    831             // need to actually load the drawable from XML.
    832             final DisplayMetrics metrics = impl.getDisplayMetrics();
    833             final boolean useCache = value.density == metrics.densityDpi;
    834 
    835             /*
    836              * Pretend the requested density is actually the display density. If
    837              * the drawable returned is not the requested density, then force it
    838              * to be scaled later by dividing its density by the ratio of
    839              * requested density to actual device density. Drawables that have
    840              * undefined density or no density don't need to be handled here.
    841              */
    842             if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
    843                 if (value.density == density) {
    844                     value.density = metrics.densityDpi;
    845                 } else {
    846                     value.density = (value.density * metrics.densityDpi) / density;
    847                 }
    848             }
    849             return impl.loadDrawable(this, value, id, theme, useCache);
    850         } finally {
    851             releaseTempTypedValue(value);
    852         }
    853     }
    854 
    855     @NonNull
    856     Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
    857             throws NotFoundException {
    858         return mResourcesImpl.loadDrawable(this, value, id, theme, true);
    859     }
    860 
    861     /**
    862      * Return a movie object associated with the particular resource ID.
    863      * @param id The desired resource identifier, as generated by the aapt
    864      *           tool. This integer encodes the package, type, and resource
    865      *           entry. The value 0 is an invalid identifier.
    866      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
    867      *
    868      */
    869     public Movie getMovie(@RawRes int id) throws NotFoundException {
    870         final InputStream is = openRawResource(id);
    871         final Movie movie = Movie.decodeStream(is);
    872         try {
    873             is.close();
    874         } catch (IOException e) {
    875             // No one cares.
    876         }
    877         return movie;
    878     }
    879 
    880     /**
    881      * Returns a color integer associated with a particular resource ID. If the
    882      * resource holds a complex {@link ColorStateList}, then the default color
    883      * from the set is returned.
    884      *
    885      * @param id The desired resource identifier, as generated by the aapt
    886      *           tool. This integer encodes the package, type, and resource
    887      *           entry. The value 0 is an invalid identifier.
    888      *
    889      * @throws NotFoundException Throws NotFoundException if the given ID does
    890      *         not exist.
    891      *
    892      * @return A single color value in the form 0xAARRGGBB.
    893      * @deprecated Use {@link #getColor(int, Theme)} instead.
    894      */
    895     @ColorInt
    896     @Deprecated
    897     public int getColor(@ColorRes int id) throws NotFoundException {
    898         return getColor(id, null);
    899     }
    900 
    901     /**
    902      * Returns a themed color integer associated with a particular resource ID.
    903      * If the resource holds a complex {@link ColorStateList}, then the default
    904      * color from the set is returned.
    905      *
    906      * @param id The desired resource identifier, as generated by the aapt
    907      *           tool. This integer encodes the package, type, and resource
    908      *           entry. The value 0 is an invalid identifier.
    909      * @param theme The theme used to style the color attributes, may be
    910      *              {@code null}.
    911      *
    912      * @throws NotFoundException Throws NotFoundException if the given ID does
    913      *         not exist.
    914      *
    915      * @return A single color value in the form 0xAARRGGBB.
    916      */
    917     @ColorInt
    918     public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
    919         final TypedValue value = obtainTempTypedValue();
    920         try {
    921             final ResourcesImpl impl = mResourcesImpl;
    922             impl.getValue(id, value, true);
    923             if (value.type >= TypedValue.TYPE_FIRST_INT
    924                     && value.type <= TypedValue.TYPE_LAST_INT) {
    925                 return value.data;
    926             } else if (value.type != TypedValue.TYPE_STRING) {
    927                 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
    928                         + " type #0x" + Integer.toHexString(value.type) + " is not valid");
    929             }
    930 
    931             final ColorStateList csl = impl.loadColorStateList(this, value, id, theme);
    932             return csl.getDefaultColor();
    933         } finally {
    934             releaseTempTypedValue(value);
    935         }
    936     }
    937 
    938     /**
    939      * Returns a color state list associated with a particular resource ID. The
    940      * resource may contain either a single raw color value or a complex
    941      * {@link ColorStateList} holding multiple possible colors.
    942      *
    943      * @param id The desired resource identifier of a {@link ColorStateList},
    944      *           as generated by the aapt tool. This integer encodes the
    945      *           package, type, and resource entry. The value 0 is an invalid
    946      *           identifier.
    947      *
    948      * @throws NotFoundException Throws NotFoundException if the given ID does
    949      *         not exist.
    950      *
    951      * @return A ColorStateList object containing either a single solid color
    952      *         or multiple colors that can be selected based on a state.
    953      * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
    954      */
    955     @Nullable
    956     @Deprecated
    957     public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
    958         final ColorStateList csl = getColorStateList(id, null);
    959         if (csl != null && csl.canApplyTheme()) {
    960             Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
    961                     + "unresolved theme attributes! Consider using "
    962                     + "Resources.getColorStateList(int, Theme) or "
    963                     + "Context.getColorStateList(int).", new RuntimeException());
    964         }
    965         return csl;
    966     }
    967 
    968     /**
    969      * Returns a themed color state list associated with a particular resource
    970      * ID. The resource may contain either a single raw color value or a
    971      * complex {@link ColorStateList} holding multiple possible colors.
    972      *
    973      * @param id The desired resource identifier of a {@link ColorStateList},
    974      *           as generated by the aapt tool. This integer encodes the
    975      *           package, type, and resource entry. The value 0 is an invalid
    976      *           identifier.
    977      * @param theme The theme used to style the color attributes, may be
    978      *              {@code null}.
    979      *
    980      * @throws NotFoundException Throws NotFoundException if the given ID does
    981      *         not exist.
    982      *
    983      * @return A themed ColorStateList object containing either a single solid
    984      *         color or multiple colors that can be selected based on a state.
    985      */
    986     @Nullable
    987     public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
    988             throws NotFoundException {
    989         final TypedValue value = obtainTempTypedValue();
    990         try {
    991             final ResourcesImpl impl = mResourcesImpl;
    992             impl.getValue(id, value, true);
    993             return impl.loadColorStateList(this, value, id, theme);
    994         } finally {
    995             releaseTempTypedValue(value);
    996         }
    997     }
    998 
    999     @Nullable
   1000     ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
   1001             throws NotFoundException {
   1002         return mResourcesImpl.loadColorStateList(this, value, id, theme);
   1003     }
   1004 
   1005     /**
   1006      * @hide
   1007      */
   1008     @Nullable
   1009     public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
   1010         return mResourcesImpl.loadComplexColor(this, value, id, theme);
   1011     }
   1012 
   1013     /**
   1014      * Return a boolean associated with a particular resource ID.  This can be
   1015      * used with any integral resource value, and will return true if it is
   1016      * non-zero.
   1017      *
   1018      * @param id The desired resource identifier, as generated by the aapt
   1019      *           tool. This integer encodes the package, type, and resource
   1020      *           entry. The value 0 is an invalid identifier.
   1021      *
   1022      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1023      *
   1024      * @return Returns the boolean value contained in the resource.
   1025      */
   1026     public boolean getBoolean(@BoolRes int id) throws NotFoundException {
   1027         final TypedValue value = obtainTempTypedValue();
   1028         try {
   1029             mResourcesImpl.getValue(id, value, true);
   1030             if (value.type >= TypedValue.TYPE_FIRST_INT
   1031                     && value.type <= TypedValue.TYPE_LAST_INT) {
   1032                 return value.data != 0;
   1033             }
   1034             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
   1035                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
   1036         } finally {
   1037             releaseTempTypedValue(value);
   1038         }
   1039     }
   1040 
   1041     /**
   1042      * Return an integer associated with a particular resource ID.
   1043      *
   1044      * @param id The desired resource identifier, as generated by the aapt
   1045      *           tool. This integer encodes the package, type, and resource
   1046      *           entry. The value 0 is an invalid identifier.
   1047      *
   1048      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1049      *
   1050      * @return Returns the integer value contained in the resource.
   1051      */
   1052     public int getInteger(@IntegerRes int id) throws NotFoundException {
   1053         final TypedValue value = obtainTempTypedValue();
   1054         try {
   1055             mResourcesImpl.getValue(id, value, true);
   1056             if (value.type >= TypedValue.TYPE_FIRST_INT
   1057                     && value.type <= TypedValue.TYPE_LAST_INT) {
   1058                 return value.data;
   1059             }
   1060             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
   1061                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
   1062         } finally {
   1063             releaseTempTypedValue(value);
   1064         }
   1065     }
   1066 
   1067     /**
   1068      * Retrieve a floating-point value for a particular resource ID.
   1069      *
   1070      * @param id The desired resource identifier, as generated by the aapt
   1071      *           tool. This integer encodes the package, type, and resource
   1072      *           entry. The value 0 is an invalid identifier.
   1073      *
   1074      * @return Returns the floating-point value contained in the resource.
   1075      *
   1076      * @throws NotFoundException Throws NotFoundException if the given ID does
   1077      *         not exist or is not a floating-point value.
   1078      * @hide Pending API council approval.
   1079      */
   1080     public float getFloat(int id) {
   1081         final TypedValue value = obtainTempTypedValue();
   1082         try {
   1083             mResourcesImpl.getValue(id, value, true);
   1084             if (value.type == TypedValue.TYPE_FLOAT) {
   1085                 return value.getFloat();
   1086             }
   1087             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
   1088                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
   1089         } finally {
   1090             releaseTempTypedValue(value);
   1091         }
   1092     }
   1093 
   1094     /**
   1095      * Return an XmlResourceParser through which you can read a view layout
   1096      * description for the given resource ID.  This parser has limited
   1097      * functionality -- in particular, you can't change its input, and only
   1098      * the high-level events are available.
   1099      *
   1100      * <p>This function is really a simple wrapper for calling
   1101      * {@link #getXml} with a layout resource.
   1102      *
   1103      * @param id The desired resource identifier, as generated by the aapt
   1104      *           tool. This integer encodes the package, type, and resource
   1105      *           entry. The value 0 is an invalid identifier.
   1106      *
   1107      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1108      *
   1109      * @return A new parser object through which you can read
   1110      *         the XML data.
   1111      *
   1112      * @see #getXml
   1113      */
   1114     public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
   1115         return loadXmlResourceParser(id, "layout");
   1116     }
   1117 
   1118     /**
   1119      * Return an XmlResourceParser through which you can read an animation
   1120      * description for the given resource ID.  This parser has limited
   1121      * functionality -- in particular, you can't change its input, and only
   1122      * the high-level events are available.
   1123      *
   1124      * <p>This function is really a simple wrapper for calling
   1125      * {@link #getXml} with an animation resource.
   1126      *
   1127      * @param id The desired resource identifier, as generated by the aapt
   1128      *           tool. This integer encodes the package, type, and resource
   1129      *           entry. The value 0 is an invalid identifier.
   1130      *
   1131      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1132      *
   1133      * @return A new parser object through which you can read
   1134      *         the XML data.
   1135      *
   1136      * @see #getXml
   1137      */
   1138     public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
   1139         return loadXmlResourceParser(id, "anim");
   1140     }
   1141 
   1142     /**
   1143      * Return an XmlResourceParser through which you can read a generic XML
   1144      * resource for the given resource ID.
   1145      *
   1146      * <p>The XmlPullParser implementation returned here has some limited
   1147      * functionality.  In particular, you can't change its input, and only
   1148      * high-level parsing events are available (since the document was
   1149      * pre-parsed for you at build time, which involved merging text and
   1150      * stripping comments).
   1151      *
   1152      * @param id The desired resource identifier, as generated by the aapt
   1153      *           tool. This integer encodes the package, type, and resource
   1154      *           entry. The value 0 is an invalid identifier.
   1155      *
   1156      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1157      *
   1158      * @return A new parser object through which you can read
   1159      *         the XML data.
   1160      *
   1161      * @see android.util.AttributeSet
   1162      */
   1163     public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
   1164         return loadXmlResourceParser(id, "xml");
   1165     }
   1166 
   1167     /**
   1168      * Open a data stream for reading a raw resource.  This can only be used
   1169      * with resources whose value is the name of an asset files -- that is, it can be
   1170      * used to open drawable, sound, and raw resources; it will fail on string
   1171      * and color resources.
   1172      *
   1173      * @param id The resource identifier to open, as generated by the appt
   1174      *           tool.
   1175      *
   1176      * @return InputStream Access to the resource data.
   1177      *
   1178      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1179      *
   1180      */
   1181     public InputStream openRawResource(@RawRes int id) throws NotFoundException {
   1182         final TypedValue value = obtainTempTypedValue();
   1183         try {
   1184             return openRawResource(id, value);
   1185         } finally {
   1186             releaseTempTypedValue(value);
   1187         }
   1188     }
   1189 
   1190     /**
   1191      * Returns a TypedValue suitable for temporary use. The obtained TypedValue
   1192      * should be released using {@link #releaseTempTypedValue(TypedValue)}.
   1193      *
   1194      * @return a typed value suitable for temporary use
   1195      */
   1196     private TypedValue obtainTempTypedValue() {
   1197         TypedValue tmpValue = null;
   1198         synchronized (mTmpValueLock) {
   1199             if (mTmpValue != null) {
   1200                 tmpValue = mTmpValue;
   1201                 mTmpValue = null;
   1202             }
   1203         }
   1204         if (tmpValue == null) {
   1205             return new TypedValue();
   1206         }
   1207         return tmpValue;
   1208     }
   1209 
   1210     /**
   1211      * Returns a TypedValue to the pool. After calling this method, the
   1212      * specified TypedValue should no longer be accessed.
   1213      *
   1214      * @param value the typed value to return to the pool
   1215      */
   1216     private void releaseTempTypedValue(TypedValue value) {
   1217         synchronized (mTmpValueLock) {
   1218             if (mTmpValue == null) {
   1219                 mTmpValue = value;
   1220             }
   1221         }
   1222     }
   1223 
   1224     /**
   1225      * Open a data stream for reading a raw resource.  This can only be used
   1226      * with resources whose value is the name of an asset file -- that is, it can be
   1227      * used to open drawable, sound, and raw resources; it will fail on string
   1228      * and color resources.
   1229      *
   1230      * @param id The resource identifier to open, as generated by the appt tool.
   1231      * @param value The TypedValue object to hold the resource information.
   1232      *
   1233      * @return InputStream Access to the resource data.
   1234      *
   1235      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1236      */
   1237     public InputStream openRawResource(@RawRes int id, TypedValue value)
   1238             throws NotFoundException {
   1239         return mResourcesImpl.openRawResource(id, value);
   1240     }
   1241 
   1242     /**
   1243      * Open a file descriptor for reading a raw resource.  This can only be used
   1244      * with resources whose value is the name of an asset files -- that is, it can be
   1245      * used to open drawable, sound, and raw resources; it will fail on string
   1246      * and color resources.
   1247      *
   1248      * <p>This function only works for resources that are stored in the package
   1249      * as uncompressed data, which typically includes things like mp3 files
   1250      * and png images.
   1251      *
   1252      * @param id The resource identifier to open, as generated by the appt
   1253      *           tool.
   1254      *
   1255      * @return AssetFileDescriptor A new file descriptor you can use to read
   1256      * the resource.  This includes the file descriptor itself, as well as the
   1257      * offset and length of data where the resource appears in the file.  A
   1258      * null is returned if the file exists but is compressed.
   1259      *
   1260      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1261      *
   1262      */
   1263     public AssetFileDescriptor openRawResourceFd(@RawRes int id)
   1264             throws NotFoundException {
   1265         final TypedValue value = obtainTempTypedValue();
   1266         try {
   1267             return mResourcesImpl.openRawResourceFd(id, value);
   1268         } finally {
   1269             releaseTempTypedValue(value);
   1270         }
   1271     }
   1272 
   1273     /**
   1274      * Return the raw data associated with a particular resource ID.
   1275      *
   1276      * @param id The desired resource identifier, as generated by the aapt
   1277      *           tool. This integer encodes the package, type, and resource
   1278      *           entry. The value 0 is an invalid identifier.
   1279      * @param outValue Object in which to place the resource data.
   1280      * @param resolveRefs If true, a resource that is a reference to another
   1281      *                    resource will be followed so that you receive the
   1282      *                    actual final resource data.  If false, the TypedValue
   1283      *                    will be filled in with the reference itself.
   1284      *
   1285      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1286      *
   1287      */
   1288     public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
   1289             throws NotFoundException {
   1290         mResourcesImpl.getValue(id, outValue, resolveRefs);
   1291     }
   1292 
   1293     /**
   1294      * Get the raw value associated with a resource with associated density.
   1295      *
   1296      * @param id resource identifier
   1297      * @param density density in DPI
   1298      * @param resolveRefs If true, a resource that is a reference to another
   1299      *            resource will be followed so that you receive the actual final
   1300      *            resource data. If false, the TypedValue will be filled in with
   1301      *            the reference itself.
   1302      * @throws NotFoundException Throws NotFoundException if the given ID does
   1303      *             not exist.
   1304      * @see #getValue(String, TypedValue, boolean)
   1305      */
   1306     public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
   1307             boolean resolveRefs) throws NotFoundException {
   1308         mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
   1309     }
   1310 
   1311     /**
   1312      * Return the raw data associated with a particular resource ID.
   1313      * See getIdentifier() for information on how names are mapped to resource
   1314      * IDs, and getString(int) for information on how string resources are
   1315      * retrieved.
   1316      *
   1317      * <p>Note: use of this function is discouraged.  It is much more
   1318      * efficient to retrieve resources by identifier than by name.
   1319      *
   1320      * @param name The name of the desired resource.  This is passed to
   1321      *             getIdentifier() with a default type of "string".
   1322      * @param outValue Object in which to place the resource data.
   1323      * @param resolveRefs If true, a resource that is a reference to another
   1324      *                    resource will be followed so that you receive the
   1325      *                    actual final resource data.  If false, the TypedValue
   1326      *                    will be filled in with the reference itself.
   1327      *
   1328      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1329      *
   1330      */
   1331     public void getValue(String name, TypedValue outValue, boolean resolveRefs)
   1332             throws NotFoundException {
   1333         mResourcesImpl.getValue(name, outValue, resolveRefs);
   1334     }
   1335 
   1336     /**
   1337      * This class holds the current attribute values for a particular theme.
   1338      * In other words, a Theme is a set of values for resource attributes;
   1339      * these are used in conjunction with {@link TypedArray}
   1340      * to resolve the final value for an attribute.
   1341      *
   1342      * <p>The Theme's attributes come into play in two ways: (1) a styled
   1343      * attribute can explicit reference a value in the theme through the
   1344      * "?themeAttribute" syntax; (2) if no value has been defined for a
   1345      * particular styled attribute, as a last resort we will try to find that
   1346      * attribute's value in the Theme.
   1347      *
   1348      * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
   1349      * retrieve XML attributes with style and theme information applied.
   1350      */
   1351     public final class Theme {
   1352         private ResourcesImpl.ThemeImpl mThemeImpl;
   1353 
   1354         private Theme() {
   1355         }
   1356 
   1357         void setImpl(ResourcesImpl.ThemeImpl impl) {
   1358             mThemeImpl = impl;
   1359         }
   1360 
   1361         /**
   1362          * Place new attribute values into the theme.  The style resource
   1363          * specified by <var>resid</var> will be retrieved from this Theme's
   1364          * resources, its values placed into the Theme object.
   1365          *
   1366          * <p>The semantics of this function depends on the <var>force</var>
   1367          * argument:  If false, only values that are not already defined in
   1368          * the theme will be copied from the system resource; otherwise, if
   1369          * any of the style's attributes are already defined in the theme, the
   1370          * current values in the theme will be overwritten.
   1371          *
   1372          * @param resId The resource ID of a style resource from which to
   1373          *              obtain attribute values.
   1374          * @param force If true, values in the style resource will always be
   1375          *              used in the theme; otherwise, they will only be used
   1376          *              if not already defined in the theme.
   1377          */
   1378         public void applyStyle(int resId, boolean force) {
   1379             mThemeImpl.applyStyle(resId, force);
   1380         }
   1381 
   1382         /**
   1383          * Set this theme to hold the same contents as the theme
   1384          * <var>other</var>.  If both of these themes are from the same
   1385          * Resources object, they will be identical after this function
   1386          * returns.  If they are from different Resources, only the resources
   1387          * they have in common will be set in this theme.
   1388          *
   1389          * @param other The existing Theme to copy from.
   1390          */
   1391         public void setTo(Theme other) {
   1392             mThemeImpl.setTo(other.mThemeImpl);
   1393         }
   1394 
   1395         /**
   1396          * Return a TypedArray holding the values defined by
   1397          * <var>Theme</var> which are listed in <var>attrs</var>.
   1398          *
   1399          * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
   1400          * with the array.
   1401          *
   1402          * @param attrs The desired attributes.
   1403          *
   1404          * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1405          *
   1406          * @return Returns a TypedArray holding an array of the attribute values.
   1407          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
   1408          * when done with it.
   1409          *
   1410          * @see Resources#obtainAttributes
   1411          * @see #obtainStyledAttributes(int, int[])
   1412          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
   1413          */
   1414         public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
   1415             return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
   1416         }
   1417 
   1418         /**
   1419          * Return a TypedArray holding the values defined by the style
   1420          * resource <var>resid</var> which are listed in <var>attrs</var>.
   1421          *
   1422          * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
   1423          * with the array.
   1424          *
   1425          * @param resId The desired style resource.
   1426          * @param attrs The desired attributes in the style.
   1427          *
   1428          * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1429          *
   1430          * @return Returns a TypedArray holding an array of the attribute values.
   1431          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
   1432          * when done with it.
   1433          *
   1434          * @see Resources#obtainAttributes
   1435          * @see #obtainStyledAttributes(int[])
   1436          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
   1437          */
   1438         public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
   1439                 throws NotFoundException {
   1440             return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
   1441         }
   1442 
   1443         /**
   1444          * Return a TypedArray holding the attribute values in
   1445          * <var>set</var>
   1446          * that are listed in <var>attrs</var>.  In addition, if the given
   1447          * AttributeSet specifies a style class (through the "style" attribute),
   1448          * that style will be applied on top of the base attributes it defines.
   1449          *
   1450          * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
   1451          * with the array.
   1452          *
   1453          * <p>When determining the final value of a particular attribute, there
   1454          * are four inputs that come into play:</p>
   1455          *
   1456          * <ol>
   1457          *     <li> Any attribute values in the given AttributeSet.
   1458          *     <li> The style resource specified in the AttributeSet (named
   1459          *     "style").
   1460          *     <li> The default style specified by <var>defStyleAttr</var> and
   1461          *     <var>defStyleRes</var>
   1462          *     <li> The base values in this theme.
   1463          * </ol>
   1464          *
   1465          * <p>Each of these inputs is considered in-order, with the first listed
   1466          * taking precedence over the following ones.  In other words, if in the
   1467          * AttributeSet you have supplied <code>&lt;Button
   1468          * textColor="#ff000000"&gt;</code>, then the button's text will
   1469          * <em>always</em> be black, regardless of what is specified in any of
   1470          * the styles.
   1471          *
   1472          * @param set The base set of attribute values.  May be null.
   1473          * @param attrs The desired attributes to be retrieved.
   1474          * @param defStyleAttr An attribute in the current theme that contains a
   1475          *                     reference to a style resource that supplies
   1476          *                     defaults values for the TypedArray.  Can be
   1477          *                     0 to not look for defaults.
   1478          * @param defStyleRes A resource identifier of a style resource that
   1479          *                    supplies default values for the TypedArray,
   1480          *                    used only if defStyleAttr is 0 or can not be found
   1481          *                    in the theme.  Can be 0 to not look for defaults.
   1482          *
   1483          * @return Returns a TypedArray holding an array of the attribute values.
   1484          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
   1485          * when done with it.
   1486          *
   1487          * @see Resources#obtainAttributes
   1488          * @see #obtainStyledAttributes(int[])
   1489          * @see #obtainStyledAttributes(int, int[])
   1490          */
   1491         public TypedArray obtainStyledAttributes(AttributeSet set,
   1492                 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
   1493             return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
   1494         }
   1495 
   1496         /**
   1497          * Retrieve the values for a set of attributes in the Theme. The
   1498          * contents of the typed array are ultimately filled in by
   1499          * {@link Resources#getValue}.
   1500          *
   1501          * @param values The base set of attribute values, must be equal in
   1502          *               length to {@code attrs}. All values must be of type
   1503          *               {@link TypedValue#TYPE_ATTRIBUTE}.
   1504          * @param attrs The desired attributes to be retrieved.
   1505          * @return Returns a TypedArray holding an array of the attribute
   1506          *         values. Be sure to call {@link TypedArray#recycle()}
   1507          *         when done with it.
   1508          * @hide
   1509          */
   1510         @NonNull
   1511         public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
   1512             return mThemeImpl.resolveAttributes(this, values, attrs);
   1513         }
   1514 
   1515         /**
   1516          * Retrieve the value of an attribute in the Theme.  The contents of
   1517          * <var>outValue</var> are ultimately filled in by
   1518          * {@link Resources#getValue}.
   1519          *
   1520          * @param resid The resource identifier of the desired theme
   1521          *              attribute.
   1522          * @param outValue Filled in with the ultimate resource value supplied
   1523          *                 by the attribute.
   1524          * @param resolveRefs If true, resource references will be walked; if
   1525          *                    false, <var>outValue</var> may be a
   1526          *                    TYPE_REFERENCE.  In either case, it will never
   1527          *                    be a TYPE_ATTRIBUTE.
   1528          *
   1529          * @return boolean Returns true if the attribute was found and
   1530          *         <var>outValue</var> is valid, else false.
   1531          */
   1532         public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
   1533             return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
   1534         }
   1535 
   1536         /**
   1537          * Gets all of the attribute ids associated with this {@link Theme}. For debugging only.
   1538          *
   1539          * @return The int array containing attribute ids associated with this {@link Theme}.
   1540          * @hide
   1541          */
   1542         public int[] getAllAttributes() {
   1543             return mThemeImpl.getAllAttributes();
   1544         }
   1545 
   1546         /**
   1547          * Returns the resources to which this theme belongs.
   1548          *
   1549          * @return Resources to which this theme belongs.
   1550          */
   1551         public Resources getResources() {
   1552             return Resources.this;
   1553         }
   1554 
   1555         /**
   1556          * Return a drawable object associated with a particular resource ID
   1557          * and styled for the Theme.
   1558          *
   1559          * @param id The desired resource identifier, as generated by the aapt
   1560          *           tool. This integer encodes the package, type, and resource
   1561          *           entry. The value 0 is an invalid identifier.
   1562          * @return Drawable An object that can be used to draw this resource.
   1563          * @throws NotFoundException Throws NotFoundException if the given ID
   1564          *         does not exist.
   1565          */
   1566         public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
   1567             return Resources.this.getDrawable(id, this);
   1568         }
   1569 
   1570         /**
   1571          * Returns a bit mask of configuration changes that will impact this
   1572          * theme (and thus require completely reloading it).
   1573          *
   1574          * @return a bit mask of configuration changes, as defined by
   1575          *         {@link ActivityInfo}
   1576          * @see ActivityInfo
   1577          */
   1578         public int getChangingConfigurations() {
   1579             return mThemeImpl.getChangingConfigurations();
   1580         }
   1581 
   1582         /**
   1583          * Print contents of this theme out to the log.  For debugging only.
   1584          *
   1585          * @param priority The log priority to use.
   1586          * @param tag The log tag to use.
   1587          * @param prefix Text to prefix each line printed.
   1588          */
   1589         public void dump(int priority, String tag, String prefix) {
   1590             mThemeImpl.dump(priority, tag, prefix);
   1591         }
   1592 
   1593         // Needed by layoutlib.
   1594         /*package*/ long getNativeTheme() {
   1595             return mThemeImpl.getNativeTheme();
   1596         }
   1597 
   1598         /*package*/ int getAppliedStyleResId() {
   1599             return mThemeImpl.getAppliedStyleResId();
   1600         }
   1601 
   1602         /**
   1603          * @hide
   1604          */
   1605         public ThemeKey getKey() {
   1606             return mThemeImpl.getKey();
   1607         }
   1608 
   1609         private String getResourceNameFromHexString(String hexString) {
   1610             return getResourceName(Integer.parseInt(hexString, 16));
   1611         }
   1612 
   1613         /**
   1614          * Parses {@link #getKey()} and returns a String array that holds pairs of
   1615          * adjacent Theme data: resource name followed by whether or not it was
   1616          * forced, as specified by {@link #applyStyle(int, boolean)}.
   1617          *
   1618          * @hide
   1619          */
   1620         @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
   1621         public String[] getTheme() {
   1622             return mThemeImpl.getTheme();
   1623         }
   1624 
   1625         /** @hide */
   1626         public void encode(@NonNull ViewHierarchyEncoder encoder) {
   1627             encoder.beginObject(this);
   1628             final String[] properties = getTheme();
   1629             for (int i = 0; i < properties.length; i += 2) {
   1630                 encoder.addProperty(properties[i], properties[i+1]);
   1631             }
   1632             encoder.endObject();
   1633         }
   1634 
   1635         /**
   1636          * Rebases the theme against the parent Resource object's current
   1637          * configuration by re-applying the styles passed to
   1638          * {@link #applyStyle(int, boolean)}.
   1639          *
   1640          * @hide
   1641          */
   1642         public void rebase() {
   1643             mThemeImpl.rebase();
   1644         }
   1645     }
   1646 
   1647     static class ThemeKey implements Cloneable {
   1648         int[] mResId;
   1649         boolean[] mForce;
   1650         int mCount;
   1651 
   1652         private int mHashCode = 0;
   1653 
   1654         public void append(int resId, boolean force) {
   1655             if (mResId == null) {
   1656                 mResId = new int[4];
   1657             }
   1658 
   1659             if (mForce == null) {
   1660                 mForce = new boolean[4];
   1661             }
   1662 
   1663             mResId = GrowingArrayUtils.append(mResId, mCount, resId);
   1664             mForce = GrowingArrayUtils.append(mForce, mCount, force);
   1665             mCount++;
   1666 
   1667             mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
   1668         }
   1669 
   1670         /**
   1671          * Sets up this key as a deep copy of another key.
   1672          *
   1673          * @param other the key to deep copy into this key
   1674          */
   1675         public void setTo(ThemeKey other) {
   1676             mResId = other.mResId == null ? null : other.mResId.clone();
   1677             mForce = other.mForce == null ? null : other.mForce.clone();
   1678             mCount = other.mCount;
   1679         }
   1680 
   1681         @Override
   1682         public int hashCode() {
   1683             return mHashCode;
   1684         }
   1685 
   1686         @Override
   1687         public boolean equals(Object o) {
   1688             if (this == o) {
   1689                 return true;
   1690             }
   1691 
   1692             if (o == null || getClass() != o.getClass() || hashCode() != o.hashCode()) {
   1693                 return false;
   1694             }
   1695 
   1696             final ThemeKey t = (ThemeKey) o;
   1697             if (mCount != t.mCount) {
   1698                 return false;
   1699             }
   1700 
   1701             final int N = mCount;
   1702             for (int i = 0; i < N; i++) {
   1703                 if (mResId[i] != t.mResId[i] || mForce[i] != t.mForce[i]) {
   1704                     return false;
   1705                 }
   1706             }
   1707 
   1708             return true;
   1709         }
   1710 
   1711         /**
   1712          * @return a shallow copy of this key
   1713          */
   1714         @Override
   1715         public ThemeKey clone() {
   1716             final ThemeKey other = new ThemeKey();
   1717             other.mResId = mResId;
   1718             other.mForce = mForce;
   1719             other.mCount = mCount;
   1720             other.mHashCode = mHashCode;
   1721             return other;
   1722         }
   1723     }
   1724 
   1725     /**
   1726      * Generate a new Theme object for this set of Resources.  It initially
   1727      * starts out empty.
   1728      *
   1729      * @return Theme The newly created Theme container.
   1730      */
   1731     public final Theme newTheme() {
   1732         Theme theme = new Theme();
   1733         theme.setImpl(mResourcesImpl.newThemeImpl());
   1734         mThemeRefs.add(new WeakReference<>(theme));
   1735         return theme;
   1736     }
   1737 
   1738     /**
   1739      * Retrieve a set of basic attribute values from an AttributeSet, not
   1740      * performing styling of them using a theme and/or style resources.
   1741      *
   1742      * @param set The current attribute values to retrieve.
   1743      * @param attrs The specific attributes to be retrieved.
   1744      * @return Returns a TypedArray holding an array of the attribute values.
   1745      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
   1746      * when done with it.
   1747      *
   1748      * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
   1749      */
   1750     public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
   1751         int len = attrs.length;
   1752         TypedArray array = TypedArray.obtain(this, len);
   1753 
   1754         // XXX note that for now we only work with compiled XML files.
   1755         // To support generic XML files we will need to manually parse
   1756         // out the attributes from the XML file (applying type information
   1757         // contained in the resources and such).
   1758         XmlBlock.Parser parser = (XmlBlock.Parser)set;
   1759         mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
   1760                 array.mData, array.mIndices);
   1761 
   1762         array.mXml = parser;
   1763 
   1764         return array;
   1765     }
   1766 
   1767     /**
   1768      * Store the newly updated configuration.
   1769      *
   1770      * @deprecated See {@link android.content.Context#createConfigurationContext(Configuration)}.
   1771      */
   1772     @Deprecated
   1773     public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
   1774         updateConfiguration(config, metrics, null);
   1775     }
   1776 
   1777     /**
   1778      * @hide
   1779      */
   1780     public void updateConfiguration(Configuration config, DisplayMetrics metrics,
   1781                                     CompatibilityInfo compat) {
   1782         mResourcesImpl.updateConfiguration(config, metrics, compat);
   1783     }
   1784 
   1785     /**
   1786      * Update the system resources configuration if they have previously
   1787      * been initialized.
   1788      *
   1789      * @hide
   1790      */
   1791     public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
   1792             CompatibilityInfo compat) {
   1793         if (mSystem != null) {
   1794             mSystem.updateConfiguration(config, metrics, compat);
   1795             //Log.i(TAG, "Updated system resources " + mSystem
   1796             //        + ": " + mSystem.getConfiguration());
   1797         }
   1798     }
   1799 
   1800     /**
   1801      * Return the current display metrics that are in effect for this resource
   1802      * object.  The returned object should be treated as read-only.
   1803      *
   1804      * @return The resource's current display metrics.
   1805      */
   1806     public DisplayMetrics getDisplayMetrics() {
   1807         return mResourcesImpl.getDisplayMetrics();
   1808     }
   1809 
   1810     /** @hide */
   1811     public DisplayAdjustments getDisplayAdjustments() {
   1812         return mResourcesImpl.getDisplayAdjustments();
   1813     }
   1814 
   1815     /**
   1816      * Return the current configuration that is in effect for this resource
   1817      * object.  The returned object should be treated as read-only.
   1818      *
   1819      * @return The resource's current configuration.
   1820      */
   1821     public Configuration getConfiguration() {
   1822         return mResourcesImpl.getConfiguration();
   1823     }
   1824 
   1825     /** @hide */
   1826     public Configuration[] getSizeConfigurations() {
   1827         return mResourcesImpl.getSizeConfigurations();
   1828     }
   1829 
   1830     /**
   1831      * Return the compatibility mode information for the application.
   1832      * The returned object should be treated as read-only.
   1833      *
   1834      * @return compatibility info.
   1835      * @hide
   1836      */
   1837     public CompatibilityInfo getCompatibilityInfo() {
   1838         return mResourcesImpl.getCompatibilityInfo();
   1839     }
   1840 
   1841     /**
   1842      * This is just for testing.
   1843      * @hide
   1844      */
   1845     @VisibleForTesting
   1846     public void setCompatibilityInfo(CompatibilityInfo ci) {
   1847         if (ci != null) {
   1848             mResourcesImpl.updateConfiguration(null, null, ci);
   1849         }
   1850     }
   1851 
   1852     /**
   1853      * Return a resource identifier for the given resource name.  A fully
   1854      * qualified resource name is of the form "package:type/entry".  The first
   1855      * two components (package and type) are optional if defType and
   1856      * defPackage, respectively, are specified here.
   1857      *
   1858      * <p>Note: use of this function is discouraged.  It is much more
   1859      * efficient to retrieve resources by identifier than by name.
   1860      *
   1861      * @param name The name of the desired resource.
   1862      * @param defType Optional default resource type to find, if "type/" is
   1863      *                not included in the name.  Can be null to require an
   1864      *                explicit type.
   1865      * @param defPackage Optional default package to find, if "package:" is
   1866      *                   not included in the name.  Can be null to require an
   1867      *                   explicit package.
   1868      *
   1869      * @return int The associated resource identifier.  Returns 0 if no such
   1870      *         resource was found.  (0 is not a valid resource ID.)
   1871      */
   1872     public int getIdentifier(String name, String defType, String defPackage) {
   1873         return mResourcesImpl.getIdentifier(name, defType, defPackage);
   1874     }
   1875 
   1876     /**
   1877      * Return true if given resource identifier includes a package.
   1878      *
   1879      * @hide
   1880      */
   1881     public static boolean resourceHasPackage(@AnyRes int resid) {
   1882         return (resid >>> 24) != 0;
   1883     }
   1884 
   1885     /**
   1886      * Return the full name for a given resource identifier.  This name is
   1887      * a single string of the form "package:type/entry".
   1888      *
   1889      * @param resid The resource identifier whose name is to be retrieved.
   1890      *
   1891      * @return A string holding the name of the resource.
   1892      *
   1893      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1894      *
   1895      * @see #getResourcePackageName
   1896      * @see #getResourceTypeName
   1897      * @see #getResourceEntryName
   1898      */
   1899     public String getResourceName(@AnyRes int resid) throws NotFoundException {
   1900         return mResourcesImpl.getResourceName(resid);
   1901     }
   1902 
   1903     /**
   1904      * Return the package name for a given resource identifier.
   1905      *
   1906      * @param resid The resource identifier whose package name is to be
   1907      * retrieved.
   1908      *
   1909      * @return A string holding the package name of the resource.
   1910      *
   1911      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1912      *
   1913      * @see #getResourceName
   1914      */
   1915     public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
   1916         return mResourcesImpl.getResourcePackageName(resid);
   1917     }
   1918 
   1919     /**
   1920      * Return the type name for a given resource identifier.
   1921      *
   1922      * @param resid The resource identifier whose type name is to be
   1923      * retrieved.
   1924      *
   1925      * @return A string holding the type name of the resource.
   1926      *
   1927      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1928      *
   1929      * @see #getResourceName
   1930      */
   1931     public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
   1932         return mResourcesImpl.getResourceTypeName(resid);
   1933     }
   1934 
   1935     /**
   1936      * Return the entry name for a given resource identifier.
   1937      *
   1938      * @param resid The resource identifier whose entry name is to be
   1939      * retrieved.
   1940      *
   1941      * @return A string holding the entry name of the resource.
   1942      *
   1943      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
   1944      *
   1945      * @see #getResourceName
   1946      */
   1947     public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
   1948         return mResourcesImpl.getResourceEntryName(resid);
   1949     }
   1950 
   1951     /**
   1952      * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
   1953      * an XML file.  You call this when you are at the parent tag of the
   1954      * extra tags, and it will return once all of the child tags have been parsed.
   1955      * This will call {@link #parseBundleExtra} for each extra tag encountered.
   1956      *
   1957      * @param parser The parser from which to retrieve the extras.
   1958      * @param outBundle A Bundle in which to place all parsed extras.
   1959      * @throws XmlPullParserException
   1960      * @throws IOException
   1961      */
   1962     public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
   1963             throws XmlPullParserException, IOException {
   1964         int outerDepth = parser.getDepth();
   1965         int type;
   1966         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
   1967                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
   1968             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
   1969                 continue;
   1970             }
   1971 
   1972             String nodeName = parser.getName();
   1973             if (nodeName.equals("extra")) {
   1974                 parseBundleExtra("extra", parser, outBundle);
   1975                 XmlUtils.skipCurrentTag(parser);
   1976 
   1977             } else {
   1978                 XmlUtils.skipCurrentTag(parser);
   1979             }
   1980         }
   1981     }
   1982 
   1983     /**
   1984      * Parse a name/value pair out of an XML tag holding that data.  The
   1985      * AttributeSet must be holding the data defined by
   1986      * {@link android.R.styleable#Extra}.  The following value types are supported:
   1987      * <ul>
   1988      * <li> {@link TypedValue#TYPE_STRING}:
   1989      * {@link Bundle#putCharSequence Bundle.putCharSequence()}
   1990      * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
   1991      * {@link Bundle#putCharSequence Bundle.putBoolean()}
   1992      * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
   1993      * {@link Bundle#putCharSequence Bundle.putBoolean()}
   1994      * <li> {@link TypedValue#TYPE_FLOAT}:
   1995      * {@link Bundle#putCharSequence Bundle.putFloat()}
   1996      * </ul>
   1997      *
   1998      * @param tagName The name of the tag these attributes come from; this is
   1999      * only used for reporting error messages.
   2000      * @param attrs The attributes from which to retrieve the name/value pair.
   2001      * @param outBundle The Bundle in which to place the parsed value.
   2002      * @throws XmlPullParserException If the attributes are not valid.
   2003      */
   2004     public void parseBundleExtra(String tagName, AttributeSet attrs,
   2005             Bundle outBundle) throws XmlPullParserException {
   2006         TypedArray sa = obtainAttributes(attrs,
   2007                 com.android.internal.R.styleable.Extra);
   2008 
   2009         String name = sa.getString(
   2010                 com.android.internal.R.styleable.Extra_name);
   2011         if (name == null) {
   2012             sa.recycle();
   2013             throw new XmlPullParserException("<" + tagName
   2014                     + "> requires an android:name attribute at "
   2015                     + attrs.getPositionDescription());
   2016         }
   2017 
   2018         TypedValue v = sa.peekValue(
   2019                 com.android.internal.R.styleable.Extra_value);
   2020         if (v != null) {
   2021             if (v.type == TypedValue.TYPE_STRING) {
   2022                 CharSequence cs = v.coerceToString();
   2023                 outBundle.putCharSequence(name, cs);
   2024             } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
   2025                 outBundle.putBoolean(name, v.data != 0);
   2026             } else if (v.type >= TypedValue.TYPE_FIRST_INT
   2027                     && v.type <= TypedValue.TYPE_LAST_INT) {
   2028                 outBundle.putInt(name, v.data);
   2029             } else if (v.type == TypedValue.TYPE_FLOAT) {
   2030                 outBundle.putFloat(name, v.getFloat());
   2031             } else {
   2032                 sa.recycle();
   2033                 throw new XmlPullParserException("<" + tagName
   2034                         + "> only supports string, integer, float, color, and boolean at "
   2035                         + attrs.getPositionDescription());
   2036             }
   2037         } else {
   2038             sa.recycle();
   2039             throw new XmlPullParserException("<" + tagName
   2040                     + "> requires an android:value or android:resource attribute at "
   2041                     + attrs.getPositionDescription());
   2042         }
   2043 
   2044         sa.recycle();
   2045     }
   2046 
   2047     /**
   2048      * Retrieve underlying AssetManager storage for these resources.
   2049      */
   2050     public final AssetManager getAssets() {
   2051         return mResourcesImpl.getAssets();
   2052     }
   2053 
   2054     /**
   2055      * Call this to remove all cached loaded layout resources from the
   2056      * Resources object.  Only intended for use with performance testing
   2057      * tools.
   2058      */
   2059     public final void flushLayoutCache() {
   2060         mResourcesImpl.flushLayoutCache();
   2061     }
   2062 
   2063     /**
   2064      * Start preloading of resource data using this Resources object.  Only
   2065      * for use by the zygote process for loading common system resources.
   2066      * {@hide}
   2067      */
   2068     public final void startPreloading() {
   2069         mResourcesImpl.startPreloading();
   2070     }
   2071 
   2072     /**
   2073      * Called by zygote when it is done preloading resources, to change back
   2074      * to normal Resources operation.
   2075      */
   2076     public final void finishPreloading() {
   2077         mResourcesImpl.finishPreloading();
   2078     }
   2079 
   2080     /**
   2081      * @hide
   2082      */
   2083     public LongSparseArray<ConstantState> getPreloadedDrawables() {
   2084         return mResourcesImpl.getPreloadedDrawables();
   2085     }
   2086 
   2087     /**
   2088      * Loads an XML parser for the specified file.
   2089      *
   2090      * @param id the resource identifier for the file
   2091      * @param type the type of resource (used for logging)
   2092      * @return a parser for the specified XML file
   2093      * @throws NotFoundException if the file could not be loaded
   2094      */
   2095     @NonNull
   2096     XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
   2097             throws NotFoundException {
   2098         final TypedValue value = obtainTempTypedValue();
   2099         try {
   2100             final ResourcesImpl impl = mResourcesImpl;
   2101             impl.getValue(id, value, true);
   2102             if (value.type == TypedValue.TYPE_STRING) {
   2103                 return impl.loadXmlResourceParser(value.string.toString(), id,
   2104                         value.assetCookie, type);
   2105             }
   2106             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
   2107                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
   2108         } finally {
   2109             releaseTempTypedValue(value);
   2110         }
   2111     }
   2112 
   2113     /**
   2114      * Loads an XML parser for the specified file.
   2115      *
   2116      * @param file the path for the XML file to parse
   2117      * @param id the resource identifier for the file
   2118      * @param assetCookie the asset cookie for the file
   2119      * @param type the type of resource (used for logging)
   2120      * @return a parser for the specified XML file
   2121      * @throws NotFoundException if the file could not be loaded
   2122      */
   2123     @NonNull
   2124     XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
   2125                                             String type) throws NotFoundException {
   2126         return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
   2127     }
   2128 
   2129     /**
   2130      * Called by ConfigurationBoundResourceCacheTest.
   2131      * @hide
   2132      */
   2133     @VisibleForTesting
   2134     public int calcConfigChanges(Configuration config) {
   2135         return mResourcesImpl.calcConfigChanges(config);
   2136     }
   2137 
   2138     /**
   2139      * Obtains styled attributes from the theme, if available, or unstyled
   2140      * resources if the theme is null.
   2141      *
   2142      * @hide
   2143      */
   2144     public static TypedArray obtainAttributes(
   2145             Resources res, Theme theme, AttributeSet set, int[] attrs) {
   2146         if (theme == null) {
   2147             return res.obtainAttributes(set, attrs);
   2148         }
   2149         return theme.obtainStyledAttributes(set, attrs, 0, 0);
   2150     }
   2151 }
   2152