Resources.java revision 082614c6a57a115ee0c5975e3579bf34a178c0f8
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    @Nullable
1003    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
1004        return mResourcesImpl.loadComplexColor(this, value, id, theme);
1005    }
1006
1007    /**
1008     * Return a boolean associated with a particular resource ID.  This can be
1009     * used with any integral resource value, and will return true if it is
1010     * non-zero.
1011     *
1012     * @param id The desired resource identifier, as generated by the aapt
1013     *           tool. This integer encodes the package, type, and resource
1014     *           entry. The value 0 is an invalid identifier.
1015     *
1016     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1017     *
1018     * @return Returns the boolean value contained in the resource.
1019     */
1020    public boolean getBoolean(@BoolRes int id) throws NotFoundException {
1021        final TypedValue value = obtainTempTypedValue();
1022        try {
1023            mResourcesImpl.getValue(id, value, true);
1024            if (value.type >= TypedValue.TYPE_FIRST_INT
1025                    && value.type <= TypedValue.TYPE_LAST_INT) {
1026                return value.data != 0;
1027            }
1028            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1029                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1030        } finally {
1031            releaseTempTypedValue(value);
1032        }
1033    }
1034
1035    /**
1036     * Return an integer associated with a particular resource ID.
1037     *
1038     * @param id The desired resource identifier, as generated by the aapt
1039     *           tool. This integer encodes the package, type, and resource
1040     *           entry. The value 0 is an invalid identifier.
1041     *
1042     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1043     *
1044     * @return Returns the integer value contained in the resource.
1045     */
1046    public int getInteger(@IntegerRes int id) throws NotFoundException {
1047        final TypedValue value = obtainTempTypedValue();
1048        try {
1049            mResourcesImpl.getValue(id, value, true);
1050            if (value.type >= TypedValue.TYPE_FIRST_INT
1051                    && value.type <= TypedValue.TYPE_LAST_INT) {
1052                return value.data;
1053            }
1054            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1055                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1056        } finally {
1057            releaseTempTypedValue(value);
1058        }
1059    }
1060
1061    /**
1062     * Retrieve a floating-point value for a particular resource ID.
1063     *
1064     * @param id The desired resource identifier, as generated by the aapt
1065     *           tool. This integer encodes the package, type, and resource
1066     *           entry. The value 0 is an invalid identifier.
1067     *
1068     * @return Returns the floating-point value contained in the resource.
1069     *
1070     * @throws NotFoundException Throws NotFoundException if the given ID does
1071     *         not exist or is not a floating-point value.
1072     * @hide Pending API council approval.
1073     */
1074    public float getFloat(int id) {
1075        final TypedValue value = obtainTempTypedValue();
1076        try {
1077            mResourcesImpl.getValue(id, value, true);
1078            if (value.type == TypedValue.TYPE_FLOAT) {
1079                return value.getFloat();
1080            }
1081            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1082                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1083        } finally {
1084            releaseTempTypedValue(value);
1085        }
1086    }
1087
1088    /**
1089     * Return an XmlResourceParser through which you can read a view layout
1090     * description for the given resource ID.  This parser has limited
1091     * functionality -- in particular, you can't change its input, and only
1092     * the high-level events are available.
1093     *
1094     * <p>This function is really a simple wrapper for calling
1095     * {@link #getXml} with a layout resource.
1096     *
1097     * @param id The desired resource identifier, as generated by the aapt
1098     *           tool. This integer encodes the package, type, and resource
1099     *           entry. The value 0 is an invalid identifier.
1100     *
1101     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1102     *
1103     * @return A new parser object through which you can read
1104     *         the XML data.
1105     *
1106     * @see #getXml
1107     */
1108    public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
1109        return loadXmlResourceParser(id, "layout");
1110    }
1111
1112    /**
1113     * Return an XmlResourceParser through which you can read an animation
1114     * description for the given resource ID.  This parser has limited
1115     * functionality -- in particular, you can't change its input, and only
1116     * the high-level events are available.
1117     *
1118     * <p>This function is really a simple wrapper for calling
1119     * {@link #getXml} with an animation resource.
1120     *
1121     * @param id The desired resource identifier, as generated by the aapt
1122     *           tool. This integer encodes the package, type, and resource
1123     *           entry. The value 0 is an invalid identifier.
1124     *
1125     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1126     *
1127     * @return A new parser object through which you can read
1128     *         the XML data.
1129     *
1130     * @see #getXml
1131     */
1132    public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
1133        return loadXmlResourceParser(id, "anim");
1134    }
1135
1136    /**
1137     * Return an XmlResourceParser through which you can read a generic XML
1138     * resource for the given resource ID.
1139     *
1140     * <p>The XmlPullParser implementation returned here has some limited
1141     * functionality.  In particular, you can't change its input, and only
1142     * high-level parsing events are available (since the document was
1143     * pre-parsed for you at build time, which involved merging text and
1144     * stripping comments).
1145     *
1146     * @param id The desired resource identifier, as generated by the aapt
1147     *           tool. This integer encodes the package, type, and resource
1148     *           entry. The value 0 is an invalid identifier.
1149     *
1150     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1151     *
1152     * @return A new parser object through which you can read
1153     *         the XML data.
1154     *
1155     * @see android.util.AttributeSet
1156     */
1157    public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
1158        return loadXmlResourceParser(id, "xml");
1159    }
1160
1161    /**
1162     * Open a data stream for reading a raw resource.  This can only be used
1163     * with resources whose value is the name of an asset files -- that is, it can be
1164     * used to open drawable, sound, and raw resources; it will fail on string
1165     * and color resources.
1166     *
1167     * @param id The resource identifier to open, as generated by the appt
1168     *           tool.
1169     *
1170     * @return InputStream Access to the resource data.
1171     *
1172     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1173     *
1174     */
1175    public InputStream openRawResource(@RawRes int id) throws NotFoundException {
1176        final TypedValue value = obtainTempTypedValue();
1177        try {
1178            return openRawResource(id, value);
1179        } finally {
1180            releaseTempTypedValue(value);
1181        }
1182    }
1183
1184    /**
1185     * Returns a TypedValue suitable for temporary use. The obtained TypedValue
1186     * should be released using {@link #releaseTempTypedValue(TypedValue)}.
1187     *
1188     * @return a typed value suitable for temporary use
1189     */
1190    private TypedValue obtainTempTypedValue() {
1191        TypedValue tmpValue = null;
1192        synchronized (mTmpValueLock) {
1193            if (mTmpValue != null) {
1194                tmpValue = mTmpValue;
1195                mTmpValue = null;
1196            }
1197        }
1198        if (tmpValue == null) {
1199            return new TypedValue();
1200        }
1201        return tmpValue;
1202    }
1203
1204    /**
1205     * Returns a TypedValue to the pool. After calling this method, the
1206     * specified TypedValue should no longer be accessed.
1207     *
1208     * @param value the typed value to return to the pool
1209     */
1210    private void releaseTempTypedValue(TypedValue value) {
1211        synchronized (mTmpValueLock) {
1212            if (mTmpValue == null) {
1213                mTmpValue = value;
1214            }
1215        }
1216    }
1217
1218    /**
1219     * Open a data stream for reading a raw resource.  This can only be used
1220     * with resources whose value is the name of an asset file -- that is, it can be
1221     * used to open drawable, sound, and raw resources; it will fail on string
1222     * and color resources.
1223     *
1224     * @param id The resource identifier to open, as generated by the appt tool.
1225     * @param value The TypedValue object to hold the resource information.
1226     *
1227     * @return InputStream Access to the resource data.
1228     *
1229     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1230     */
1231    public InputStream openRawResource(@RawRes int id, TypedValue value)
1232            throws NotFoundException {
1233        return mResourcesImpl.openRawResource(id, value);
1234    }
1235
1236    /**
1237     * Open a file descriptor for reading a raw resource.  This can only be used
1238     * with resources whose value is the name of an asset files -- that is, it can be
1239     * used to open drawable, sound, and raw resources; it will fail on string
1240     * and color resources.
1241     *
1242     * <p>This function only works for resources that are stored in the package
1243     * as uncompressed data, which typically includes things like mp3 files
1244     * and png images.
1245     *
1246     * @param id The resource identifier to open, as generated by the appt
1247     *           tool.
1248     *
1249     * @return AssetFileDescriptor A new file descriptor you can use to read
1250     * the resource.  This includes the file descriptor itself, as well as the
1251     * offset and length of data where the resource appears in the file.  A
1252     * null is returned if the file exists but is compressed.
1253     *
1254     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1255     *
1256     */
1257    public AssetFileDescriptor openRawResourceFd(@RawRes int id)
1258            throws NotFoundException {
1259        final TypedValue value = obtainTempTypedValue();
1260        try {
1261            return mResourcesImpl.openRawResourceFd(id, value);
1262        } finally {
1263            releaseTempTypedValue(value);
1264        }
1265    }
1266
1267    /**
1268     * Return the raw data associated with a particular resource ID.
1269     *
1270     * @param id The desired resource identifier, as generated by the aapt
1271     *           tool. This integer encodes the package, type, and resource
1272     *           entry. The value 0 is an invalid identifier.
1273     * @param outValue Object in which to place the resource data.
1274     * @param resolveRefs If true, a resource that is a reference to another
1275     *                    resource will be followed so that you receive the
1276     *                    actual final resource data.  If false, the TypedValue
1277     *                    will be filled in with the reference itself.
1278     *
1279     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1280     *
1281     */
1282    public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
1283            throws NotFoundException {
1284        mResourcesImpl.getValue(id, outValue, resolveRefs);
1285    }
1286
1287    /**
1288     * Get the raw value associated with a resource with associated density.
1289     *
1290     * @param id resource identifier
1291     * @param density density in DPI
1292     * @param resolveRefs If true, a resource that is a reference to another
1293     *            resource will be followed so that you receive the actual final
1294     *            resource data. If false, the TypedValue will be filled in with
1295     *            the reference itself.
1296     * @throws NotFoundException Throws NotFoundException if the given ID does
1297     *             not exist.
1298     * @see #getValue(String, TypedValue, boolean)
1299     */
1300    public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
1301            boolean resolveRefs) throws NotFoundException {
1302        mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
1303    }
1304
1305    /**
1306     * Return the raw data associated with a particular resource ID.
1307     * See getIdentifier() for information on how names are mapped to resource
1308     * IDs, and getString(int) for information on how string resources are
1309     * retrieved.
1310     *
1311     * <p>Note: use of this function is discouraged.  It is much more
1312     * efficient to retrieve resources by identifier than by name.
1313     *
1314     * @param name The name of the desired resource.  This is passed to
1315     *             getIdentifier() with a default type of "string".
1316     * @param outValue Object in which to place the resource data.
1317     * @param resolveRefs If true, a resource that is a reference to another
1318     *                    resource will be followed so that you receive the
1319     *                    actual final resource data.  If false, the TypedValue
1320     *                    will be filled in with the reference itself.
1321     *
1322     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1323     *
1324     */
1325    public void getValue(String name, TypedValue outValue, boolean resolveRefs)
1326            throws NotFoundException {
1327        mResourcesImpl.getValue(name, outValue, resolveRefs);
1328    }
1329
1330    /**
1331     * This class holds the current attribute values for a particular theme.
1332     * In other words, a Theme is a set of values for resource attributes;
1333     * these are used in conjunction with {@link TypedArray}
1334     * to resolve the final value for an attribute.
1335     *
1336     * <p>The Theme's attributes come into play in two ways: (1) a styled
1337     * attribute can explicit reference a value in the theme through the
1338     * "?themeAttribute" syntax; (2) if no value has been defined for a
1339     * particular styled attribute, as a last resort we will try to find that
1340     * attribute's value in the Theme.
1341     *
1342     * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
1343     * retrieve XML attributes with style and theme information applied.
1344     */
1345    public final class Theme {
1346        private ResourcesImpl.ThemeImpl mThemeImpl;
1347
1348        private Theme() {
1349        }
1350
1351        void setImpl(ResourcesImpl.ThemeImpl impl) {
1352            mThemeImpl = impl;
1353        }
1354
1355        /**
1356         * Place new attribute values into the theme.  The style resource
1357         * specified by <var>resid</var> will be retrieved from this Theme's
1358         * resources, its values placed into the Theme object.
1359         *
1360         * <p>The semantics of this function depends on the <var>force</var>
1361         * argument:  If false, only values that are not already defined in
1362         * the theme will be copied from the system resource; otherwise, if
1363         * any of the style's attributes are already defined in the theme, the
1364         * current values in the theme will be overwritten.
1365         *
1366         * @param resId The resource ID of a style resource from which to
1367         *              obtain attribute values.
1368         * @param force If true, values in the style resource will always be
1369         *              used in the theme; otherwise, they will only be used
1370         *              if not already defined in the theme.
1371         */
1372        public void applyStyle(int resId, boolean force) {
1373            mThemeImpl.applyStyle(resId, force);
1374        }
1375
1376        /**
1377         * Set this theme to hold the same contents as the theme
1378         * <var>other</var>.  If both of these themes are from the same
1379         * Resources object, they will be identical after this function
1380         * returns.  If they are from different Resources, only the resources
1381         * they have in common will be set in this theme.
1382         *
1383         * @param other The existing Theme to copy from.
1384         */
1385        public void setTo(Theme other) {
1386            mThemeImpl.setTo(other.mThemeImpl);
1387        }
1388
1389        /**
1390         * Return a TypedArray holding the values defined by
1391         * <var>Theme</var> which are listed in <var>attrs</var>.
1392         *
1393         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1394         * with the array.
1395         *
1396         * @param attrs The desired attributes.
1397         *
1398         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1399         *
1400         * @return Returns a TypedArray holding an array of the attribute values.
1401         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1402         * when done with it.
1403         *
1404         * @see Resources#obtainAttributes
1405         * @see #obtainStyledAttributes(int, int[])
1406         * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1407         */
1408        public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
1409            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
1410        }
1411
1412        /**
1413         * Return a TypedArray holding the values defined by the style
1414         * resource <var>resid</var> which are listed in <var>attrs</var>.
1415         *
1416         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1417         * with the array.
1418         *
1419         * @param resId The desired style resource.
1420         * @param attrs The desired attributes in the style.
1421         *
1422         * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1423         *
1424         * @return Returns a TypedArray holding an array of the attribute values.
1425         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1426         * when done with it.
1427         *
1428         * @see Resources#obtainAttributes
1429         * @see #obtainStyledAttributes(int[])
1430         * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1431         */
1432        public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
1433                throws NotFoundException {
1434            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
1435        }
1436
1437        /**
1438         * Return a TypedArray holding the attribute values in
1439         * <var>set</var>
1440         * that are listed in <var>attrs</var>.  In addition, if the given
1441         * AttributeSet specifies a style class (through the "style" attribute),
1442         * that style will be applied on top of the base attributes it defines.
1443         *
1444         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1445         * with the array.
1446         *
1447         * <p>When determining the final value of a particular attribute, there
1448         * are four inputs that come into play:</p>
1449         *
1450         * <ol>
1451         *     <li> Any attribute values in the given AttributeSet.
1452         *     <li> The style resource specified in the AttributeSet (named
1453         *     "style").
1454         *     <li> The default style specified by <var>defStyleAttr</var> and
1455         *     <var>defStyleRes</var>
1456         *     <li> The base values in this theme.
1457         * </ol>
1458         *
1459         * <p>Each of these inputs is considered in-order, with the first listed
1460         * taking precedence over the following ones.  In other words, if in the
1461         * AttributeSet you have supplied <code>&lt;Button
1462         * textColor="#ff000000"&gt;</code>, then the button's text will
1463         * <em>always</em> be black, regardless of what is specified in any of
1464         * the styles.
1465         *
1466         * @param set The base set of attribute values.  May be null.
1467         * @param attrs The desired attributes to be retrieved.
1468         * @param defStyleAttr An attribute in the current theme that contains a
1469         *                     reference to a style resource that supplies
1470         *                     defaults values for the TypedArray.  Can be
1471         *                     0 to not look for defaults.
1472         * @param defStyleRes A resource identifier of a style resource that
1473         *                    supplies default values for the TypedArray,
1474         *                    used only if defStyleAttr is 0 or can not be found
1475         *                    in the theme.  Can be 0 to not look for defaults.
1476         *
1477         * @return Returns a TypedArray holding an array of the attribute values.
1478         * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1479         * when done with it.
1480         *
1481         * @see Resources#obtainAttributes
1482         * @see #obtainStyledAttributes(int[])
1483         * @see #obtainStyledAttributes(int, int[])
1484         */
1485        public TypedArray obtainStyledAttributes(AttributeSet set,
1486                @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
1487            return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
1488        }
1489
1490        /**
1491         * Retrieve the values for a set of attributes in the Theme. The
1492         * contents of the typed array are ultimately filled in by
1493         * {@link Resources#getValue}.
1494         *
1495         * @param values The base set of attribute values, must be equal in
1496         *               length to {@code attrs}. All values must be of type
1497         *               {@link TypedValue#TYPE_ATTRIBUTE}.
1498         * @param attrs The desired attributes to be retrieved.
1499         * @return Returns a TypedArray holding an array of the attribute
1500         *         values. Be sure to call {@link TypedArray#recycle()}
1501         *         when done with it.
1502         * @hide
1503         */
1504        @NonNull
1505        public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
1506            return mThemeImpl.resolveAttributes(this, values, attrs);
1507        }
1508
1509        /**
1510         * Retrieve the value of an attribute in the Theme.  The contents of
1511         * <var>outValue</var> are ultimately filled in by
1512         * {@link Resources#getValue}.
1513         *
1514         * @param resid The resource identifier of the desired theme
1515         *              attribute.
1516         * @param outValue Filled in with the ultimate resource value supplied
1517         *                 by the attribute.
1518         * @param resolveRefs If true, resource references will be walked; if
1519         *                    false, <var>outValue</var> may be a
1520         *                    TYPE_REFERENCE.  In either case, it will never
1521         *                    be a TYPE_ATTRIBUTE.
1522         *
1523         * @return boolean Returns true if the attribute was found and
1524         *         <var>outValue</var> is valid, else false.
1525         */
1526        public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1527            return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
1528        }
1529
1530        /**
1531         * Gets all of the attribute ids associated with this {@link Theme}. For debugging only.
1532         *
1533         * @return The int array containing attribute ids associated with this {@link Theme}.
1534         * @hide
1535         */
1536        public int[] getAllAttributes() {
1537            return mThemeImpl.getAllAttributes();
1538        }
1539
1540        /**
1541         * Returns the resources to which this theme belongs.
1542         *
1543         * @return Resources to which this theme belongs.
1544         */
1545        public Resources getResources() {
1546            return Resources.this;
1547        }
1548
1549        /**
1550         * Return a drawable object associated with a particular resource ID
1551         * and styled for the Theme.
1552         *
1553         * @param id The desired resource identifier, as generated by the aapt
1554         *           tool. This integer encodes the package, type, and resource
1555         *           entry. The value 0 is an invalid identifier.
1556         * @return Drawable An object that can be used to draw this resource.
1557         * @throws NotFoundException Throws NotFoundException if the given ID
1558         *         does not exist.
1559         */
1560        public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
1561            return Resources.this.getDrawable(id, this);
1562        }
1563
1564        /**
1565         * Returns a bit mask of configuration changes that will impact this
1566         * theme (and thus require completely reloading it).
1567         *
1568         * @return a bit mask of configuration changes, as defined by
1569         *         {@link ActivityInfo}
1570         * @see ActivityInfo
1571         */
1572        public int getChangingConfigurations() {
1573            return mThemeImpl.getChangingConfigurations();
1574        }
1575
1576        /**
1577         * Print contents of this theme out to the log.  For debugging only.
1578         *
1579         * @param priority The log priority to use.
1580         * @param tag The log tag to use.
1581         * @param prefix Text to prefix each line printed.
1582         */
1583        public void dump(int priority, String tag, String prefix) {
1584            mThemeImpl.dump(priority, tag, prefix);
1585        }
1586
1587        // Needed by layoutlib.
1588        /*package*/ long getNativeTheme() {
1589            return mThemeImpl.getNativeTheme();
1590        }
1591
1592        /*package*/ int getAppliedStyleResId() {
1593            return mThemeImpl.getAppliedStyleResId();
1594        }
1595
1596        /**
1597         * @hide
1598         */
1599        public ThemeKey getKey() {
1600            return mThemeImpl.getKey();
1601        }
1602
1603        private String getResourceNameFromHexString(String hexString) {
1604            return getResourceName(Integer.parseInt(hexString, 16));
1605        }
1606
1607        /**
1608         * Parses {@link #getKey()} and returns a String array that holds pairs of
1609         * adjacent Theme data: resource name followed by whether or not it was
1610         * forced, as specified by {@link #applyStyle(int, boolean)}.
1611         *
1612         * @hide
1613         */
1614        @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
1615        public String[] getTheme() {
1616            return mThemeImpl.getTheme();
1617        }
1618
1619        /** @hide */
1620        public void encode(@NonNull ViewHierarchyEncoder encoder) {
1621            encoder.beginObject(this);
1622            final String[] properties = getTheme();
1623            for (int i = 0; i < properties.length; i += 2) {
1624                encoder.addProperty(properties[i], properties[i+1]);
1625            }
1626            encoder.endObject();
1627        }
1628
1629        /**
1630         * Rebases the theme against the parent Resource object's current
1631         * configuration by re-applying the styles passed to
1632         * {@link #applyStyle(int, boolean)}.
1633         *
1634         * @hide
1635         */
1636        public void rebase() {
1637            mThemeImpl.rebase();
1638        }
1639    }
1640
1641    static class ThemeKey implements Cloneable {
1642        int[] mResId;
1643        boolean[] mForce;
1644        int mCount;
1645
1646        private int mHashCode = 0;
1647
1648        public void append(int resId, boolean force) {
1649            if (mResId == null) {
1650                mResId = new int[4];
1651            }
1652
1653            if (mForce == null) {
1654                mForce = new boolean[4];
1655            }
1656
1657            mResId = GrowingArrayUtils.append(mResId, mCount, resId);
1658            mForce = GrowingArrayUtils.append(mForce, mCount, force);
1659            mCount++;
1660
1661            mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
1662        }
1663
1664        /**
1665         * Sets up this key as a deep copy of another key.
1666         *
1667         * @param other the key to deep copy into this key
1668         */
1669        public void setTo(ThemeKey other) {
1670            mResId = other.mResId == null ? null : other.mResId.clone();
1671            mForce = other.mForce == null ? null : other.mForce.clone();
1672            mCount = other.mCount;
1673        }
1674
1675        @Override
1676        public int hashCode() {
1677            return mHashCode;
1678        }
1679
1680        @Override
1681        public boolean equals(Object o) {
1682            if (this == o) {
1683                return true;
1684            }
1685
1686            if (o == null || getClass() != o.getClass() || hashCode() != o.hashCode()) {
1687                return false;
1688            }
1689
1690            final ThemeKey t = (ThemeKey) o;
1691            if (mCount != t.mCount) {
1692                return false;
1693            }
1694
1695            final int N = mCount;
1696            for (int i = 0; i < N; i++) {
1697                if (mResId[i] != t.mResId[i] || mForce[i] != t.mForce[i]) {
1698                    return false;
1699                }
1700            }
1701
1702            return true;
1703        }
1704
1705        /**
1706         * @return a shallow copy of this key
1707         */
1708        @Override
1709        public ThemeKey clone() {
1710            final ThemeKey other = new ThemeKey();
1711            other.mResId = mResId;
1712            other.mForce = mForce;
1713            other.mCount = mCount;
1714            other.mHashCode = mHashCode;
1715            return other;
1716        }
1717    }
1718
1719    /**
1720     * Generate a new Theme object for this set of Resources.  It initially
1721     * starts out empty.
1722     *
1723     * @return Theme The newly created Theme container.
1724     */
1725    public final Theme newTheme() {
1726        Theme theme = new Theme();
1727        theme.setImpl(mResourcesImpl.newThemeImpl());
1728        mThemeRefs.add(new WeakReference<>(theme));
1729        return theme;
1730    }
1731
1732    /**
1733     * Retrieve a set of basic attribute values from an AttributeSet, not
1734     * performing styling of them using a theme and/or style resources.
1735     *
1736     * @param set The current attribute values to retrieve.
1737     * @param attrs The specific attributes to be retrieved.
1738     * @return Returns a TypedArray holding an array of the attribute values.
1739     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1740     * when done with it.
1741     *
1742     * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1743     */
1744    public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1745        int len = attrs.length;
1746        TypedArray array = TypedArray.obtain(this, len);
1747
1748        // XXX note that for now we only work with compiled XML files.
1749        // To support generic XML files we will need to manually parse
1750        // out the attributes from the XML file (applying type information
1751        // contained in the resources and such).
1752        XmlBlock.Parser parser = (XmlBlock.Parser)set;
1753        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
1754                array.mData, array.mIndices);
1755
1756        array.mXml = parser;
1757
1758        return array;
1759    }
1760
1761    /**
1762     * Store the newly updated configuration.
1763     */
1764    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
1765        updateConfiguration(config, metrics, null);
1766    }
1767
1768    /**
1769     * @hide
1770     */
1771    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
1772                                    CompatibilityInfo compat) {
1773        mResourcesImpl.updateConfiguration(config, metrics, compat);
1774    }
1775
1776    /**
1777     * Update the system resources configuration if they have previously
1778     * been initialized.
1779     *
1780     * @hide
1781     */
1782    public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
1783            CompatibilityInfo compat) {
1784        if (mSystem != null) {
1785            mSystem.updateConfiguration(config, metrics, compat);
1786            //Log.i(TAG, "Updated system resources " + mSystem
1787            //        + ": " + mSystem.getConfiguration());
1788        }
1789    }
1790
1791    /**
1792     * Return the current display metrics that are in effect for this resource
1793     * object.  The returned object should be treated as read-only.
1794     *
1795     * @return The resource's current display metrics.
1796     */
1797    public DisplayMetrics getDisplayMetrics() {
1798        return mResourcesImpl.getDisplayMetrics();
1799    }
1800
1801    /**
1802     * Return the current configuration that is in effect for this resource
1803     * object.  The returned object should be treated as read-only.
1804     *
1805     * @return The resource's current configuration.
1806     */
1807    public Configuration getConfiguration() {
1808        return mResourcesImpl.getConfiguration();
1809    }
1810
1811    /** @hide */
1812    public Configuration[] getSizeConfigurations() {
1813        return mResourcesImpl.getSizeConfigurations();
1814    }
1815
1816    /**
1817     * Return the compatibility mode information for the application.
1818     * The returned object should be treated as read-only.
1819     *
1820     * @return compatibility info.
1821     * @hide
1822     */
1823    public CompatibilityInfo getCompatibilityInfo() {
1824        return mResourcesImpl.getCompatibilityInfo();
1825    }
1826
1827    /**
1828     * This is just for testing.
1829     * @hide
1830     */
1831    @VisibleForTesting
1832    public void setCompatibilityInfo(CompatibilityInfo ci) {
1833        if (ci != null) {
1834            mResourcesImpl.updateConfiguration(null, null, ci);
1835        }
1836    }
1837
1838    /**
1839     * Return a resource identifier for the given resource name.  A fully
1840     * qualified resource name is of the form "package:type/entry".  The first
1841     * two components (package and type) are optional if defType and
1842     * defPackage, respectively, are specified here.
1843     *
1844     * <p>Note: use of this function is discouraged.  It is much more
1845     * efficient to retrieve resources by identifier than by name.
1846     *
1847     * @param name The name of the desired resource.
1848     * @param defType Optional default resource type to find, if "type/" is
1849     *                not included in the name.  Can be null to require an
1850     *                explicit type.
1851     * @param defPackage Optional default package to find, if "package:" is
1852     *                   not included in the name.  Can be null to require an
1853     *                   explicit package.
1854     *
1855     * @return int The associated resource identifier.  Returns 0 if no such
1856     *         resource was found.  (0 is not a valid resource ID.)
1857     */
1858    public int getIdentifier(String name, String defType, String defPackage) {
1859        return mResourcesImpl.getIdentifier(name, defType, defPackage);
1860    }
1861
1862    /**
1863     * Return true if given resource identifier includes a package.
1864     *
1865     * @hide
1866     */
1867    public static boolean resourceHasPackage(@AnyRes int resid) {
1868        return (resid >>> 24) != 0;
1869    }
1870
1871    /**
1872     * Return the full name for a given resource identifier.  This name is
1873     * a single string of the form "package:type/entry".
1874     *
1875     * @param resid The resource identifier whose name is to be retrieved.
1876     *
1877     * @return A string holding the name of the resource.
1878     *
1879     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1880     *
1881     * @see #getResourcePackageName
1882     * @see #getResourceTypeName
1883     * @see #getResourceEntryName
1884     */
1885    public String getResourceName(@AnyRes int resid) throws NotFoundException {
1886        return mResourcesImpl.getResourceName(resid);
1887    }
1888
1889    /**
1890     * Return the package name for a given resource identifier.
1891     *
1892     * @param resid The resource identifier whose package name is to be
1893     * retrieved.
1894     *
1895     * @return A string holding the package name of the resource.
1896     *
1897     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1898     *
1899     * @see #getResourceName
1900     */
1901    public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
1902        return mResourcesImpl.getResourcePackageName(resid);
1903    }
1904
1905    /**
1906     * Return the type name for a given resource identifier.
1907     *
1908     * @param resid The resource identifier whose type name is to be
1909     * retrieved.
1910     *
1911     * @return A string holding the type name of the resource.
1912     *
1913     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1914     *
1915     * @see #getResourceName
1916     */
1917    public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
1918        return mResourcesImpl.getResourceTypeName(resid);
1919    }
1920
1921    /**
1922     * Return the entry name for a given resource identifier.
1923     *
1924     * @param resid The resource identifier whose entry name is to be
1925     * retrieved.
1926     *
1927     * @return A string holding the entry name of the resource.
1928     *
1929     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1930     *
1931     * @see #getResourceName
1932     */
1933    public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
1934        return mResourcesImpl.getResourceEntryName(resid);
1935    }
1936
1937    /**
1938     * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
1939     * an XML file.  You call this when you are at the parent tag of the
1940     * extra tags, and it will return once all of the child tags have been parsed.
1941     * This will call {@link #parseBundleExtra} for each extra tag encountered.
1942     *
1943     * @param parser The parser from which to retrieve the extras.
1944     * @param outBundle A Bundle in which to place all parsed extras.
1945     * @throws XmlPullParserException
1946     * @throws IOException
1947     */
1948    public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
1949            throws XmlPullParserException, IOException {
1950        int outerDepth = parser.getDepth();
1951        int type;
1952        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1953               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1954            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1955                continue;
1956            }
1957
1958            String nodeName = parser.getName();
1959            if (nodeName.equals("extra")) {
1960                parseBundleExtra("extra", parser, outBundle);
1961                XmlUtils.skipCurrentTag(parser);
1962
1963            } else {
1964                XmlUtils.skipCurrentTag(parser);
1965            }
1966        }
1967    }
1968
1969    /**
1970     * Parse a name/value pair out of an XML tag holding that data.  The
1971     * AttributeSet must be holding the data defined by
1972     * {@link android.R.styleable#Extra}.  The following value types are supported:
1973     * <ul>
1974     * <li> {@link TypedValue#TYPE_STRING}:
1975     * {@link Bundle#putCharSequence Bundle.putCharSequence()}
1976     * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
1977     * {@link Bundle#putCharSequence Bundle.putBoolean()}
1978     * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
1979     * {@link Bundle#putCharSequence Bundle.putBoolean()}
1980     * <li> {@link TypedValue#TYPE_FLOAT}:
1981     * {@link Bundle#putCharSequence Bundle.putFloat()}
1982     * </ul>
1983     *
1984     * @param tagName The name of the tag these attributes come from; this is
1985     * only used for reporting error messages.
1986     * @param attrs The attributes from which to retrieve the name/value pair.
1987     * @param outBundle The Bundle in which to place the parsed value.
1988     * @throws XmlPullParserException If the attributes are not valid.
1989     */
1990    public void parseBundleExtra(String tagName, AttributeSet attrs,
1991            Bundle outBundle) throws XmlPullParserException {
1992        TypedArray sa = obtainAttributes(attrs,
1993                com.android.internal.R.styleable.Extra);
1994
1995        String name = sa.getString(
1996                com.android.internal.R.styleable.Extra_name);
1997        if (name == null) {
1998            sa.recycle();
1999            throw new XmlPullParserException("<" + tagName
2000                    + "> requires an android:name attribute at "
2001                    + attrs.getPositionDescription());
2002        }
2003
2004        TypedValue v = sa.peekValue(
2005                com.android.internal.R.styleable.Extra_value);
2006        if (v != null) {
2007            if (v.type == TypedValue.TYPE_STRING) {
2008                CharSequence cs = v.coerceToString();
2009                outBundle.putCharSequence(name, cs);
2010            } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2011                outBundle.putBoolean(name, v.data != 0);
2012            } else if (v.type >= TypedValue.TYPE_FIRST_INT
2013                    && v.type <= TypedValue.TYPE_LAST_INT) {
2014                outBundle.putInt(name, v.data);
2015            } else if (v.type == TypedValue.TYPE_FLOAT) {
2016                outBundle.putFloat(name, v.getFloat());
2017            } else {
2018                sa.recycle();
2019                throw new XmlPullParserException("<" + tagName
2020                        + "> only supports string, integer, float, color, and boolean at "
2021                        + attrs.getPositionDescription());
2022            }
2023        } else {
2024            sa.recycle();
2025            throw new XmlPullParserException("<" + tagName
2026                    + "> requires an android:value or android:resource attribute at "
2027                    + attrs.getPositionDescription());
2028        }
2029
2030        sa.recycle();
2031    }
2032
2033    /**
2034     * Retrieve underlying AssetManager storage for these resources.
2035     */
2036    public final AssetManager getAssets() {
2037        return mResourcesImpl.getAssets();
2038    }
2039
2040    /**
2041     * Call this to remove all cached loaded layout resources from the
2042     * Resources object.  Only intended for use with performance testing
2043     * tools.
2044     */
2045    public final void flushLayoutCache() {
2046        mResourcesImpl.flushLayoutCache();
2047    }
2048
2049    /**
2050     * Start preloading of resource data using this Resources object.  Only
2051     * for use by the zygote process for loading common system resources.
2052     * {@hide}
2053     */
2054    public final void startPreloading() {
2055        mResourcesImpl.startPreloading();
2056    }
2057
2058    /**
2059     * Called by zygote when it is done preloading resources, to change back
2060     * to normal Resources operation.
2061     */
2062    public final void finishPreloading() {
2063        mResourcesImpl.finishPreloading();
2064    }
2065
2066    /**
2067     * @hide
2068     */
2069    public LongSparseArray<ConstantState> getPreloadedDrawables() {
2070        return mResourcesImpl.getPreloadedDrawables();
2071    }
2072
2073    /**
2074     * Loads an XML parser for the specified file.
2075     *
2076     * @param id the resource identifier for the file
2077     * @param type the type of resource (used for logging)
2078     * @return a parser for the specified XML file
2079     * @throws NotFoundException if the file could not be loaded
2080     */
2081    @NonNull
2082    XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
2083            throws NotFoundException {
2084        final TypedValue value = obtainTempTypedValue();
2085        try {
2086            final ResourcesImpl impl = mResourcesImpl;
2087            impl.getValue(id, value, true);
2088            if (value.type == TypedValue.TYPE_STRING) {
2089                return impl.loadXmlResourceParser(value.string.toString(), id,
2090                        value.assetCookie, type);
2091            }
2092            throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
2093                    + " type #0x" + Integer.toHexString(value.type) + " is not valid");
2094        } finally {
2095            releaseTempTypedValue(value);
2096        }
2097    }
2098
2099    /**
2100     * Loads an XML parser for the specified file.
2101     *
2102     * @param file the path for the XML file to parse
2103     * @param id the resource identifier for the file
2104     * @param assetCookie the asset cookie for the file
2105     * @param type the type of resource (used for logging)
2106     * @return a parser for the specified XML file
2107     * @throws NotFoundException if the file could not be loaded
2108     */
2109    @NonNull
2110    XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
2111                                            String type) throws NotFoundException {
2112        return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
2113    }
2114
2115    /**
2116     * Called by ConfigurationBoundResourceCacheTest.
2117     * @hide
2118     */
2119    @VisibleForTesting
2120    public int calcConfigChanges(Configuration config) {
2121        return mResourcesImpl.calcConfigChanges(config);
2122    }
2123
2124    /**
2125     * Obtains styled attributes from the theme, if available, or unstyled
2126     * resources if the theme is null.
2127     *
2128     * @hide
2129     */
2130    public static TypedArray obtainAttributes(
2131            Resources res, Theme theme, AttributeSet set, int[] attrs) {
2132        if (theme == null) {
2133            return res.obtainAttributes(set, attrs);
2134        }
2135        return theme.obtainStyledAttributes(set, attrs, 0, 0);
2136    }
2137}
2138