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