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