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