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