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