Resources.java revision e03c469fd416cf68c9d27268140f058028cd8666
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.ViewDebug;
55import android.view.ViewHierarchyEncoder;
56
57import com.android.internal.annotations.VisibleForTesting;
58import com.android.internal.util.GrowingArrayUtils;
59import com.android.internal.util.XmlUtils;
60
61import org.xmlpull.v1.XmlPullParser;
62import org.xmlpull.v1.XmlPullParserException;
63
64import java.io.IOException;
65import java.io.InputStream;
66import java.lang.ref.WeakReference;
67import java.util.ArrayList;
68
69/**
70 * Class for accessing an application's resources.  This sits on top of the
71 * asset manager of the application (accessible through {@link #getAssets}) and
72 * provides a high-level API for getting typed data from the assets.
73 *
74 * <p>The Android resource system keeps track of all non-code assets associated with an
75 * application. You can use this class to access your application's resources. You can generally
76 * acquire the {@link android.content.res.Resources} instance associated with your application
77 * with {@link android.content.Context#getResources getResources()}.</p>
78 *
79 * <p>The Android SDK tools compile your application's resources into the application binary
80 * at build time.  To use a resource, you must install it correctly in the source tree (inside
81 * your project's {@code res/} directory) and build your application.  As part of the build
82 * process, the SDK tools generate symbols for each resource, which you can use in your application
83 * code to access the resources.</p>
84 *
85 * <p>Using application resources makes it easy to update various characteristics of your
86 * application without modifying code, and&mdash;by providing sets of alternative
87 * resources&mdash;enables you to optimize your application for a variety of device configurations
88 * (such as for different languages and screen sizes). This is an important aspect of developing
89 * Android applications that are compatible on different types of devices.</p>
90 *
91 * <p>For more information about using resources, see the documentation about <a
92 * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
93 */
94public class Resources {
95    static final String TAG = "Resources";
96
97    private static final Object sSync = new Object();
98
99    // Used by BridgeResources in layoutlib
100    static Resources mSystem = null;
101
102    private ResourcesImpl mResourcesImpl;
103
104    // Pool of TypedArrays targeted to this Resources object.
105    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
106
107    /** Used to inflate drawable objects from XML. */
108    private DrawableInflater mDrawableInflater;
109
110    /** Lock object used to protect access to {@link #mTmpValue}. */
111    private final Object mTmpValueLock = new Object();
112
113    /** Single-item pool used to minimize TypedValue allocations. */
114    private TypedValue mTmpValue = new TypedValue();
115
116    final ClassLoader mClassLoader;
117
118    /**
119     * WeakReferences to Themes that were constructed from this Resources object.
120     * We keep track of these in case our underlying implementation is changed, in which case
121     * the Themes must also get updated ThemeImpls.
122     */
123    private final ArrayList<WeakReference<Theme>> mThemeRefs = new ArrayList<>();
124
125    /**
126     * Returns the most appropriate default theme for the specified target SDK version.
127     * <ul>
128     * <li>Below API 11: Gingerbread
129     * <li>APIs 11 thru 14: Holo
130     * <li>APIs 14 thru XX: Device default dark
131     * <li>API XX and above: Device default light with dark action bar
132     * </ul>
133     *
134     * @param curTheme The current theme, or 0 if not specified.
135     * @param targetSdkVersion The target SDK version.
136     * @return A theme resource identifier
137     * @hide
138     */
139    public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
140        return selectSystemTheme(curTheme, targetSdkVersion,
141                com.android.internal.R.style.Theme,
142                com.android.internal.R.style.Theme_Holo,
143                com.android.internal.R.style.Theme_DeviceDefault,
144                com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
145    }
146
147    /** @hide */
148    public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
149            int dark, int deviceDefault) {
150        if (curTheme != 0) {
151            return curTheme;
152        }
153        if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
154            return orig;
155        }
156        if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
157            return holo;
158        }
159        if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
160            return dark;
161        }
162        return deviceDefault;
163    }
164
165    /**
166     * Return a global shared Resources object that provides access to only
167     * system resources (no application resources), and is not configured for
168     * the current screen (can not use dimension units, does not change based
169     * on orientation, etc).
170     */
171    public static Resources getSystem() {
172        synchronized (sSync) {
173            Resources ret = mSystem;
174            if (ret == null) {
175                ret = new Resources();
176                mSystem = ret;
177            }
178            return ret;
179        }
180    }
181
182    /**
183     * This exception is thrown by the resource APIs when a requested resource
184     * can not be found.
185     */
186    public static class NotFoundException extends RuntimeException {
187        public NotFoundException() {
188        }
189
190        public NotFoundException(String name) {
191            super(name);
192        }
193
194        public NotFoundException(String name, Exception cause) {
195            super(name, cause);
196        }
197    }
198
199    /**
200     * Create a new Resources object on top of an existing set of assets in an
201     * AssetManager.
202     *
203     * @param assets Previously created AssetManager.
204     * @param metrics Current display metrics to consider when
205     *                selecting/computing resource values.
206     * @param config Desired device configuration to consider when
207     *               selecting/computing resource values (optional).
208     */
209    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
210        this(null);
211        mResourcesImpl = new ResourcesImpl(assets, metrics, config,
212                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
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                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
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 retrieve the Drawable through
719     * {@link TypedArray#getDrawable TypedArray.getDrawable}.  Use
720     * {@link android.content.Context#obtainStyledAttributes(int[])
721     * Context.obtainStyledAttributes} with
722     * an array containing the resource ID of interest to create the TypedArray.</p>
723     *
724     * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
725     * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
726     * or {@link #getDrawable(int, Theme)} passing the desired theme.</p>
727     *
728     * @param id The desired resource identifier, as generated by the aapt
729     *           tool. This integer encodes the package, type, and resource
730     *           entry. The value 0 is an invalid identifier.
731     * @return Drawable An object that can be used to draw this resource.
732     * @throws NotFoundException Throws NotFoundException if the given ID does
733     *         not exist.
734     * @see #getDrawable(int, Theme)
735     * @deprecated Use {@link #getDrawable(int, Theme)} instead.
736     */
737    @Deprecated
738    public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
739        final Drawable d = getDrawable(id, null);
740        if (d != null && d.canApplyTheme()) {
741            Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
742                    + "attributes! Consider using Resources.getDrawable(int, Theme) or "
743                    + "Context.getDrawable(int).", new RuntimeException());
744        }
745        return d;
746    }
747
748    /**
749     * Return a drawable object associated with a particular resource ID and
750     * styled for the specified theme. Various types of objects will be
751     * returned depending on the underlying resource -- for example, a solid
752     * color, PNG image, scalable image, etc.
753     *
754     * @param id The desired resource identifier, as generated by the aapt
755     *           tool. This integer encodes the package, type, and resource
756     *           entry. The value 0 is an invalid identifier.
757     * @param theme The theme used to style the drawable attributes, may be {@code null}.
758     * @return Drawable An object that can be used to draw this resource.
759     * @throws NotFoundException Throws NotFoundException if the given ID does
760     *         not exist.
761     */
762    public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
763            throws NotFoundException {
764        final TypedValue value = obtainTempTypedValue();
765        try {
766            final ResourcesImpl impl = mResourcesImpl;
767            impl.getValue(id, value, true);
768            return impl.loadDrawable(this, value, id, theme, true);
769        } finally {
770            releaseTempTypedValue(value);
771        }
772    }
773
774    /**
775     * Return a drawable object associated with a particular resource ID for the
776     * given screen density in DPI. This will set the drawable's density to be
777     * the device's density multiplied by the ratio of actual drawable density
778     * to requested density. This allows the drawable to be scaled up to the
779     * correct size if needed. Various types of objects will be returned
780     * depending on the underlying resource -- for example, a solid color, PNG
781     * image, scalable image, etc. The Drawable API hides these implementation
782     * details.
783     *
784     * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
785     * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
786     * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired
787     * theme.</p>
788     *
789     * @param id The desired resource identifier, as generated by the aapt tool.
790     *            This integer encodes the package, type, and resource entry.
791     *            The value 0 is an invalid identifier.
792     * @param density the desired screen density indicated by the resource as
793     *            found in {@link DisplayMetrics}.
794     * @return Drawable An object that can be used to draw this resource.
795     * @throws NotFoundException Throws NotFoundException if the given ID does
796     *             not exist.
797     * @see #getDrawableForDensity(int, int, Theme)
798     * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
799     */
800    @Deprecated
801    public Drawable getDrawableForDensity(@DrawableRes int id, int density)
802            throws NotFoundException {
803        return getDrawableForDensity(id, density, null);
804    }
805
806    /**
807     * Return a drawable object associated with a particular resource ID for the
808     * given screen density in DPI and styled for the specified theme.
809     *
810     * @param id The desired resource identifier, as generated by the aapt tool.
811     *            This integer encodes the package, type, and resource entry.
812     *            The value 0 is an invalid identifier.
813     * @param density The desired screen density indicated by the resource as
814     *            found in {@link DisplayMetrics}.
815     * @param theme The theme used to style the drawable attributes, may be {@code null}.
816     * @return Drawable An object that can be used to draw this resource.
817     * @throws NotFoundException Throws NotFoundException if the given ID does
818     *             not exist.
819     */
820    public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
821        final TypedValue value = obtainTempTypedValue();
822        try {
823            final ResourcesImpl impl = mResourcesImpl;
824            impl.getValueForDensity(id, density, value, true);
825
826            // If the drawable's XML lives in our current density qualifier,
827            // it's okay to use a scaled version from the cache. Otherwise, we
828            // need to actually load the drawable from XML.
829            final DisplayMetrics metrics = impl.getDisplayMetrics();
830            final boolean useCache = value.density == metrics.densityDpi;
831
832            /*
833             * Pretend the requested density is actually the display density. If
834             * the drawable returned is not the requested density, then force it
835             * to be scaled later by dividing its density by the ratio of
836             * requested density to actual device density. Drawables that have
837             * undefined density or no density don't need to be handled here.
838             */
839            if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
840                if (value.density == density) {
841                    value.density = metrics.densityDpi;
842                } else {
843                    value.density = (value.density * metrics.densityDpi) / density;
844                }
845            }
846            return impl.loadDrawable(this, value, id, theme, useCache);
847        } finally {
848            releaseTempTypedValue(value);
849        }
850    }
851
852    @NonNull
853    Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
854            throws NotFoundException {
855        return mResourcesImpl.loadDrawable(this, value, id, theme, true);
856    }
857
858    /**
859     * Return a movie object associated with the particular resource ID.
860     * @param id The desired resource identifier, as generated by the aapt
861     *           tool. This integer encodes the package, type, and resource
862     *           entry. The value 0 is an invalid identifier.
863     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
864     *
865     */
866    public Movie getMovie(@RawRes int id) throws NotFoundException {
867        final InputStream is = openRawResource(id);
868        final Movie movie = Movie.decodeStream(is);
869        try {
870            is.close();
871        } catch (IOException e) {
872            // No one cares.
873        }
874        return movie;
875    }
876
877    /**
878     * Returns a color integer associated with a particular resource ID. If the
879     * resource holds a complex {@link ColorStateList}, then the default color
880     * from the set is returned.
881     *
882     * @param id The desired resource identifier, as generated by the aapt
883     *           tool. This integer encodes the package, type, and resource
884     *           entry. The value 0 is an invalid identifier.
885     *
886     * @throws NotFoundException Throws NotFoundException if the given ID does
887     *         not exist.
888     *
889     * @return A single color value in the form 0xAARRGGBB.
890     * @deprecated Use {@link #getColor(int, Theme)} instead.
891     */
892    @ColorInt
893    @Deprecated
894    public int getColor(@ColorRes int id) throws NotFoundException {
895        return getColor(id, null);
896    }
897
898    /**
899     * Returns a themed color integer associated with a particular resource ID.
900     * If the resource holds a complex {@link ColorStateList}, then the default
901     * color from the set is returned.
902     *
903     * @param id The desired resource identifier, as generated by the aapt
904     *           tool. This integer encodes the package, type, and resource
905     *           entry. The value 0 is an invalid identifier.
906     * @param theme The theme used to style the color attributes, may be
907     *              {@code null}.
908     *
909     * @throws NotFoundException Throws NotFoundException if the given ID does
910     *         not exist.
911     *
912     * @return A single color value in the form 0xAARRGGBB.
913     */
914    @ColorInt
915    public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
916        final TypedValue value = obtainTempTypedValue();
917        try {
918            final ResourcesImpl impl = mResourcesImpl;
919            impl.getValue(id, value, true);
920            if (value.type >= TypedValue.TYPE_FIRST_INT
921                    && value.type <= TypedValue.TYPE_LAST_INT) {
922                return value.data;
923            } else if (value.type != TypedValue.TYPE_STRING) {
924                throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
925                        + " type #0x" + Integer.toHexString(value.type) + " is not valid");
926            }
927
928            final ColorStateList csl = impl.loadColorStateList(this, value, id, theme);
929            return csl.getDefaultColor();
930        } finally {
931            releaseTempTypedValue(value);
932        }
933    }
934
935    /**
936     * Returns a color state list associated with a particular resource ID. The
937     * resource may contain either a single raw color value or a complex
938     * {@link ColorStateList} holding multiple possible colors.
939     *
940     * @param id The desired resource identifier of a {@link ColorStateList},
941     *           as generated by the aapt tool. This integer encodes the
942     *           package, type, and resource entry. The value 0 is an invalid
943     *           identifier.
944     *
945     * @throws NotFoundException Throws NotFoundException if the given ID does
946     *         not exist.
947     *
948     * @return A ColorStateList object containing either a single solid color
949     *         or multiple colors that can be selected based on a state.
950     * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
951     */
952    @Nullable
953    @Deprecated
954    public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
955        final ColorStateList csl = getColorStateList(id, null);
956        if (csl != null && csl.canApplyTheme()) {
957            Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
958                    + "unresolved theme attributes! Consider using "
959                    + "Resources.getColorStateList(int, Theme) or "
960                    + "Context.getColorStateList(int).", new RuntimeException());
961        }
962        return csl;
963    }
964
965    /**
966     * Returns a themed color state list associated with a particular resource
967     * ID. The resource may contain either a single raw color value or a
968     * complex {@link ColorStateList} holding multiple possible colors.
969     *
970     * @param id The desired resource identifier of a {@link ColorStateList},
971     *           as generated by the aapt tool. This integer encodes the
972     *           package, type, and resource entry. The value 0 is an invalid
973     *           identifier.
974     * @param theme The theme used to style the color attributes, may be
975     *              {@code null}.
976     *
977     * @throws NotFoundException Throws NotFoundException if the given ID does
978     *         not exist.
979     *
980     * @return A themed ColorStateList object containing either a single solid
981     *         color or multiple colors that can be selected based on a state.
982     */
983    @Nullable
984    public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
985            throws NotFoundException {
986        final TypedValue value = obtainTempTypedValue();
987        try {
988            final ResourcesImpl impl = mResourcesImpl;
989            impl.getValue(id, value, true);
990            return impl.loadColorStateList(this, value, id, theme);
991        } finally {
992            releaseTempTypedValue(value);
993        }
994    }
995
996    @Nullable
997    ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
998            throws NotFoundException {
999        return mResourcesImpl.loadColorStateList(this, value, id, theme);
1000    }
1001
1002    /**
1003     * @hide
1004     */
1005    @Nullable
1006    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
1007        return mResourcesImpl.loadComplexColor(this, value, id, theme);
1008    }
1009
1010    /**
1011     * Return a boolean associated with a particular resource ID.  This can be
1012     * used with any integral resource value, and will return true if it is
1013     * non-zero.
1014     *
1015     * @param id The desired resource identifier, as generated by the aapt
1016     *           tool. This integer encodes the package, type, and resource
1017     *           entry. The value 0 is an invalid identifier.
1018     *
1019     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1020     *
1021     * @return Returns the boolean value contained in the resource.
1022     */
1023    public boolean getBoolean(@BoolRes int id) throws NotFoundException {
1024        final TypedValue value = obtainTempTypedValue();
1025        try {
1026            mResourcesImpl.getValue(id, value, true);
1027            if (value.type >= TypedValue.TYPE_FIRST_INT
1028                    && value.type <= TypedValue.TYPE_LAST_INT) {
1029                return value.data != 0;
1030            }
1031            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1032                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1033        } finally {
1034            releaseTempTypedValue(value);
1035        }
1036    }
1037
1038    /**
1039     * Return an integer associated with a particular resource ID.
1040     *
1041     * @param id The desired resource identifier, as generated by the aapt
1042     *           tool. This integer encodes the package, type, and resource
1043     *           entry. The value 0 is an invalid identifier.
1044     *
1045     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1046     *
1047     * @return Returns the integer value contained in the resource.
1048     */
1049    public int getInteger(@IntegerRes int id) throws NotFoundException {
1050        final TypedValue value = obtainTempTypedValue();
1051        try {
1052            mResourcesImpl.getValue(id, value, true);
1053            if (value.type >= TypedValue.TYPE_FIRST_INT
1054                    && value.type <= TypedValue.TYPE_LAST_INT) {
1055                return value.data;
1056            }
1057            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1058                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1059        } finally {
1060            releaseTempTypedValue(value);
1061        }
1062    }
1063
1064    /**
1065     * Retrieve a floating-point value for a particular resource ID.
1066     *
1067     * @param id The desired resource identifier, as generated by the aapt
1068     *           tool. This integer encodes the package, type, and resource
1069     *           entry. The value 0 is an invalid identifier.
1070     *
1071     * @return Returns the floating-point value contained in the resource.
1072     *
1073     * @throws NotFoundException Throws NotFoundException if the given ID does
1074     *         not exist or is not a floating-point value.
1075     * @hide Pending API council approval.
1076     */
1077    public float getFloat(int id) {
1078        final TypedValue value = obtainTempTypedValue();
1079        try {
1080            mResourcesImpl.getValue(id, value, true);
1081            if (value.type == TypedValue.TYPE_FLOAT) {
1082                return value.getFloat();
1083            }
1084            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1085                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1086        } finally {
1087            releaseTempTypedValue(value);
1088        }
1089    }
1090
1091    /**
1092     * Return an XmlResourceParser through which you can read a view layout
1093     * description for the given resource ID.  This parser has limited
1094     * functionality -- in particular, you can't change its input, and only
1095     * the high-level events are available.
1096     *
1097     * <p>This function is really a simple wrapper for calling
1098     * {@link #getXml} with a layout resource.
1099     *
1100     * @param id The desired resource identifier, as generated by the aapt
1101     *           tool. This integer encodes the package, type, and resource
1102     *           entry. The value 0 is an invalid identifier.
1103     *
1104     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1105     *
1106     * @return A new parser object through which you can read
1107     *         the XML data.
1108     *
1109     * @see #getXml
1110     */
1111    public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
1112        return loadXmlResourceParser(id, "layout");
1113    }
1114
1115    /**
1116     * Return an XmlResourceParser through which you can read an animation
1117     * description for the given resource ID.  This parser has limited
1118     * functionality -- in particular, you can't change its input, and only
1119     * the high-level events are available.
1120     *
1121     * <p>This function is really a simple wrapper for calling
1122     * {@link #getXml} with an animation resource.
1123     *
1124     * @param id The desired resource identifier, as generated by the aapt
1125     *           tool. This integer encodes the package, type, and resource
1126     *           entry. The value 0 is an invalid identifier.
1127     *
1128     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1129     *
1130     * @return A new parser object through which you can read
1131     *         the XML data.
1132     *
1133     * @see #getXml
1134     */
1135    public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
1136        return loadXmlResourceParser(id, "anim");
1137    }
1138
1139    /**
1140     * Return an XmlResourceParser through which you can read a generic XML
1141     * resource for the given resource ID.
1142     *
1143     * <p>The XmlPullParser implementation returned here has some limited
1144     * functionality.  In particular, you can't change its input, and only
1145     * high-level parsing events are available (since the document was
1146     * pre-parsed for you at build time, which involved merging text and
1147     * stripping comments).
1148     *
1149     * @param id The desired resource identifier, as generated by the aapt
1150     *           tool. This integer encodes the package, type, and resource
1151     *           entry. The value 0 is an invalid identifier.
1152     *
1153     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1154     *
1155     * @return A new parser object through which you can read
1156     *         the XML data.
1157     *
1158     * @see android.util.AttributeSet
1159     */
1160    public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
1161        return loadXmlResourceParser(id, "xml");
1162    }
1163
1164    /**
1165     * Open a data stream for reading a raw resource.  This can only be used
1166     * with resources whose value is the name of an asset files -- that is, it can be
1167     * used to open drawable, sound, and raw resources; it will fail on string
1168     * and color resources.
1169     *
1170     * @param id The resource identifier to open, as generated by the appt
1171     *           tool.
1172     *
1173     * @return InputStream Access to the resource data.
1174     *
1175     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1176     *
1177     */
1178    public InputStream openRawResource(@RawRes int id) throws NotFoundException {
1179        final TypedValue value = obtainTempTypedValue();
1180        try {
1181            return openRawResource(id, value);
1182        } finally {
1183            releaseTempTypedValue(value);
1184        }
1185    }
1186
1187    /**
1188     * Returns a TypedValue suitable for temporary use. The obtained TypedValue
1189     * should be released using {@link #releaseTempTypedValue(TypedValue)}.
1190     *
1191     * @return a typed value suitable for temporary use
1192     */
1193    private TypedValue obtainTempTypedValue() {
1194        TypedValue tmpValue = null;
1195        synchronized (mTmpValueLock) {
1196            if (mTmpValue != null) {
1197                tmpValue = mTmpValue;
1198                mTmpValue = null;
1199            }
1200        }
1201        if (tmpValue == null) {
1202            return new TypedValue();
1203        }
1204        return tmpValue;
1205    }
1206
1207    /**
1208     * Returns a TypedValue to the pool. After calling this method, the
1209     * specified TypedValue should no longer be accessed.
1210     *
1211     * @param value the typed value to return to the pool
1212     */
1213    private void releaseTempTypedValue(TypedValue value) {
1214        synchronized (mTmpValueLock) {
1215            if (mTmpValue == null) {
1216                mTmpValue = value;
1217            }
1218        }
1219    }
1220
1221    /**
1222     * Open a data stream for reading a raw resource.  This can only be used
1223     * with resources whose value is the name of an asset file -- that is, it can be
1224     * used to open drawable, sound, and raw resources; it will fail on string
1225     * and color resources.
1226     *
1227     * @param id The resource identifier to open, as generated by the appt tool.
1228     * @param value The TypedValue object to hold the resource information.
1229     *
1230     * @return InputStream Access to the resource data.
1231     *
1232     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1233     */
1234    public InputStream openRawResource(@RawRes int id, TypedValue value)
1235            throws NotFoundException {
1236        return mResourcesImpl.openRawResource(id, value);
1237    }
1238
1239    /**
1240     * Open a file descriptor for reading a raw resource.  This can only be used
1241     * with resources whose value is the name of an asset files -- that is, it can be
1242     * used to open drawable, sound, and raw resources; it will fail on string
1243     * and color resources.
1244     *
1245     * <p>This function only works for resources that are stored in the package
1246     * as uncompressed data, which typically includes things like mp3 files
1247     * and png images.
1248     *
1249     * @param id The resource identifier to open, as generated by the appt
1250     *           tool.
1251     *
1252     * @return AssetFileDescriptor A new file descriptor you can use to read
1253     * the resource.  This includes the file descriptor itself, as well as the
1254     * offset and length of data where the resource appears in the file.  A
1255     * null is returned if the file exists but is compressed.
1256     *
1257     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1258     *
1259     */
1260    public AssetFileDescriptor openRawResourceFd(@RawRes int id)
1261            throws NotFoundException {
1262        final TypedValue value = obtainTempTypedValue();
1263        try {
1264            return mResourcesImpl.openRawResourceFd(id, value);
1265        } finally {
1266            releaseTempTypedValue(value);
1267        }
1268    }
1269
1270    /**
1271     * Return the raw data associated with a particular resource ID.
1272     *
1273     * @param id The desired resource identifier, as generated by the aapt
1274     *           tool. This integer encodes the package, type, and resource
1275     *           entry. The value 0 is an invalid identifier.
1276     * @param outValue Object in which to place the resource data.
1277     * @param resolveRefs If true, a resource that is a reference to another
1278     *                    resource will be followed so that you receive the
1279     *                    actual final resource data.  If false, the TypedValue
1280     *                    will be filled in with the reference itself.
1281     *
1282     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1283     *
1284     */
1285    public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
1286            throws NotFoundException {
1287        mResourcesImpl.getValue(id, outValue, resolveRefs);
1288    }
1289
1290    /**
1291     * Get the raw value associated with a resource with associated density.
1292     *
1293     * @param id resource identifier
1294     * @param density density in DPI
1295     * @param resolveRefs If true, a resource that is a reference to another
1296     *            resource will be followed so that you receive the actual final
1297     *            resource data. If false, the TypedValue will be filled in with
1298     *            the reference itself.
1299     * @throws NotFoundException Throws NotFoundException if the given ID does
1300     *             not exist.
1301     * @see #getValue(String, TypedValue, boolean)
1302     */
1303    public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
1304            boolean resolveRefs) throws NotFoundException {
1305        mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
1306    }
1307
1308    /**
1309     * Return the raw data associated with a particular resource ID.
1310     * See getIdentifier() for information on how names are mapped to resource
1311     * IDs, and getString(int) for information on how string resources are
1312     * retrieved.
1313     *
1314     * <p>Note: use of this function is discouraged.  It is much more
1315     * efficient to retrieve resources by identifier than by name.
1316     *
1317     * @param name The name of the desired resource.  This is passed to
1318     *             getIdentifier() with a default type of "string".
1319     * @param outValue Object in which to place the resource data.
1320     * @param resolveRefs If true, a resource that is a reference to another
1321     *                    resource will be followed so that you receive the
1322     *                    actual final resource data.  If false, the TypedValue
1323     *                    will be filled in with the reference itself.
1324     *
1325     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1326     *
1327     */
1328    public void getValue(String name, TypedValue outValue, boolean resolveRefs)
1329            throws NotFoundException {
1330        mResourcesImpl.getValue(name, outValue, resolveRefs);
1331    }
1332
1333    /**
1334     * This class holds the current attribute values for a particular theme.
1335     * In other words, a Theme is a set of values for resource attributes;
1336     * these are used in conjunction with {@link TypedArray}
1337     * to resolve the final value for an attribute.
1338     *
1339     * <p>The Theme's attributes come into play in two ways: (1) a styled
1340     * attribute can explicit reference a value in the theme through the
1341     * "?themeAttribute" syntax; (2) if no value has been defined for a
1342     * particular styled attribute, as a last resort we will try to find that
1343     * attribute's value in the Theme.
1344     *
1345     * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
1346     * retrieve XML attributes with style and theme information applied.
1347     */
1348    public final class Theme {
1349        private ResourcesImpl.ThemeImpl mThemeImpl;
1350
1351        private Theme() {
1352        }
1353
1354        void setImpl(ResourcesImpl.ThemeImpl impl) {
1355            mThemeImpl = impl;
1356        }
1357
1358        /**
1359         * Place new attribute values into the theme.  The style resource
1360         * specified by <var>resid</var> will be retrieved from this Theme's
1361         * resources, its values placed into the Theme object.
1362         *
1363         * <p>The semantics of this function depends on the <var>force</var>
1364         * argument:  If false, only values that are not already defined in
1365         * the theme will be copied from the system resource; otherwise, if
1366         * any of the style's attributes are already defined in the theme, the
1367         * current values in the theme will be overwritten.
1368         *
1369         * @param resId The resource ID of a style resource from which to
1370         *              obtain attribute values.
1371         * @param force If true, values in the style resource will always be
1372         *              used in the theme; otherwise, they will only be used
1373         *              if not already defined in the theme.
1374         */
1375        public void applyStyle(int resId, boolean force) {
1376            mThemeImpl.applyStyle(resId, force);
1377        }
1378
1379        /**
1380         * Set this theme to hold the same contents as the theme
1381         * <var>other</var>.  If both of these themes are from the same
1382         * Resources object, they will be identical after this function
1383         * returns.  If they are from different Resources, only the resources
1384         * they have in common will be set in this theme.
1385         *
1386         * @param other The existing Theme to copy from.
1387         */
1388        public void setTo(Theme other) {
1389            mThemeImpl.setTo(other.mThemeImpl);
1390        }
1391
1392        /**
1393         * Return a TypedArray holding the values defined by
1394         * <var>Theme</var> which are listed in <var>attrs</var>.
1395         *
1396         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1397         * with the array.
1398         *
1399         * @param attrs The desired attributes.
1400         *
1401         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1402         *
1403         * @return Returns a TypedArray holding an array of the attribute values.
1404         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1405         * when done with it.
1406         *
1407         * @see Resources#obtainAttributes
1408         * @see #obtainStyledAttributes(int, int[])
1409         * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1410         */
1411        public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
1412            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
1413        }
1414
1415        /**
1416         * Return a TypedArray holding the values defined by the style
1417         * resource <var>resid</var> which are listed in <var>attrs</var>.
1418         *
1419         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1420         * with the array.
1421         *
1422         * @param resId The desired style resource.
1423         * @param attrs The desired attributes in the style.
1424         *
1425         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1426         *
1427         * @return Returns a TypedArray holding an array of the attribute values.
1428         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1429         * when done with it.
1430         *
1431         * @see Resources#obtainAttributes
1432         * @see #obtainStyledAttributes(int[])
1433         * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1434         */
1435        public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
1436                throws NotFoundException {
1437            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
1438        }
1439
1440        /**
1441         * Return a TypedArray holding the attribute values in
1442         * <var>set</var>
1443         * that are listed in <var>attrs</var>.  In addition, if the given
1444         * AttributeSet specifies a style class (through the "style" attribute),
1445         * that style will be applied on top of the base attributes it defines.
1446         *
1447         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1448         * with the array.
1449         *
1450         * <p>When determining the final value of a particular attribute, there
1451         * are four inputs that come into play:</p>
1452         *
1453         * <ol>
1454         *     <li> Any attribute values in the given AttributeSet.
1455         *     <li> The style resource specified in the AttributeSet (named
1456         *     "style").
1457         *     <li> The default style specified by <var>defStyleAttr</var> and
1458         *     <var>defStyleRes</var>
1459         *     <li> The base values in this theme.
1460         * </ol>
1461         *
1462         * <p>Each of these inputs is considered in-order, with the first listed
1463         * taking precedence over the following ones.  In other words, if in the
1464         * AttributeSet you have supplied <code>&lt;Button
1465         * textColor="#ff000000"&gt;</code>, then the button's text will
1466         * <em>always</em> be black, regardless of what is specified in any of
1467         * the styles.
1468         *
1469         * @param set The base set of attribute values.  May be null.
1470         * @param attrs The desired attributes to be retrieved.
1471         * @param defStyleAttr An attribute in the current theme that contains a
1472         *                     reference to a style resource that supplies
1473         *                     defaults values for the TypedArray.  Can be
1474         *                     0 to not look for defaults.
1475         * @param defStyleRes A resource identifier of a style resource that
1476         *                    supplies default values for the TypedArray,
1477         *                    used only if defStyleAttr is 0 or can not be found
1478         *                    in the theme.  Can be 0 to not look for defaults.
1479         *
1480         * @return Returns a TypedArray holding an array of the attribute values.
1481         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1482         * when done with it.
1483         *
1484         * @see Resources#obtainAttributes
1485         * @see #obtainStyledAttributes(int[])
1486         * @see #obtainStyledAttributes(int, int[])
1487         */
1488        public TypedArray obtainStyledAttributes(AttributeSet set,
1489                @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
1490            return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
1491        }
1492
1493        /**
1494         * Retrieve the values for a set of attributes in the Theme. The
1495         * contents of the typed array are ultimately filled in by
1496         * {@link Resources#getValue}.
1497         *
1498         * @param values The base set of attribute values, must be equal in
1499         *               length to {@code attrs}. All values must be of type
1500         *               {@link TypedValue#TYPE_ATTRIBUTE}.
1501         * @param attrs The desired attributes to be retrieved.
1502         * @return Returns a TypedArray holding an array of the attribute
1503         *         values. Be sure to call {@link TypedArray#recycle()}
1504         *         when done with it.
1505         * @hide
1506         */
1507        @NonNull
1508        public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
1509            return mThemeImpl.resolveAttributes(this, values, attrs);
1510        }
1511
1512        /**
1513         * Retrieve the value of an attribute in the Theme.  The contents of
1514         * <var>outValue</var> are ultimately filled in by
1515         * {@link Resources#getValue}.
1516         *
1517         * @param resid The resource identifier of the desired theme
1518         *              attribute.
1519         * @param outValue Filled in with the ultimate resource value supplied
1520         *                 by the attribute.
1521         * @param resolveRefs If true, resource references will be walked; if
1522         *                    false, <var>outValue</var> may be a
1523         *                    TYPE_REFERENCE.  In either case, it will never
1524         *                    be a TYPE_ATTRIBUTE.
1525         *
1526         * @return boolean Returns true if the attribute was found and
1527         *         <var>outValue</var> is valid, else false.
1528         */
1529        public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1530            return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
1531        }
1532
1533        /**
1534         * Gets all of the attribute ids associated with this {@link Theme}. For debugging only.
1535         *
1536         * @return The int array containing attribute ids associated with this {@link Theme}.
1537         * @hide
1538         */
1539        public int[] getAllAttributes() {
1540            return mThemeImpl.getAllAttributes();
1541        }
1542
1543        /**
1544         * Returns the resources to which this theme belongs.
1545         *
1546         * @return Resources to which this theme belongs.
1547         */
1548        public Resources getResources() {
1549            return Resources.this;
1550        }
1551
1552        /**
1553         * Return a drawable object associated with a particular resource ID
1554         * and styled for the Theme.
1555         *
1556         * @param id The desired resource identifier, as generated by the aapt
1557         *           tool. This integer encodes the package, type, and resource
1558         *           entry. The value 0 is an invalid identifier.
1559         * @return Drawable An object that can be used to draw this resource.
1560         * @throws NotFoundException Throws NotFoundException if the given ID
1561         *         does not exist.
1562         */
1563        public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
1564            return Resources.this.getDrawable(id, this);
1565        }
1566
1567        /**
1568         * Returns a bit mask of configuration changes that will impact this
1569         * theme (and thus require completely reloading it).
1570         *
1571         * @return a bit mask of configuration changes, as defined by
1572         *         {@link ActivityInfo}
1573         * @see ActivityInfo
1574         */
1575        public int getChangingConfigurations() {
1576            return mThemeImpl.getChangingConfigurations();
1577        }
1578
1579        /**
1580         * Print contents of this theme out to the log.  For debugging only.
1581         *
1582         * @param priority The log priority to use.
1583         * @param tag The log tag to use.
1584         * @param prefix Text to prefix each line printed.
1585         */
1586        public void dump(int priority, String tag, String prefix) {
1587            mThemeImpl.dump(priority, tag, prefix);
1588        }
1589
1590        // Needed by layoutlib.
1591        /*package*/ long getNativeTheme() {
1592            return mThemeImpl.getNativeTheme();
1593        }
1594
1595        /*package*/ int getAppliedStyleResId() {
1596            return mThemeImpl.getAppliedStyleResId();
1597        }
1598
1599        /**
1600         * @hide
1601         */
1602        public ThemeKey getKey() {
1603            return mThemeImpl.getKey();
1604        }
1605
1606        private String getResourceNameFromHexString(String hexString) {
1607            return getResourceName(Integer.parseInt(hexString, 16));
1608        }
1609
1610        /**
1611         * Parses {@link #getKey()} and returns a String array that holds pairs of
1612         * adjacent Theme data: resource name followed by whether or not it was
1613         * forced, as specified by {@link #applyStyle(int, boolean)}.
1614         *
1615         * @hide
1616         */
1617        @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
1618        public String[] getTheme() {
1619            return mThemeImpl.getTheme();
1620        }
1621
1622        /** @hide */
1623        public void encode(@NonNull ViewHierarchyEncoder encoder) {
1624            encoder.beginObject(this);
1625            final String[] properties = getTheme();
1626            for (int i = 0; i < properties.length; i += 2) {
1627                encoder.addProperty(properties[i], properties[i+1]);
1628            }
1629            encoder.endObject();
1630        }
1631
1632        /**
1633         * Rebases the theme against the parent Resource object's current
1634         * configuration by re-applying the styles passed to
1635         * {@link #applyStyle(int, boolean)}.
1636         *
1637         * @hide
1638         */
1639        public void rebase() {
1640            mThemeImpl.rebase();
1641        }
1642    }
1643
1644    static class ThemeKey implements Cloneable {
1645        int[] mResId;
1646        boolean[] mForce;
1647        int mCount;
1648
1649        private int mHashCode = 0;
1650
1651        public void append(int resId, boolean force) {
1652            if (mResId == null) {
1653                mResId = new int[4];
1654            }
1655
1656            if (mForce == null) {
1657                mForce = new boolean[4];
1658            }
1659
1660            mResId = GrowingArrayUtils.append(mResId, mCount, resId);
1661            mForce = GrowingArrayUtils.append(mForce, mCount, force);
1662            mCount++;
1663
1664            mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
1665        }
1666
1667        /**
1668         * Sets up this key as a deep copy of another key.
1669         *
1670         * @param other the key to deep copy into this key
1671         */
1672        public void setTo(ThemeKey other) {
1673            mResId = other.mResId == null ? null : other.mResId.clone();
1674            mForce = other.mForce == null ? null : other.mForce.clone();
1675            mCount = other.mCount;
1676        }
1677
1678        @Override
1679        public int hashCode() {
1680            return mHashCode;
1681        }
1682
1683        @Override
1684        public boolean equals(Object o) {
1685            if (this == o) {
1686                return true;
1687            }
1688
1689            if (o == null || getClass() != o.getClass() || hashCode() != o.hashCode()) {
1690                return false;
1691            }
1692
1693            final ThemeKey t = (ThemeKey) o;
1694            if (mCount != t.mCount) {
1695                return false;
1696            }
1697
1698            final int N = mCount;
1699            for (int i = 0; i < N; i++) {
1700                if (mResId[i] != t.mResId[i] || mForce[i] != t.mForce[i]) {
1701                    return false;
1702                }
1703            }
1704
1705            return true;
1706        }
1707
1708        /**
1709         * @return a shallow copy of this key
1710         */
1711        @Override
1712        public ThemeKey clone() {
1713            final ThemeKey other = new ThemeKey();
1714            other.mResId = mResId;
1715            other.mForce = mForce;
1716            other.mCount = mCount;
1717            other.mHashCode = mHashCode;
1718            return other;
1719        }
1720    }
1721
1722    /**
1723     * Generate a new Theme object for this set of Resources.  It initially
1724     * starts out empty.
1725     *
1726     * @return Theme The newly created Theme container.
1727     */
1728    public final Theme newTheme() {
1729        Theme theme = new Theme();
1730        theme.setImpl(mResourcesImpl.newThemeImpl());
1731        mThemeRefs.add(new WeakReference<>(theme));
1732        return theme;
1733    }
1734
1735    /**
1736     * Retrieve a set of basic attribute values from an AttributeSet, not
1737     * performing styling of them using a theme and/or style resources.
1738     *
1739     * @param set The current attribute values to retrieve.
1740     * @param attrs The specific attributes to be retrieved.
1741     * @return Returns a TypedArray holding an array of the attribute values.
1742     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1743     * when done with it.
1744     *
1745     * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1746     */
1747    public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1748        int len = attrs.length;
1749        TypedArray array = TypedArray.obtain(this, len);
1750
1751        // XXX note that for now we only work with compiled XML files.
1752        // To support generic XML files we will need to manually parse
1753        // out the attributes from the XML file (applying type information
1754        // contained in the resources and such).
1755        XmlBlock.Parser parser = (XmlBlock.Parser)set;
1756        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
1757                array.mData, array.mIndices);
1758
1759        array.mXml = parser;
1760
1761        return array;
1762    }
1763
1764    /**
1765     * Store the newly updated configuration.
1766     */
1767    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
1768        updateConfiguration(config, metrics, null);
1769    }
1770
1771    /**
1772     * @hide
1773     */
1774    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
1775                                    CompatibilityInfo compat) {
1776        mResourcesImpl.updateConfiguration(config, metrics, compat);
1777    }
1778
1779    /**
1780     * Update the system resources configuration if they have previously
1781     * been initialized.
1782     *
1783     * @hide
1784     */
1785    public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
1786            CompatibilityInfo compat) {
1787        if (mSystem != null) {
1788            mSystem.updateConfiguration(config, metrics, compat);
1789            //Log.i(TAG, "Updated system resources " + mSystem
1790            //        + ": " + mSystem.getConfiguration());
1791        }
1792    }
1793
1794    /**
1795     * Return the current display metrics that are in effect for this resource
1796     * object.  The returned object should be treated as read-only.
1797     *
1798     * @return The resource's current display metrics.
1799     */
1800    public DisplayMetrics getDisplayMetrics() {
1801        return mResourcesImpl.getDisplayMetrics();
1802    }
1803
1804    /**
1805     * Return the current configuration that is in effect for this resource
1806     * object.  The returned object should be treated as read-only.
1807     *
1808     * @return The resource's current configuration.
1809     */
1810    public Configuration getConfiguration() {
1811        return mResourcesImpl.getConfiguration();
1812    }
1813
1814    /** @hide */
1815    public Configuration[] getSizeConfigurations() {
1816        return mResourcesImpl.getSizeConfigurations();
1817    }
1818
1819    /**
1820     * Return the compatibility mode information for the application.
1821     * The returned object should be treated as read-only.
1822     *
1823     * @return compatibility info.
1824     * @hide
1825     */
1826    public CompatibilityInfo getCompatibilityInfo() {
1827        return mResourcesImpl.getCompatibilityInfo();
1828    }
1829
1830    /**
1831     * This is just for testing.
1832     * @hide
1833     */
1834    @VisibleForTesting
1835    public void setCompatibilityInfo(CompatibilityInfo ci) {
1836        if (ci != null) {
1837            mResourcesImpl.updateConfiguration(null, null, ci);
1838        }
1839    }
1840
1841    /**
1842     * Return a resource identifier for the given resource name.  A fully
1843     * qualified resource name is of the form "package:type/entry".  The first
1844     * two components (package and type) are optional if defType and
1845     * defPackage, respectively, are specified here.
1846     *
1847     * <p>Note: use of this function is discouraged.  It is much more
1848     * efficient to retrieve resources by identifier than by name.
1849     *
1850     * @param name The name of the desired resource.
1851     * @param defType Optional default resource type to find, if "type/" is
1852     *                not included in the name.  Can be null to require an
1853     *                explicit type.
1854     * @param defPackage Optional default package to find, if "package:" is
1855     *                   not included in the name.  Can be null to require an
1856     *                   explicit package.
1857     *
1858     * @return int The associated resource identifier.  Returns 0 if no such
1859     *         resource was found.  (0 is not a valid resource ID.)
1860     */
1861    public int getIdentifier(String name, String defType, String defPackage) {
1862        return mResourcesImpl.getIdentifier(name, defType, defPackage);
1863    }
1864
1865    /**
1866     * Return true if given resource identifier includes a package.
1867     *
1868     * @hide
1869     */
1870    public static boolean resourceHasPackage(@AnyRes int resid) {
1871        return (resid >>> 24) != 0;
1872    }
1873
1874    /**
1875     * Return the full name for a given resource identifier.  This name is
1876     * a single string of the form "package:type/entry".
1877     *
1878     * @param resid The resource identifier whose name is to be retrieved.
1879     *
1880     * @return A string holding the name of the resource.
1881     *
1882     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1883     *
1884     * @see #getResourcePackageName
1885     * @see #getResourceTypeName
1886     * @see #getResourceEntryName
1887     */
1888    public String getResourceName(@AnyRes int resid) throws NotFoundException {
1889        return mResourcesImpl.getResourceName(resid);
1890    }
1891
1892    /**
1893     * Return the package name for a given resource identifier.
1894     *
1895     * @param resid The resource identifier whose package name is to be
1896     * retrieved.
1897     *
1898     * @return A string holding the package name of the resource.
1899     *
1900     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1901     *
1902     * @see #getResourceName
1903     */
1904    public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
1905        return mResourcesImpl.getResourcePackageName(resid);
1906    }
1907
1908    /**
1909     * Return the type name for a given resource identifier.
1910     *
1911     * @param resid The resource identifier whose type name is to be
1912     * retrieved.
1913     *
1914     * @return A string holding the type name of the resource.
1915     *
1916     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1917     *
1918     * @see #getResourceName
1919     */
1920    public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
1921        return mResourcesImpl.getResourceTypeName(resid);
1922    }
1923
1924    /**
1925     * Return the entry name for a given resource identifier.
1926     *
1927     * @param resid The resource identifier whose entry name is to be
1928     * retrieved.
1929     *
1930     * @return A string holding the entry name of the resource.
1931     *
1932     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1933     *
1934     * @see #getResourceName
1935     */
1936    public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
1937        return mResourcesImpl.getResourceEntryName(resid);
1938    }
1939
1940    /**
1941     * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
1942     * an XML file.  You call this when you are at the parent tag of the
1943     * extra tags, and it will return once all of the child tags have been parsed.
1944     * This will call {@link #parseBundleExtra} for each extra tag encountered.
1945     *
1946     * @param parser The parser from which to retrieve the extras.
1947     * @param outBundle A Bundle in which to place all parsed extras.
1948     * @throws XmlPullParserException
1949     * @throws IOException
1950     */
1951    public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
1952            throws XmlPullParserException, IOException {
1953        int outerDepth = parser.getDepth();
1954        int type;
1955        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1956               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1957            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1958                continue;
1959            }
1960
1961            String nodeName = parser.getName();
1962            if (nodeName.equals("extra")) {
1963                parseBundleExtra("extra", parser, outBundle);
1964                XmlUtils.skipCurrentTag(parser);
1965
1966            } else {
1967                XmlUtils.skipCurrentTag(parser);
1968            }
1969        }
1970    }
1971
1972    /**
1973     * Parse a name/value pair out of an XML tag holding that data.  The
1974     * AttributeSet must be holding the data defined by
1975     * {@link android.R.styleable#Extra}.  The following value types are supported:
1976     * <ul>
1977     * <li> {@link TypedValue#TYPE_STRING}:
1978     * {@link Bundle#putCharSequence Bundle.putCharSequence()}
1979     * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
1980     * {@link Bundle#putCharSequence Bundle.putBoolean()}
1981     * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
1982     * {@link Bundle#putCharSequence Bundle.putBoolean()}
1983     * <li> {@link TypedValue#TYPE_FLOAT}:
1984     * {@link Bundle#putCharSequence Bundle.putFloat()}
1985     * </ul>
1986     *
1987     * @param tagName The name of the tag these attributes come from; this is
1988     * only used for reporting error messages.
1989     * @param attrs The attributes from which to retrieve the name/value pair.
1990     * @param outBundle The Bundle in which to place the parsed value.
1991     * @throws XmlPullParserException If the attributes are not valid.
1992     */
1993    public void parseBundleExtra(String tagName, AttributeSet attrs,
1994            Bundle outBundle) throws XmlPullParserException {
1995        TypedArray sa = obtainAttributes(attrs,
1996                com.android.internal.R.styleable.Extra);
1997
1998        String name = sa.getString(
1999                com.android.internal.R.styleable.Extra_name);
2000        if (name == null) {
2001            sa.recycle();
2002            throw new XmlPullParserException("<" + tagName
2003                    + "> requires an android:name attribute at "
2004                    + attrs.getPositionDescription());
2005        }
2006
2007        TypedValue v = sa.peekValue(
2008                com.android.internal.R.styleable.Extra_value);
2009        if (v != null) {
2010            if (v.type == TypedValue.TYPE_STRING) {
2011                CharSequence cs = v.coerceToString();
2012                outBundle.putCharSequence(name, cs);
2013            } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2014                outBundle.putBoolean(name, v.data != 0);
2015            } else if (v.type >= TypedValue.TYPE_FIRST_INT
2016                    && v.type <= TypedValue.TYPE_LAST_INT) {
2017                outBundle.putInt(name, v.data);
2018            } else if (v.type == TypedValue.TYPE_FLOAT) {
2019                outBundle.putFloat(name, v.getFloat());
2020            } else {
2021                sa.recycle();
2022                throw new XmlPullParserException("<" + tagName
2023                        + "> only supports string, integer, float, color, and boolean at "
2024                        + attrs.getPositionDescription());
2025            }
2026        } else {
2027            sa.recycle();
2028            throw new XmlPullParserException("<" + tagName
2029                    + "> requires an android:value or android:resource attribute at "
2030                    + attrs.getPositionDescription());
2031        }
2032
2033        sa.recycle();
2034    }
2035
2036    /**
2037     * Retrieve underlying AssetManager storage for these resources.
2038     */
2039    public final AssetManager getAssets() {
2040        return mResourcesImpl.getAssets();
2041    }
2042
2043    /**
2044     * Call this to remove all cached loaded layout resources from the
2045     * Resources object.  Only intended for use with performance testing
2046     * tools.
2047     */
2048    public final void flushLayoutCache() {
2049        mResourcesImpl.flushLayoutCache();
2050    }
2051
2052    /**
2053     * Start preloading of resource data using this Resources object.  Only
2054     * for use by the zygote process for loading common system resources.
2055     * {@hide}
2056     */
2057    public final void startPreloading() {
2058        mResourcesImpl.startPreloading();
2059    }
2060
2061    /**
2062     * Called by zygote when it is done preloading resources, to change back
2063     * to normal Resources operation.
2064     */
2065    public final void finishPreloading() {
2066        mResourcesImpl.finishPreloading();
2067    }
2068
2069    /**
2070     * @hide
2071     */
2072    public LongSparseArray<ConstantState> getPreloadedDrawables() {
2073        return mResourcesImpl.getPreloadedDrawables();
2074    }
2075
2076    /**
2077     * Loads an XML parser for the specified file.
2078     *
2079     * @param id the resource identifier for the file
2080     * @param type the type of resource (used for logging)
2081     * @return a parser for the specified XML file
2082     * @throws NotFoundException if the file could not be loaded
2083     */
2084    @NonNull
2085    XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
2086            throws NotFoundException {
2087        final TypedValue value = obtainTempTypedValue();
2088        try {
2089            final ResourcesImpl impl = mResourcesImpl;
2090            impl.getValue(id, value, true);
2091            if (value.type == TypedValue.TYPE_STRING) {
2092                return impl.loadXmlResourceParser(value.string.toString(), id,
2093                        value.assetCookie, type);
2094            }
2095            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
2096                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
2097        } finally {
2098            releaseTempTypedValue(value);
2099        }
2100    }
2101
2102    /**
2103     * Loads an XML parser for the specified file.
2104     *
2105     * @param file the path for the XML file to parse
2106     * @param id the resource identifier for the file
2107     * @param assetCookie the asset cookie for the file
2108     * @param type the type of resource (used for logging)
2109     * @return a parser for the specified XML file
2110     * @throws NotFoundException if the file could not be loaded
2111     */
2112    @NonNull
2113    XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
2114                                            String type) throws NotFoundException {
2115        return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
2116    }
2117
2118    /**
2119     * Called by ConfigurationBoundResourceCacheTest.
2120     * @hide
2121     */
2122    @VisibleForTesting
2123    public int calcConfigChanges(Configuration config) {
2124        return mResourcesImpl.calcConfigChanges(config);
2125    }
2126
2127    /**
2128     * Obtains styled attributes from the theme, if available, or unstyled
2129     * resources if the theme is null.
2130     *
2131     * @hide
2132     */
2133    public static TypedArray obtainAttributes(
2134            Resources res, Theme theme, AttributeSet set, int[] attrs) {
2135        if (theme == null) {
2136            return res.obtainAttributes(set, attrs);
2137        }
2138        return theme.obtainStyledAttributes(set, attrs, 0, 0);
2139    }
2140}
2141