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