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