• 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 
20 import com.android.internal.util.XmlUtils;
21 
22 import org.xmlpull.v1.XmlPullParser;
23 import org.xmlpull.v1.XmlPullParserException;
24 
25 import android.graphics.Movie;
26 import android.graphics.drawable.Drawable;
27 import android.graphics.drawable.ColorDrawable;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.os.SystemProperties;
31 import android.util.AttributeSet;
32 import android.util.DisplayMetrics;
33 import android.util.Log;
34 import android.util.SparseArray;
35 import android.util.TypedValue;
36 import android.util.LongSparseArray;
37 import android.view.Display;
38 
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.lang.ref.WeakReference;
42 
43 /**
44  * Class for accessing an application's resources.  This sits on top of the
45  * asset manager of the application (accessible through getAssets()) and
46  * provides a higher-level API for getting typed data from the assets.
47  */
48 public class Resources {
49     static final String TAG = "Resources";
50     private static final boolean DEBUG_LOAD = false;
51     private static final boolean DEBUG_CONFIG = false;
52     private static final boolean TRACE_FOR_PRELOAD = false;
53 
54     // Use the current SDK version code.  If we are a development build,
55     // also allow the previous SDK version + 1.
56     private static final int sSdkVersion = Build.VERSION.SDK_INT
57             + ("REL".equals(Build.VERSION.CODENAME) ? 0 : 1);
58     private static final Object mSync = new Object();
59     private static Resources mSystem = null;
60 
61     // Information about preloaded resources.  Note that they are not
62     // protected by a lock, because while preloading in zygote we are all
63     // single-threaded, and after that these are immutable.
64     private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables
65             = new LongSparseArray<Drawable.ConstantState>();
66     private static final SparseArray<ColorStateList> mPreloadedColorStateLists
67             = new SparseArray<ColorStateList>();
68     private static boolean mPreloaded;
69 
70     /*package*/ final TypedValue mTmpValue = new TypedValue();
71 
72     // These are protected by the mTmpValue lock.
73     private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
74             = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
75     private final SparseArray<WeakReference<ColorStateList> > mColorStateListCache
76             = new SparseArray<WeakReference<ColorStateList> >();
77     private boolean mPreloading;
78 
79     /*package*/ TypedArray mCachedStyledAttributes = null;
80 
81     private int mLastCachedXmlBlockIndex = -1;
82     private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
83     private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
84 
85     /*package*/ final AssetManager mAssets;
86     private final Configuration mConfiguration = new Configuration();
87     /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
88     PluralRules mPluralRule;
89 
90     private CompatibilityInfo mCompatibilityInfo;
91     private Display mDefaultDisplay;
92 
93     private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
94         @Override
95         public void put(long k, Object o) {
96             throw new UnsupportedOperationException();
97         }
98         @Override
99         public void append(long k, Object o) {
100             throw new UnsupportedOperationException();
101         }
102     };
103 
104     @SuppressWarnings("unchecked")
emptySparseArray()105     private static <T> LongSparseArray<T> emptySparseArray() {
106         return (LongSparseArray<T>) EMPTY_ARRAY;
107     }
108 
109     /**
110      * This exception is thrown by the resource APIs when a requested resource
111      * can not be found.
112      */
113     public static class NotFoundException extends RuntimeException {
NotFoundException()114         public NotFoundException() {
115         }
116 
NotFoundException(String name)117         public NotFoundException(String name) {
118             super(name);
119         }
120     }
121 
122     /**
123      * Create a new Resources object on top of an existing set of assets in an
124      * AssetManager.
125      *
126      * @param assets Previously created AssetManager.
127      * @param metrics Current display metrics to consider when
128      *                selecting/computing resource values.
129      * @param config Desired device configuration to consider when
130      *               selecting/computing resource values (optional).
131      */
Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)132     public Resources(AssetManager assets, DisplayMetrics metrics,
133             Configuration config) {
134         this(assets, metrics, config, (CompatibilityInfo) null);
135     }
136 
137     /**
138      * Creates a new Resources object with CompatibilityInfo.
139      *
140      * @param assets Previously created AssetManager.
141      * @param metrics Current display metrics to consider when
142      *                selecting/computing resource values.
143      * @param config Desired device configuration to consider when
144      *               selecting/computing resource values (optional).
145      * @param compInfo this resource's compatibility info. It will use the default compatibility
146      *  info when it's null.
147      * @hide
148      */
Resources(AssetManager assets, DisplayMetrics metrics, Configuration config, CompatibilityInfo compInfo)149     public Resources(AssetManager assets, DisplayMetrics metrics,
150             Configuration config, CompatibilityInfo compInfo) {
151         mAssets = assets;
152         mMetrics.setToDefaults();
153         if (compInfo == null) {
154             mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
155         } else {
156             mCompatibilityInfo = compInfo;
157         }
158         updateConfiguration(config, metrics);
159         assets.ensureStringBlocks();
160     }
161 
162     /**
163      * Return a global shared Resources object that provides access to only
164      * system resources (no application resources), and is not configured for
165      * the current screen (can not use dimension units, does not change based
166      * on orientation, etc).
167      */
getSystem()168     public static Resources getSystem() {
169         synchronized (mSync) {
170             Resources ret = mSystem;
171             if (ret == null) {
172                 ret = new Resources();
173                 mSystem = ret;
174             }
175 
176             return ret;
177         }
178     }
179 
180     /**
181      * Return the string value associated with a particular resource ID.  The
182      * returned object will be a String if this is a plain string; it will be
183      * some other type of CharSequence if it is styled.
184      * {@more}
185      *
186      * @param id The desired resource identifier, as generated by the aapt
187      *           tool. This integer encodes the package, type, and resource
188      *           entry. The value 0 is an invalid identifier.
189      *
190      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
191      *
192      * @return CharSequence The string data associated with the resource, plus
193      *         possibly styled text information.
194      */
getText(int id)195     public CharSequence getText(int id) throws NotFoundException {
196         CharSequence res = mAssets.getResourceText(id);
197         if (res != null) {
198             return res;
199         }
200         throw new NotFoundException("String resource ID #0x"
201                                     + Integer.toHexString(id));
202     }
203 
204     /**
205      * @param id The desired resource identifier, as generated by the aapt
206      *           tool. This integer encodes the package, type, and resource
207      *           entry. The value 0 is an invalid identifier.
208      *
209      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
210      *
211      * @return CharSequence The string data associated with the resource, plus
212      *         possibly styled text information.
213      */
getQuantityText(int id, int quantity)214     public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
215         PluralRules rule = getPluralRule();
216         CharSequence res = mAssets.getResourceBagText(id, rule.attrForNumber(quantity));
217         if (res != null) {
218             return res;
219         }
220         res = mAssets.getResourceBagText(id, PluralRules.ID_OTHER);
221         if (res != null) {
222             return res;
223         }
224         throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
225                 + " quantity=" + quantity
226                 + " item=" + PluralRules.stringForQuantity(rule.quantityForNumber(quantity)));
227     }
228 
getPluralRule()229     private PluralRules getPluralRule() {
230         synchronized (mSync) {
231             if (mPluralRule == null) {
232                 mPluralRule = PluralRules.ruleForLocale(mConfiguration.locale);
233             }
234             return mPluralRule;
235         }
236     }
237 
238     /**
239      * Return the string value associated with a particular resource ID.  It
240      * will be stripped of any styled text information.
241      * {@more}
242      *
243      * @param id The desired resource identifier, as generated by the aapt
244      *           tool. This integer encodes the package, type, and resource
245      *           entry. The value 0 is an invalid identifier.
246      *
247      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
248      *
249      * @return String The string data associated with the resource,
250      * stripped of styled text information.
251      */
getString(int id)252     public String getString(int id) throws NotFoundException {
253         CharSequence res = getText(id);
254         if (res != null) {
255             return res.toString();
256         }
257         throw new NotFoundException("String resource ID #0x"
258                                     + Integer.toHexString(id));
259     }
260 
261 
262     /**
263      * Return the string value associated with a particular resource ID,
264      * substituting the format arguments as defined in {@link java.util.Formatter}
265      * and {@link java.lang.String#format}. It will be stripped of any styled text
266      * information.
267      * {@more}
268      *
269      * @param id The desired resource identifier, as generated by the aapt
270      *           tool. This integer encodes the package, type, and resource
271      *           entry. The value 0 is an invalid identifier.
272      *
273      * @param formatArgs The format arguments that will be used for substitution.
274      *
275      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
276      *
277      * @return String The string data associated with the resource,
278      * stripped of styled text information.
279      */
getString(int id, Object... formatArgs)280     public String getString(int id, Object... formatArgs) throws NotFoundException {
281         String raw = getString(id);
282         return String.format(mConfiguration.locale, raw, formatArgs);
283     }
284 
285     /**
286      * Return the string value associated with a particular resource ID for a particular
287      * numerical quantity, substituting the format arguments as defined in
288      * {@link java.util.Formatter} and {@link java.lang.String#format}. It will be
289      * stripped of any styled text information.
290      * {@more}
291      *
292      * @param id The desired resource identifier, as generated by the aapt
293      *           tool. This integer encodes the package, type, and resource
294      *           entry. The value 0 is an invalid identifier.
295      * @param quantity The number used to get the correct string for the current language's
296      *           plural rules.
297      * @param formatArgs The format arguments that will be used for substitution.
298      *
299      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
300      *
301      * @return String The string data associated with the resource,
302      * stripped of styled text information.
303      */
getQuantityString(int id, int quantity, Object... formatArgs)304     public String getQuantityString(int id, int quantity, Object... formatArgs)
305             throws NotFoundException {
306         String raw = getQuantityText(id, quantity).toString();
307         return String.format(mConfiguration.locale, raw, formatArgs);
308     }
309 
310     /**
311      * Return the string value associated with a particular resource ID for a particular
312      * numerical quantity.
313      *
314      * @param id The desired resource identifier, as generated by the aapt
315      *           tool. This integer encodes the package, type, and resource
316      *           entry. The value 0 is an invalid identifier.
317      * @param quantity The number used to get the correct string for the current language's
318      *           plural rules.
319      *
320      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
321      *
322      * @return String The string data associated with the resource,
323      * stripped of styled text information.
324      */
getQuantityString(int id, int quantity)325     public String getQuantityString(int id, int quantity) throws NotFoundException {
326         return getQuantityText(id, quantity).toString();
327     }
328 
329     /**
330      * Return the string value associated with a particular resource ID.  The
331      * returned object will be a String if this is a plain string; it will be
332      * some other type of CharSequence if it is styled.
333      *
334      * @param id The desired resource identifier, as generated by the aapt
335      *           tool. This integer encodes the package, type, and resource
336      *           entry. The value 0 is an invalid identifier.
337      *
338      * @param def The default CharSequence to return.
339      *
340      * @return CharSequence The string data associated with the resource, plus
341      *         possibly styled text information, or def if id is 0 or not found.
342      */
getText(int id, CharSequence def)343     public CharSequence getText(int id, CharSequence def) {
344         CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
345         return res != null ? res : def;
346     }
347 
348     /**
349      * Return the styled text array associated with a particular resource ID.
350      *
351      * @param id The desired resource identifier, as generated by the aapt
352      *           tool. This integer encodes the package, type, and resource
353      *           entry. The value 0 is an invalid identifier.
354      *
355      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
356      *
357      * @return The styled text array associated with the resource.
358      */
getTextArray(int id)359     public CharSequence[] getTextArray(int id) throws NotFoundException {
360         CharSequence[] res = mAssets.getResourceTextArray(id);
361         if (res != null) {
362             return res;
363         }
364         throw new NotFoundException("Text array resource ID #0x"
365                                     + Integer.toHexString(id));
366     }
367 
368     /**
369      * Return the string array associated with a particular resource ID.
370      *
371      * @param id The desired resource identifier, as generated by the aapt
372      *           tool. This integer encodes the package, type, and resource
373      *           entry. The value 0 is an invalid identifier.
374      *
375      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
376      *
377      * @return The string array associated with the resource.
378      */
getStringArray(int id)379     public String[] getStringArray(int id) throws NotFoundException {
380         String[] res = mAssets.getResourceStringArray(id);
381         if (res != null) {
382             return res;
383         }
384         throw new NotFoundException("String array resource ID #0x"
385                                     + Integer.toHexString(id));
386     }
387 
388     /**
389      * Return the int array associated with a particular resource ID.
390      *
391      * @param id The desired resource identifier, as generated by the aapt
392      *           tool. This integer encodes the package, type, and resource
393      *           entry. The value 0 is an invalid identifier.
394      *
395      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
396      *
397      * @return The int array associated with the resource.
398      */
getIntArray(int id)399     public int[] getIntArray(int id) throws NotFoundException {
400         int[] res = mAssets.getArrayIntResource(id);
401         if (res != null) {
402             return res;
403         }
404         throw new NotFoundException("Int array resource ID #0x"
405                                     + Integer.toHexString(id));
406     }
407 
408     /**
409      * Return an array of heterogeneous values.
410      *
411      * @param id The desired resource identifier, as generated by the aapt
412      *           tool. This integer encodes the package, type, and resource
413      *           entry. The value 0 is an invalid identifier.
414      *
415      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
416      *
417      * @return Returns a TypedArray holding an array of the array values.
418      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
419      * when done with it.
420      */
obtainTypedArray(int id)421     public TypedArray obtainTypedArray(int id) throws NotFoundException {
422         int len = mAssets.getArraySize(id);
423         if (len < 0) {
424             throw new NotFoundException("Array resource ID #0x"
425                                         + Integer.toHexString(id));
426         }
427 
428         TypedArray array = getCachedStyledAttributes(len);
429         array.mLength = mAssets.retrieveArray(id, array.mData);
430         array.mIndices[0] = 0;
431 
432         return array;
433     }
434 
435     /**
436      * Retrieve a dimensional for a particular resource ID.  Unit
437      * conversions are based on the current {@link DisplayMetrics} associated
438      * with the resources.
439      *
440      * @param id The desired resource identifier, as generated by the aapt
441      *           tool. This integer encodes the package, type, and resource
442      *           entry. The value 0 is an invalid identifier.
443      *
444      * @return Resource dimension value multiplied by the appropriate
445      * metric.
446      *
447      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
448      *
449      * @see #getDimensionPixelOffset
450      * @see #getDimensionPixelSize
451      */
getDimension(int id)452     public float getDimension(int id) throws NotFoundException {
453         synchronized (mTmpValue) {
454             TypedValue value = mTmpValue;
455             getValue(id, value, true);
456             if (value.type == TypedValue.TYPE_DIMENSION) {
457                 return TypedValue.complexToDimension(value.data, mMetrics);
458             }
459             throw new NotFoundException(
460                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
461                     + Integer.toHexString(value.type) + " is not valid");
462         }
463     }
464 
465     /**
466      * Retrieve a dimensional for a particular resource ID for use
467      * as an offset in raw pixels.  This is the same as
468      * {@link #getDimension}, except the returned value is converted to
469      * integer pixels for you.  An offset conversion involves simply
470      * truncating the base value to an integer.
471      *
472      * @param id The desired resource identifier, as generated by the aapt
473      *           tool. This integer encodes the package, type, and resource
474      *           entry. The value 0 is an invalid identifier.
475      *
476      * @return Resource dimension value multiplied by the appropriate
477      * metric and truncated to integer pixels.
478      *
479      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
480      *
481      * @see #getDimension
482      * @see #getDimensionPixelSize
483      */
getDimensionPixelOffset(int id)484     public int getDimensionPixelOffset(int id) throws NotFoundException {
485         synchronized (mTmpValue) {
486             TypedValue value = mTmpValue;
487             getValue(id, value, true);
488             if (value.type == TypedValue.TYPE_DIMENSION) {
489                 return TypedValue.complexToDimensionPixelOffset(
490                         value.data, mMetrics);
491             }
492             throw new NotFoundException(
493                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
494                     + Integer.toHexString(value.type) + " is not valid");
495         }
496     }
497 
498     /**
499      * Retrieve a dimensional for a particular resource ID for use
500      * as a size in raw pixels.  This is the same as
501      * {@link #getDimension}, except the returned value is converted to
502      * integer pixels for use as a size.  A size conversion involves
503      * rounding the base value, and ensuring that a non-zero base value
504      * is at least one pixel in size.
505      *
506      * @param id The desired resource identifier, as generated by the aapt
507      *           tool. This integer encodes the package, type, and resource
508      *           entry. The value 0 is an invalid identifier.
509      *
510      * @return Resource dimension value multiplied by the appropriate
511      * metric and truncated to integer pixels.
512      *
513      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
514      *
515      * @see #getDimension
516      * @see #getDimensionPixelOffset
517      */
getDimensionPixelSize(int id)518     public int getDimensionPixelSize(int id) throws NotFoundException {
519         synchronized (mTmpValue) {
520             TypedValue value = mTmpValue;
521             getValue(id, value, true);
522             if (value.type == TypedValue.TYPE_DIMENSION) {
523                 return TypedValue.complexToDimensionPixelSize(
524                         value.data, mMetrics);
525             }
526             throw new NotFoundException(
527                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
528                     + Integer.toHexString(value.type) + " is not valid");
529         }
530     }
531 
532     /**
533      * Retrieve a fractional unit for a particular resource ID.
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      * @param base The base value of this fraction.  In other words, a
539      *             standard fraction is multiplied by this value.
540      * @param pbase The parent base value of this fraction.  In other
541      *             words, a parent fraction (nn%p) is multiplied by this
542      *             value.
543      *
544      * @return Attribute fractional value multiplied by the appropriate
545      * base value.
546      *
547      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
548      */
getFraction(int id, int base, int pbase)549     public float getFraction(int id, int base, int pbase) {
550         synchronized (mTmpValue) {
551             TypedValue value = mTmpValue;
552             getValue(id, value, true);
553             if (value.type == TypedValue.TYPE_FRACTION) {
554                 return TypedValue.complexToFraction(value.data, base, pbase);
555             }
556             throw new NotFoundException(
557                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
558                     + Integer.toHexString(value.type) + " is not valid");
559         }
560     }
561 
562     /**
563      * Return a drawable object associated with a particular resource ID.
564      * Various types of objects will be returned depending on the underlying
565      * resource -- for example, a solid color, PNG image, scalable image, etc.
566      * The Drawable API hides these implementation details.
567      *
568      * @param id The desired resource identifier, as generated by the aapt
569      *           tool. This integer encodes the package, type, and resource
570      *           entry. The value 0 is an invalid identifier.
571      *
572      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
573      *
574      * @return Drawable An object that can be used to draw this resource.
575      */
getDrawable(int id)576     public Drawable getDrawable(int id) throws NotFoundException {
577         synchronized (mTmpValue) {
578             TypedValue value = mTmpValue;
579             getValue(id, value, true);
580             return loadDrawable(value, id);
581         }
582     }
583 
584     /**
585      * Return a movie object associated with the particular resource ID.
586      * @param id The desired resource identifier, as generated by the aapt
587      *           tool. This integer encodes the package, type, and resource
588      *           entry. The value 0 is an invalid identifier.
589      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
590      *
591      */
getMovie(int id)592     public Movie getMovie(int id) throws NotFoundException {
593         InputStream is = openRawResource(id);
594         Movie movie = Movie.decodeStream(is);
595         try {
596             is.close();
597         }
598         catch (java.io.IOException e) {
599             // don't care, since the return value is valid
600         }
601         return movie;
602     }
603 
604     /**
605      * Return a color integer associated with a particular resource ID.
606      * If the resource holds a complex
607      * {@link android.content.res.ColorStateList}, then the default color from
608      * the set is returned.
609      *
610      * @param id The desired resource identifier, as generated by the aapt
611      *           tool. This integer encodes the package, type, and resource
612      *           entry. The value 0 is an invalid identifier.
613      *
614      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
615      *
616      * @return Returns a single color value in the form 0xAARRGGBB.
617      */
getColor(int id)618     public int getColor(int id) throws NotFoundException {
619         synchronized (mTmpValue) {
620             TypedValue value = mTmpValue;
621             getValue(id, value, true);
622             if (value.type >= TypedValue.TYPE_FIRST_INT
623                 && value.type <= TypedValue.TYPE_LAST_INT) {
624                 return value.data;
625             } else if (value.type == TypedValue.TYPE_STRING) {
626                 ColorStateList csl = loadColorStateList(mTmpValue, id);
627                 return csl.getDefaultColor();
628             }
629             throw new NotFoundException(
630                 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
631                 + Integer.toHexString(value.type) + " is not valid");
632         }
633     }
634 
635     /**
636      * Return a color state list associated with a particular resource ID.  The
637      * resource may contain either a single raw color value, or a complex
638      * {@link android.content.res.ColorStateList} holding multiple possible colors.
639      *
640      * @param id The desired resource identifier of a {@link ColorStateList},
641      *        as generated by the aapt tool. This integer encodes the package, type, and resource
642      *        entry. The value 0 is an invalid identifier.
643      *
644      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
645      *
646      * @return Returns a ColorStateList object containing either a single
647      * solid color or multiple colors that can be selected based on a state.
648      */
getColorStateList(int id)649     public ColorStateList getColorStateList(int id) throws NotFoundException {
650         synchronized (mTmpValue) {
651             TypedValue value = mTmpValue;
652             getValue(id, value, true);
653             return loadColorStateList(value, id);
654         }
655     }
656 
657     /**
658      * Return a boolean associated with a particular resource ID.  This can be
659      * used with any integral resource value, and will return true if it is
660      * non-zero.
661      *
662      * @param id The desired resource identifier, as generated by the aapt
663      *           tool. This integer encodes the package, type, and resource
664      *           entry. The value 0 is an invalid identifier.
665      *
666      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
667      *
668      * @return Returns the boolean value contained in the resource.
669      */
getBoolean(int id)670     public boolean getBoolean(int id) throws NotFoundException {
671         synchronized (mTmpValue) {
672             TypedValue value = mTmpValue;
673             getValue(id, value, true);
674             if (value.type >= TypedValue.TYPE_FIRST_INT
675                 && value.type <= TypedValue.TYPE_LAST_INT) {
676                 return value.data != 0;
677             }
678             throw new NotFoundException(
679                 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
680                 + Integer.toHexString(value.type) + " is not valid");
681         }
682     }
683 
684     /**
685      * Return an integer associated with a particular resource ID.
686      *
687      * @param id The desired resource identifier, as generated by the aapt
688      *           tool. This integer encodes the package, type, and resource
689      *           entry. The value 0 is an invalid identifier.
690      *
691      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
692      *
693      * @return Returns the integer value contained in the resource.
694      */
getInteger(int id)695     public int getInteger(int id) throws NotFoundException {
696         synchronized (mTmpValue) {
697             TypedValue value = mTmpValue;
698             getValue(id, value, true);
699             if (value.type >= TypedValue.TYPE_FIRST_INT
700                 && value.type <= TypedValue.TYPE_LAST_INT) {
701                 return value.data;
702             }
703             throw new NotFoundException(
704                 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
705                 + Integer.toHexString(value.type) + " is not valid");
706         }
707     }
708 
709     /**
710      * Return an XmlResourceParser through which you can read a view layout
711      * description for the given resource ID.  This parser has limited
712      * functionality -- in particular, you can't change its input, and only
713      * the high-level events are available.
714      *
715      * <p>This function is really a simple wrapper for calling
716      * {@link #getXml} with a layout resource.
717      *
718      * @param id The desired resource identifier, as generated by the aapt
719      *           tool. This integer encodes the package, type, and resource
720      *           entry. The value 0 is an invalid identifier.
721      *
722      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
723      *
724      * @return A new parser object through which you can read
725      *         the XML data.
726      *
727      * @see #getXml
728      */
getLayout(int id)729     public XmlResourceParser getLayout(int id) throws NotFoundException {
730         return loadXmlResourceParser(id, "layout");
731     }
732 
733     /**
734      * Return an XmlResourceParser through which you can read an animation
735      * description for the given resource ID.  This parser has limited
736      * functionality -- in particular, you can't change its input, and only
737      * the high-level events are available.
738      *
739      * <p>This function is really a simple wrapper for calling
740      * {@link #getXml} with an animation resource.
741      *
742      * @param id The desired resource identifier, as generated by the aapt
743      *           tool. This integer encodes the package, type, and resource
744      *           entry. The value 0 is an invalid identifier.
745      *
746      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
747      *
748      * @return A new parser object through which you can read
749      *         the XML data.
750      *
751      * @see #getXml
752      */
getAnimation(int id)753     public XmlResourceParser getAnimation(int id) throws NotFoundException {
754         return loadXmlResourceParser(id, "anim");
755     }
756 
757     /**
758      * Return an XmlResourceParser through which you can read a generic XML
759      * resource for the given resource ID.
760      *
761      * <p>The XmlPullParser implementation returned here has some limited
762      * functionality.  In particular, you can't change its input, and only
763      * high-level parsing events are available (since the document was
764      * pre-parsed for you at build time, which involved merging text and
765      * stripping comments).
766      *
767      * @param id The desired resource identifier, as generated by the aapt
768      *           tool. This integer encodes the package, type, and resource
769      *           entry. The value 0 is an invalid identifier.
770      *
771      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
772      *
773      * @return A new parser object through which you can read
774      *         the XML data.
775      *
776      * @see android.util.AttributeSet
777      */
getXml(int id)778     public XmlResourceParser getXml(int id) throws NotFoundException {
779         return loadXmlResourceParser(id, "xml");
780     }
781 
782     /**
783      * Open a data stream for reading a raw resource.  This can only be used
784      * with resources whose value is the name of an asset files -- that is, it can be
785      * used to open drawable, sound, and raw resources; it will fail on string
786      * and color resources.
787      *
788      * @param id The resource identifier to open, as generated by the appt
789      *           tool.
790      *
791      * @return InputStream Access to the resource data.
792      *
793      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
794      *
795      */
openRawResource(int id)796     public InputStream openRawResource(int id) throws NotFoundException {
797         synchronized (mTmpValue) {
798             return openRawResource(id, mTmpValue);
799         }
800     }
801 
802     /**
803      * Open a data stream for reading a raw resource.  This can only be used
804      * with resources whose value is the name of an asset file -- that is, it can be
805      * used to open drawable, sound, and raw resources; it will fail on string
806      * and color resources.
807      *
808      * @param id The resource identifier to open, as generated by the appt tool.
809      * @param value The TypedValue object to hold the resource information.
810      *
811      * @return InputStream Access to the resource data.
812      *
813      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
814      */
openRawResource(int id, TypedValue value)815     public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
816         getValue(id, value, true);
817 
818         try {
819             return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
820                     AssetManager.ACCESS_STREAMING);
821         } catch (Exception e) {
822             NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
823                     " from drawable resource ID #0x" + Integer.toHexString(id));
824             rnf.initCause(e);
825             throw rnf;
826         }
827     }
828 
829     /**
830      * Open a file descriptor for reading a raw resource.  This can only be used
831      * with resources whose value is the name of an asset files -- that is, it can be
832      * used to open drawable, sound, and raw resources; it will fail on string
833      * and color resources.
834      *
835      * <p>This function only works for resources that are stored in the package
836      * as uncompressed data, which typically includes things like mp3 files
837      * and png images.
838      *
839      * @param id The resource identifier to open, as generated by the appt
840      *           tool.
841      *
842      * @return AssetFileDescriptor A new file descriptor you can use to read
843      * the resource.  This includes the file descriptor itself, as well as the
844      * offset and length of data where the resource appears in the file.  A
845      * null is returned if the file exists but is compressed.
846      *
847      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
848      *
849      */
openRawResourceFd(int id)850     public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
851         synchronized (mTmpValue) {
852             TypedValue value = mTmpValue;
853             getValue(id, value, true);
854 
855             try {
856                 return mAssets.openNonAssetFd(
857                     value.assetCookie, value.string.toString());
858             } catch (Exception e) {
859                 NotFoundException rnf = new NotFoundException(
860                     "File " + value.string.toString()
861                     + " from drawable resource ID #0x"
862                     + Integer.toHexString(id));
863                 rnf.initCause(e);
864                 throw rnf;
865             }
866 
867         }
868     }
869 
870     /**
871      * Return the raw data associated with a particular resource ID.
872      *
873      * @param id The desired resource identifier, as generated by the aapt
874      *           tool. This integer encodes the package, type, and resource
875      *           entry. The value 0 is an invalid identifier.
876      * @param outValue Object in which to place the resource data.
877      * @param resolveRefs If true, a resource that is a reference to another
878      *                    resource will be followed so that you receive the
879      *                    actual final resource data.  If false, the TypedValue
880      *                    will be filled in with the reference itself.
881      *
882      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
883      *
884      */
getValue(int id, TypedValue outValue, boolean resolveRefs)885     public void getValue(int id, TypedValue outValue, boolean resolveRefs)
886             throws NotFoundException {
887         boolean found = mAssets.getResourceValue(id, outValue, resolveRefs);
888         if (found) {
889             return;
890         }
891         throw new NotFoundException("Resource ID #0x"
892                                     + Integer.toHexString(id));
893     }
894 
895     /**
896      * Return the raw data associated with a particular resource ID.
897      * See getIdentifier() for information on how names are mapped to resource
898      * IDs, and getString(int) for information on how string resources are
899      * retrieved.
900      *
901      * <p>Note: use of this function is discouraged.  It is much more
902      * efficient to retrieve resources by identifier than by name.
903      *
904      * @param name The name of the desired resource.  This is passed to
905      *             getIdentifier() with a default type of "string".
906      * @param outValue Object in which to place the resource data.
907      * @param resolveRefs If true, a resource that is a reference to another
908      *                    resource will be followed so that you receive the
909      *                    actual final resource data.  If false, the TypedValue
910      *                    will be filled in with the reference itself.
911      *
912      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
913      *
914      */
getValue(String name, TypedValue outValue, boolean resolveRefs)915     public void getValue(String name, TypedValue outValue, boolean resolveRefs)
916             throws NotFoundException {
917         int id = getIdentifier(name, "string", null);
918         if (id != 0) {
919             getValue(id, outValue, resolveRefs);
920             return;
921         }
922         throw new NotFoundException("String resource name " + name);
923     }
924 
925     /**
926      * This class holds the current attribute values for a particular theme.
927      * In other words, a Theme is a set of values for resource attributes;
928      * these are used in conjunction with {@link TypedArray}
929      * to resolve the final value for an attribute.
930      *
931      * <p>The Theme's attributes come into play in two ways: (1) a styled
932      * attribute can explicit reference a value in the theme through the
933      * "?themeAttribute" syntax; (2) if no value has been defined for a
934      * particular styled attribute, as a last resort we will try to find that
935      * attribute's value in the Theme.
936      *
937      * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
938      * retrieve XML attributes with style and theme information applied.
939      */
940     public final class Theme {
941         /**
942          * Place new attribute values into the theme.  The style resource
943          * specified by <var>resid</var> will be retrieved from this Theme's
944          * resources, its values placed into the Theme object.
945          *
946          * <p>The semantics of this function depends on the <var>force</var>
947          * argument:  If false, only values that are not already defined in
948          * the theme will be copied from the system resource; otherwise, if
949          * any of the style's attributes are already defined in the theme, the
950          * current values in the theme will be overwritten.
951          *
952          * @param resid The resource ID of a style resource from which to
953          *              obtain attribute values.
954          * @param force If true, values in the style resource will always be
955          *              used in the theme; otherwise, they will only be used
956          *              if not already defined in the theme.
957          */
applyStyle(int resid, boolean force)958         public void applyStyle(int resid, boolean force) {
959             AssetManager.applyThemeStyle(mTheme, resid, force);
960         }
961 
962         /**
963          * Set this theme to hold the same contents as the theme
964          * <var>other</var>.  If both of these themes are from the same
965          * Resources object, they will be identical after this function
966          * returns.  If they are from different Resources, only the resources
967          * they have in common will be set in this theme.
968          *
969          * @param other The existing Theme to copy from.
970          */
setTo(Theme other)971         public void setTo(Theme other) {
972             AssetManager.copyTheme(mTheme, other.mTheme);
973         }
974 
975         /**
976          * Return a StyledAttributes holding the values defined by
977          * <var>Theme</var> which are listed in <var>attrs</var>.
978          *
979          * <p>Be sure to call StyledAttributes.recycle() when you are done with
980          * the array.
981          *
982          * @param attrs The desired attributes.
983          *
984          * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
985          *
986          * @return Returns a TypedArray holding an array of the attribute values.
987          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
988          * when done with it.
989          *
990          * @see Resources#obtainAttributes
991          * @see #obtainStyledAttributes(int, int[])
992          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
993          */
obtainStyledAttributes(int[] attrs)994         public TypedArray obtainStyledAttributes(int[] attrs) {
995             int len = attrs.length;
996             TypedArray array = getCachedStyledAttributes(len);
997             array.mRsrcs = attrs;
998             AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
999                     array.mData, array.mIndices);
1000             return array;
1001         }
1002 
1003         /**
1004          * Return a StyledAttributes holding the values defined by the style
1005          * resource <var>resid</var> which are listed in <var>attrs</var>.
1006          *
1007          * <p>Be sure to call StyledAttributes.recycle() when you are done with
1008          * the array.
1009          *
1010          * @param resid The desired style resource.
1011          * @param attrs The desired attributes in the style.
1012          *
1013          * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1014          *
1015          * @return Returns a TypedArray holding an array of the attribute values.
1016          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1017          * when done with it.
1018          *
1019          * @see Resources#obtainAttributes
1020          * @see #obtainStyledAttributes(int[])
1021          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1022          */
obtainStyledAttributes(int resid, int[] attrs)1023         public TypedArray obtainStyledAttributes(int resid, int[] attrs)
1024                 throws NotFoundException {
1025             int len = attrs.length;
1026             TypedArray array = getCachedStyledAttributes(len);
1027             array.mRsrcs = attrs;
1028 
1029             AssetManager.applyStyle(mTheme, 0, resid, 0, attrs,
1030                     array.mData, array.mIndices);
1031             if (false) {
1032                 int[] data = array.mData;
1033 
1034                 System.out.println("**********************************************************");
1035                 System.out.println("**********************************************************");
1036                 System.out.println("**********************************************************");
1037                 System.out.println("Attributes:");
1038                 String s = "  Attrs:";
1039                 int i;
1040                 for (i=0; i<attrs.length; i++) {
1041                     s = s + " 0x" + Integer.toHexString(attrs[i]);
1042                 }
1043                 System.out.println(s);
1044                 s = "  Found:";
1045                 TypedValue value = new TypedValue();
1046                 for (i=0; i<attrs.length; i++) {
1047                     int d = i*AssetManager.STYLE_NUM_ENTRIES;
1048                     value.type = data[d+AssetManager.STYLE_TYPE];
1049                     value.data = data[d+AssetManager.STYLE_DATA];
1050                     value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1051                     value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1052                     s = s + " 0x" + Integer.toHexString(attrs[i])
1053                         + "=" + value;
1054                 }
1055                 System.out.println(s);
1056             }
1057             return array;
1058         }
1059 
1060         /**
1061          * Return a StyledAttributes holding the attribute values in
1062          * <var>set</var>
1063          * that are listed in <var>attrs</var>.  In addition, if the given
1064          * AttributeSet specifies a style class (through the "style" attribute),
1065          * that style will be applied on top of the base attributes it defines.
1066          *
1067          * <p>Be sure to call StyledAttributes.recycle() when you are done with
1068          * the array.
1069          *
1070          * <p>When determining the final value of a particular attribute, there
1071          * are four inputs that come into play:</p>
1072          *
1073          * <ol>
1074          *     <li> Any attribute values in the given AttributeSet.
1075          *     <li> The style resource specified in the AttributeSet (named
1076          *     "style").
1077          *     <li> The default style specified by <var>defStyleAttr</var> and
1078          *     <var>defStyleRes</var>
1079          *     <li> The base values in this theme.
1080          * </ol>
1081          *
1082          * <p>Each of these inputs is considered in-order, with the first listed
1083          * taking precedence over the following ones.  In other words, if in the
1084          * AttributeSet you have supplied <code>&lt;Button
1085          * textColor="#ff000000"&gt;</code>, then the button's text will
1086          * <em>always</em> be black, regardless of what is specified in any of
1087          * the styles.
1088          *
1089          * @param set The base set of attribute values.  May be null.
1090          * @param attrs The desired attributes to be retrieved.
1091          * @param defStyleAttr An attribute in the current theme that contains a
1092          *                     reference to a style resource that supplies
1093          *                     defaults values for the StyledAttributes.  Can be
1094          *                     0 to not look for defaults.
1095          * @param defStyleRes A resource identifier of a style resource that
1096          *                    supplies default values for the StyledAttributes,
1097          *                    used only if defStyleAttr is 0 or can not be found
1098          *                    in the theme.  Can be 0 to not look for defaults.
1099          *
1100          * @return Returns a TypedArray holding an array of the attribute values.
1101          * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1102          * when done with it.
1103          *
1104          * @see Resources#obtainAttributes
1105          * @see #obtainStyledAttributes(int[])
1106          * @see #obtainStyledAttributes(int, int[])
1107          */
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)1108         public TypedArray obtainStyledAttributes(AttributeSet set,
1109                 int[] attrs, int defStyleAttr, int defStyleRes) {
1110             int len = attrs.length;
1111             TypedArray array = getCachedStyledAttributes(len);
1112 
1113             // XXX note that for now we only work with compiled XML files.
1114             // To support generic XML files we will need to manually parse
1115             // out the attributes from the XML file (applying type information
1116             // contained in the resources and such).
1117             XmlBlock.Parser parser = (XmlBlock.Parser)set;
1118             AssetManager.applyStyle(
1119                 mTheme, defStyleAttr, defStyleRes,
1120                 parser != null ? parser.mParseState : 0, attrs,
1121                         array.mData, array.mIndices);
1122 
1123             array.mRsrcs = attrs;
1124             array.mXml = parser;
1125 
1126             if (false) {
1127                 int[] data = array.mData;
1128 
1129                 System.out.println("Attributes:");
1130                 String s = "  Attrs:";
1131                 int i;
1132                 for (i=0; i<set.getAttributeCount(); i++) {
1133                     s = s + " " + set.getAttributeName(i);
1134                     int id = set.getAttributeNameResource(i);
1135                     if (id != 0) {
1136                         s = s + "(0x" + Integer.toHexString(id) + ")";
1137                     }
1138                     s = s + "=" + set.getAttributeValue(i);
1139                 }
1140                 System.out.println(s);
1141                 s = "  Found:";
1142                 TypedValue value = new TypedValue();
1143                 for (i=0; i<attrs.length; i++) {
1144                     int d = i*AssetManager.STYLE_NUM_ENTRIES;
1145                     value.type = data[d+AssetManager.STYLE_TYPE];
1146                     value.data = data[d+AssetManager.STYLE_DATA];
1147                     value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1148                     value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1149                     s = s + " 0x" + Integer.toHexString(attrs[i])
1150                         + "=" + value;
1151                 }
1152                 System.out.println(s);
1153             }
1154 
1155             return array;
1156         }
1157 
1158         /**
1159          * Retrieve the value of an attribute in the Theme.  The contents of
1160          * <var>outValue</var> are ultimately filled in by
1161          * {@link Resources#getValue}.
1162          *
1163          * @param resid The resource identifier of the desired theme
1164          *              attribute.
1165          * @param outValue Filled in with the ultimate resource value supplied
1166          *                 by the attribute.
1167          * @param resolveRefs If true, resource references will be walked; if
1168          *                    false, <var>outValue</var> may be a
1169          *                    TYPE_REFERENCE.  In either case, it will never
1170          *                    be a TYPE_ATTRIBUTE.
1171          *
1172          * @return boolean Returns true if the attribute was found and
1173          *         <var>outValue</var> is valid, else false.
1174          */
resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs)1175         public boolean resolveAttribute(int resid, TypedValue outValue,
1176                 boolean resolveRefs) {
1177             boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1178             if (false) {
1179                 System.out.println(
1180                     "resolveAttribute #" + Integer.toHexString(resid)
1181                     + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type)
1182                     + ", data=0x" + Integer.toHexString(outValue.data));
1183             }
1184             return got;
1185         }
1186 
1187         /**
1188          * Print contents of this theme out to the log.  For debugging only.
1189          *
1190          * @param priority The log priority to use.
1191          * @param tag The log tag to use.
1192          * @param prefix Text to prefix each line printed.
1193          */
dump(int priority, String tag, String prefix)1194         public void dump(int priority, String tag, String prefix) {
1195             AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1196         }
1197 
finalize()1198         protected void finalize() throws Throwable {
1199             super.finalize();
1200             mAssets.releaseTheme(mTheme);
1201         }
1202 
Theme()1203         /*package*/ Theme() {
1204             mAssets = Resources.this.mAssets;
1205             mTheme = mAssets.createTheme();
1206         }
1207 
1208         private final AssetManager mAssets;
1209         private final int mTheme;
1210     }
1211 
1212     /**
1213      * Generate a new Theme object for this set of Resources.  It initially
1214      * starts out empty.
1215      *
1216      * @return Theme The newly created Theme container.
1217      */
newTheme()1218     public final Theme newTheme() {
1219         return new Theme();
1220     }
1221 
1222     /**
1223      * Retrieve a set of basic attribute values from an AttributeSet, not
1224      * performing styling of them using a theme and/or style resources.
1225      *
1226      * @param set The current attribute values to retrieve.
1227      * @param attrs The specific attributes to be retrieved.
1228      * @return Returns a TypedArray holding an array of the attribute values.
1229      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1230      * when done with it.
1231      *
1232      * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1233      */
obtainAttributes(AttributeSet set, int[] attrs)1234     public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1235         int len = attrs.length;
1236         TypedArray array = getCachedStyledAttributes(len);
1237 
1238         // XXX note that for now we only work with compiled XML files.
1239         // To support generic XML files we will need to manually parse
1240         // out the attributes from the XML file (applying type information
1241         // contained in the resources and such).
1242         XmlBlock.Parser parser = (XmlBlock.Parser)set;
1243         mAssets.retrieveAttributes(parser.mParseState, attrs,
1244                 array.mData, array.mIndices);
1245 
1246         array.mRsrcs = attrs;
1247         array.mXml = parser;
1248 
1249         return array;
1250     }
1251 
1252     /**
1253      * Store the newly updated configuration.
1254      */
updateConfiguration(Configuration config, DisplayMetrics metrics)1255     public void updateConfiguration(Configuration config,
1256             DisplayMetrics metrics) {
1257         synchronized (mTmpValue) {
1258             int configChanges = 0xfffffff;
1259             if (config != null) {
1260                 configChanges = mConfiguration.updateFrom(config);
1261             }
1262             if (metrics != null) {
1263                 mMetrics.setTo(metrics);
1264                 mMetrics.updateMetrics(mCompatibilityInfo,
1265                         mConfiguration.orientation, mConfiguration.screenLayout);
1266             }
1267             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
1268 
1269             String locale = null;
1270             if (mConfiguration.locale != null) {
1271                 locale = mConfiguration.locale.getLanguage();
1272                 if (mConfiguration.locale.getCountry() != null) {
1273                     locale += "-" + mConfiguration.locale.getCountry();
1274                 }
1275             }
1276             int width, height;
1277             if (mMetrics.widthPixels >= mMetrics.heightPixels) {
1278                 width = mMetrics.widthPixels;
1279                 height = mMetrics.heightPixels;
1280             } else {
1281                 //noinspection SuspiciousNameCombination
1282                 width = mMetrics.heightPixels;
1283                 //noinspection SuspiciousNameCombination
1284                 height = mMetrics.widthPixels;
1285             }
1286             int keyboardHidden = mConfiguration.keyboardHidden;
1287             if (keyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO
1288                     && mConfiguration.hardKeyboardHidden
1289                             == Configuration.HARDKEYBOARDHIDDEN_YES) {
1290                 keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
1291             }
1292             mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
1293                     locale, mConfiguration.orientation,
1294                     mConfiguration.touchscreen,
1295                     (int)(mMetrics.density*160), mConfiguration.keyboard,
1296                     keyboardHidden, mConfiguration.navigation, width, height,
1297                     mConfiguration.screenLayout, sSdkVersion);
1298             int N = mDrawableCache.size();
1299             if (DEBUG_CONFIG) {
1300                 Log.d(TAG, "Cleaning up drawables config changes: 0x"
1301                         + Integer.toHexString(configChanges));
1302             }
1303             for (int i=0; i<N; i++) {
1304                 WeakReference<Drawable.ConstantState> ref = mDrawableCache.valueAt(i);
1305                 if (ref != null) {
1306                     Drawable.ConstantState cs = ref.get();
1307                     if (cs != null) {
1308                         if (Configuration.needNewResources(
1309                                 configChanges, cs.getChangingConfigurations())) {
1310                             if (DEBUG_CONFIG) {
1311                                 Log.d(TAG, "FLUSHING #0x"
1312                                         + Long.toHexString(mDrawableCache.keyAt(i))
1313                                         + " / " + cs + " with changes: 0x"
1314                                         + Integer.toHexString(cs.getChangingConfigurations()));
1315                             }
1316                             mDrawableCache.setValueAt(i, null);
1317                         } else if (DEBUG_CONFIG) {
1318                             Log.d(TAG, "(Keeping #0x"
1319                                     + Long.toHexString(mDrawableCache.keyAt(i))
1320                                     + " / " + cs + " with changes: 0x"
1321                                     + Integer.toHexString(cs.getChangingConfigurations())
1322                                     + ")");
1323                         }
1324                     }
1325                 }
1326             }
1327             mDrawableCache.clear();
1328             mColorStateListCache.clear();
1329             flushLayoutCache();
1330         }
1331         synchronized (mSync) {
1332             if (mPluralRule != null) {
1333                 mPluralRule = PluralRules.ruleForLocale(config.locale);
1334             }
1335         }
1336     }
1337 
1338     /**
1339      * Update the system resources configuration if they have previously
1340      * been initialized.
1341      *
1342      * @hide
1343      */
updateSystemConfiguration(Configuration config, DisplayMetrics metrics)1344     public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
1345         if (mSystem != null) {
1346             mSystem.updateConfiguration(config, metrics);
1347             //Log.i(TAG, "Updated system resources " + mSystem
1348             //        + ": " + mSystem.getConfiguration());
1349         }
1350     }
1351 
1352     /**
1353      * Return the current display metrics that are in effect for this resource
1354      * object.  The returned object should be treated as read-only.
1355      *
1356      * @return The resource's current display metrics.
1357      */
getDisplayMetrics()1358     public DisplayMetrics getDisplayMetrics() {
1359         return mMetrics;
1360     }
1361 
1362     /**
1363      * Return the current configuration that is in effect for this resource
1364      * object.  The returned object should be treated as read-only.
1365      *
1366      * @return The resource's current configuration.
1367      */
getConfiguration()1368     public Configuration getConfiguration() {
1369         return mConfiguration;
1370     }
1371 
1372     /**
1373      * Return the compatibility mode information for the application.
1374      * The returned object should be treated as read-only.
1375      *
1376      * @return compatibility info. null if the app does not require compatibility mode.
1377      * @hide
1378      */
getCompatibilityInfo()1379     public CompatibilityInfo getCompatibilityInfo() {
1380         return mCompatibilityInfo;
1381     }
1382 
1383     /**
1384      * This is just for testing.
1385      * @hide
1386      */
setCompatibilityInfo(CompatibilityInfo ci)1387     public void setCompatibilityInfo(CompatibilityInfo ci) {
1388         mCompatibilityInfo = ci;
1389         updateConfiguration(mConfiguration, mMetrics);
1390     }
1391 
1392     /**
1393      * Return a resource identifier for the given resource name.  A fully
1394      * qualified resource name is of the form "package:type/entry".  The first
1395      * two components (package and type) are optional if defType and
1396      * defPackage, respectively, are specified here.
1397      *
1398      * <p>Note: use of this function is discouraged.  It is much more
1399      * efficient to retrieve resources by identifier than by name.
1400      *
1401      * @param name The name of the desired resource.
1402      * @param defType Optional default resource type to find, if "type/" is
1403      *                not included in the name.  Can be null to require an
1404      *                explicit type.
1405      * @param defPackage Optional default package to find, if "package:" is
1406      *                   not included in the name.  Can be null to require an
1407      *                   explicit package.
1408      *
1409      * @return int The associated resource identifier.  Returns 0 if no such
1410      *         resource was found.  (0 is not a valid resource ID.)
1411      */
getIdentifier(String name, String defType, String defPackage)1412     public int getIdentifier(String name, String defType, String defPackage) {
1413         try {
1414             return Integer.parseInt(name);
1415         } catch (Exception e) {
1416             // Ignore
1417         }
1418         return mAssets.getResourceIdentifier(name, defType, defPackage);
1419     }
1420 
1421     /**
1422      * Return the full name for a given resource identifier.  This name is
1423      * a single string of the form "package:type/entry".
1424      *
1425      * @param resid The resource identifier whose name is to be retrieved.
1426      *
1427      * @return A string holding the name of the resource.
1428      *
1429      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1430      *
1431      * @see #getResourcePackageName
1432      * @see #getResourceTypeName
1433      * @see #getResourceEntryName
1434      */
getResourceName(int resid)1435     public String getResourceName(int resid) throws NotFoundException {
1436         String str = mAssets.getResourceName(resid);
1437         if (str != null) return str;
1438         throw new NotFoundException("Unable to find resource ID #0x"
1439                 + Integer.toHexString(resid));
1440     }
1441 
1442     /**
1443      * Return the package name for a given resource identifier.
1444      *
1445      * @param resid The resource identifier whose package name is to be
1446      * retrieved.
1447      *
1448      * @return A string holding the package name of the resource.
1449      *
1450      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1451      *
1452      * @see #getResourceName
1453      */
getResourcePackageName(int resid)1454     public String getResourcePackageName(int resid) throws NotFoundException {
1455         String str = mAssets.getResourcePackageName(resid);
1456         if (str != null) return str;
1457         throw new NotFoundException("Unable to find resource ID #0x"
1458                 + Integer.toHexString(resid));
1459     }
1460 
1461     /**
1462      * Return the type name for a given resource identifier.
1463      *
1464      * @param resid The resource identifier whose type name is to be
1465      * retrieved.
1466      *
1467      * @return A string holding the type name of the resource.
1468      *
1469      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1470      *
1471      * @see #getResourceName
1472      */
getResourceTypeName(int resid)1473     public String getResourceTypeName(int resid) throws NotFoundException {
1474         String str = mAssets.getResourceTypeName(resid);
1475         if (str != null) return str;
1476         throw new NotFoundException("Unable to find resource ID #0x"
1477                 + Integer.toHexString(resid));
1478     }
1479 
1480     /**
1481      * Return the entry name for a given resource identifier.
1482      *
1483      * @param resid The resource identifier whose entry name is to be
1484      * retrieved.
1485      *
1486      * @return A string holding the entry name of the resource.
1487      *
1488      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1489      *
1490      * @see #getResourceName
1491      */
getResourceEntryName(int resid)1492     public String getResourceEntryName(int resid) throws NotFoundException {
1493         String str = mAssets.getResourceEntryName(resid);
1494         if (str != null) return str;
1495         throw new NotFoundException("Unable to find resource ID #0x"
1496                 + Integer.toHexString(resid));
1497     }
1498 
1499     /**
1500      * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
1501      * an XML file.  You call this when you are at the parent tag of the
1502      * extra tags, and it return once all of the child tags have been parsed.
1503      * This will call {@link #parseBundleExtra} for each extra tag encountered.
1504      *
1505      * @param parser The parser from which to retrieve the extras.
1506      * @param outBundle A Bundle in which to place all parsed extras.
1507      * @throws XmlPullParserException
1508      * @throws IOException
1509      */
parseBundleExtras(XmlResourceParser parser, Bundle outBundle)1510     public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
1511             throws XmlPullParserException, IOException {
1512         int outerDepth = parser.getDepth();
1513         int type;
1514         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1515                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1516             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1517                 continue;
1518             }
1519 
1520             String nodeName = parser.getName();
1521             if (nodeName.equals("extra")) {
1522                 parseBundleExtra("extra", parser, outBundle);
1523                 XmlUtils.skipCurrentTag(parser);
1524 
1525             } else {
1526                 XmlUtils.skipCurrentTag(parser);
1527             }
1528         }
1529     }
1530 
1531     /**
1532      * Parse a name/value pair out of an XML tag holding that data.  The
1533      * AttributeSet must be holding the data defined by
1534      * {@link android.R.styleable#Extra}.  The following value types are supported:
1535      * <ul>
1536      * <li> {@link TypedValue#TYPE_STRING}:
1537      * {@link Bundle#putCharSequence Bundle.putCharSequence()}
1538      * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
1539      * {@link Bundle#putCharSequence Bundle.putBoolean()}
1540      * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
1541      * {@link Bundle#putCharSequence Bundle.putBoolean()}
1542      * <li> {@link TypedValue#TYPE_FLOAT}:
1543      * {@link Bundle#putCharSequence Bundle.putFloat()}
1544      * </ul>
1545      *
1546      * @param tagName The name of the tag these attributes come from; this is
1547      * only used for reporting error messages.
1548      * @param attrs The attributes from which to retrieve the name/value pair.
1549      * @param outBundle The Bundle in which to place the parsed value.
1550      * @throws XmlPullParserException If the attributes are not valid.
1551      */
parseBundleExtra(String tagName, AttributeSet attrs, Bundle outBundle)1552     public void parseBundleExtra(String tagName, AttributeSet attrs,
1553             Bundle outBundle) throws XmlPullParserException {
1554         TypedArray sa = obtainAttributes(attrs,
1555                 com.android.internal.R.styleable.Extra);
1556 
1557         String name = sa.getString(
1558                 com.android.internal.R.styleable.Extra_name);
1559         if (name == null) {
1560             sa.recycle();
1561             throw new XmlPullParserException("<" + tagName
1562                     + "> requires an android:name attribute at "
1563                     + attrs.getPositionDescription());
1564         }
1565 
1566         TypedValue v = sa.peekValue(
1567                 com.android.internal.R.styleable.Extra_value);
1568         if (v != null) {
1569             if (v.type == TypedValue.TYPE_STRING) {
1570                 CharSequence cs = v.coerceToString();
1571                 outBundle.putCharSequence(name, cs);
1572             } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
1573                 outBundle.putBoolean(name, v.data != 0);
1574             } else if (v.type >= TypedValue.TYPE_FIRST_INT
1575                     && v.type <= TypedValue.TYPE_LAST_INT) {
1576                 outBundle.putInt(name, v.data);
1577             } else if (v.type == TypedValue.TYPE_FLOAT) {
1578                 outBundle.putFloat(name, v.getFloat());
1579             } else {
1580                 sa.recycle();
1581                 throw new XmlPullParserException("<" + tagName
1582                         + "> only supports string, integer, float, color, and boolean at "
1583                         + attrs.getPositionDescription());
1584             }
1585         } else {
1586             sa.recycle();
1587             throw new XmlPullParserException("<" + tagName
1588                     + "> requires an android:value or android:resource attribute at "
1589                     + attrs.getPositionDescription());
1590         }
1591 
1592         sa.recycle();
1593     }
1594 
1595     /**
1596      * Retrieve underlying AssetManager storage for these resources.
1597      */
getAssets()1598     public final AssetManager getAssets() {
1599         return mAssets;
1600     }
1601 
1602     /**
1603      * Call this to remove all cached loaded layout resources from the
1604      * Resources object.  Only intended for use with performance testing
1605      * tools.
1606      */
flushLayoutCache()1607     public final void flushLayoutCache() {
1608         synchronized (mCachedXmlBlockIds) {
1609             // First see if this block is in our cache.
1610             final int num = mCachedXmlBlockIds.length;
1611             for (int i=0; i<num; i++) {
1612                 mCachedXmlBlockIds[i] = -0;
1613                 XmlBlock oldBlock = mCachedXmlBlocks[i];
1614                 if (oldBlock != null) {
1615                     oldBlock.close();
1616                 }
1617                 mCachedXmlBlocks[i] = null;
1618             }
1619         }
1620     }
1621 
1622     /**
1623      * Start preloading of resource data using this Resources object.  Only
1624      * for use by the zygote process for loading common system resources.
1625      * {@hide}
1626      */
startPreloading()1627     public final void startPreloading() {
1628         synchronized (mSync) {
1629             if (mPreloaded) {
1630                 throw new IllegalStateException("Resources already preloaded");
1631             }
1632             mPreloaded = true;
1633             mPreloading = true;
1634         }
1635     }
1636 
1637     /**
1638      * Called by zygote when it is done preloading resources, to change back
1639      * to normal Resources operation.
1640      */
finishPreloading()1641     public final void finishPreloading() {
1642         if (mPreloading) {
1643             mPreloading = false;
1644             flushLayoutCache();
1645         }
1646     }
1647 
loadDrawable(TypedValue value, int id)1648     /*package*/ Drawable loadDrawable(TypedValue value, int id)
1649             throws NotFoundException {
1650 
1651         if (TRACE_FOR_PRELOAD) {
1652             // Log only framework resources
1653             if ((id >>> 24) == 0x1) {
1654                 final String name = getResourceName(id);
1655                 if (name != null) android.util.Log.d("PreloadDrawable", name);
1656             }
1657         }
1658 
1659         final long key = (((long) value.assetCookie) << 32) | value.data;
1660         Drawable dr = getCachedDrawable(key);
1661 
1662         if (dr != null) {
1663             return dr;
1664         }
1665 
1666         Drawable.ConstantState cs = sPreloadedDrawables.get(key);
1667         if (cs != null) {
1668             dr = cs.newDrawable(this);
1669         } else {
1670             if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
1671                     value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
1672                 dr = new ColorDrawable(value.data);
1673             }
1674 
1675             if (dr == null) {
1676                 if (value.string == null) {
1677                     throw new NotFoundException(
1678                             "Resource is not a Drawable (color or path): " + value);
1679                 }
1680 
1681                 String file = value.string.toString();
1682 
1683                 if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
1684                         + value.assetCookie + ": " + file);
1685 
1686                 if (file.endsWith(".xml")) {
1687                     try {
1688                         XmlResourceParser rp = loadXmlResourceParser(
1689                                 file, id, value.assetCookie, "drawable");
1690                         dr = Drawable.createFromXml(this, rp);
1691                         rp.close();
1692                     } catch (Exception e) {
1693                         NotFoundException rnf = new NotFoundException(
1694                             "File " + file + " from drawable resource ID #0x"
1695                             + Integer.toHexString(id));
1696                         rnf.initCause(e);
1697                         throw rnf;
1698                     }
1699 
1700                 } else {
1701                     try {
1702                         InputStream is = mAssets.openNonAsset(
1703                                 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
1704         //                System.out.println("Opened file " + file + ": " + is);
1705                         dr = Drawable.createFromResourceStream(this, value, is,
1706                                 file, null);
1707                         is.close();
1708         //                System.out.println("Created stream: " + dr);
1709                     } catch (Exception e) {
1710                         NotFoundException rnf = new NotFoundException(
1711                             "File " + file + " from drawable resource ID #0x"
1712                             + Integer.toHexString(id));
1713                         rnf.initCause(e);
1714                         throw rnf;
1715                     }
1716                 }
1717             }
1718         }
1719 
1720         if (dr != null) {
1721             dr.setChangingConfigurations(value.changingConfigurations);
1722             cs = dr.getConstantState();
1723             if (cs != null) {
1724                 if (mPreloading) {
1725                     sPreloadedDrawables.put(key, cs);
1726                 } else {
1727                     synchronized (mTmpValue) {
1728                         //Log.i(TAG, "Saving cached drawable @ #" +
1729                         //        Integer.toHexString(key.intValue())
1730                         //        + " in " + this + ": " + cs);
1731                         mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
1732                     }
1733                 }
1734             }
1735         }
1736 
1737         return dr;
1738     }
1739 
getCachedDrawable(long key)1740     private Drawable getCachedDrawable(long key) {
1741         synchronized (mTmpValue) {
1742             WeakReference<Drawable.ConstantState> wr = mDrawableCache.get(key);
1743             if (wr != null) {   // we have the key
1744                 Drawable.ConstantState entry = wr.get();
1745                 if (entry != null) {
1746                     //Log.i(TAG, "Returning cached drawable @ #" +
1747                     //        Integer.toHexString(((Integer)key).intValue())
1748                     //        + " in " + this + ": " + entry);
1749                     return entry.newDrawable(this);
1750                 }
1751                 else {  // our entry has been purged
1752                     mDrawableCache.delete(key);
1753                 }
1754             }
1755         }
1756         return null;
1757     }
1758 
loadColorStateList(TypedValue value, int id)1759     /*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
1760             throws NotFoundException {
1761         if (TRACE_FOR_PRELOAD) {
1762             // Log only framework resources
1763             if ((id >>> 24) == 0x1) {
1764                 final String name = getResourceName(id);
1765                 if (name != null) android.util.Log.d("PreloadColorStateList", name);
1766             }
1767         }
1768 
1769         final int key = (value.assetCookie << 24) | value.data;
1770 
1771         ColorStateList csl;
1772 
1773         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
1774                 value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
1775 
1776             csl = mPreloadedColorStateLists.get(key);
1777             if (csl != null) {
1778                 return csl;
1779             }
1780 
1781             csl = ColorStateList.valueOf(value.data);
1782             if (mPreloading) {
1783                 mPreloadedColorStateLists.put(key, csl);
1784             }
1785 
1786             return csl;
1787         }
1788 
1789         csl = getCachedColorStateList(key);
1790         if (csl != null) {
1791             return csl;
1792         }
1793 
1794         csl = mPreloadedColorStateLists.get(key);
1795         if (csl != null) {
1796             return csl;
1797         }
1798 
1799         if (value.string == null) {
1800             throw new NotFoundException(
1801                     "Resource is not a ColorStateList (color or path): " + value);
1802         }
1803 
1804         String file = value.string.toString();
1805 
1806         if (file.endsWith(".xml")) {
1807             try {
1808                 XmlResourceParser rp = loadXmlResourceParser(
1809                         file, id, value.assetCookie, "colorstatelist");
1810                 csl = ColorStateList.createFromXml(this, rp);
1811                 rp.close();
1812             } catch (Exception e) {
1813                 NotFoundException rnf = new NotFoundException(
1814                     "File " + file + " from color state list resource ID #0x"
1815                     + Integer.toHexString(id));
1816                 rnf.initCause(e);
1817                 throw rnf;
1818             }
1819         } else {
1820             throw new NotFoundException(
1821                     "File " + file + " from drawable resource ID #0x"
1822                     + Integer.toHexString(id) + ": .xml extension required");
1823         }
1824 
1825         if (csl != null) {
1826             if (mPreloading) {
1827                 mPreloadedColorStateLists.put(key, csl);
1828             } else {
1829                 synchronized (mTmpValue) {
1830                     //Log.i(TAG, "Saving cached color state list @ #" +
1831                     //        Integer.toHexString(key.intValue())
1832                     //        + " in " + this + ": " + csl);
1833                     mColorStateListCache.put(
1834                         key, new WeakReference<ColorStateList>(csl));
1835                 }
1836             }
1837         }
1838 
1839         return csl;
1840     }
1841 
getCachedColorStateList(int key)1842     private ColorStateList getCachedColorStateList(int key) {
1843         synchronized (mTmpValue) {
1844             WeakReference<ColorStateList> wr = mColorStateListCache.get(key);
1845             if (wr != null) {   // we have the key
1846                 ColorStateList entry = wr.get();
1847                 if (entry != null) {
1848                     //Log.i(TAG, "Returning cached color state list @ #" +
1849                     //        Integer.toHexString(((Integer)key).intValue())
1850                     //        + " in " + this + ": " + entry);
1851                     return entry;
1852                 }
1853                 else {  // our entry has been purged
1854                     mColorStateListCache.delete(key);
1855                 }
1856             }
1857         }
1858         return null;
1859     }
1860 
loadXmlResourceParser(int id, String type)1861     /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
1862             throws NotFoundException {
1863         synchronized (mTmpValue) {
1864             TypedValue value = mTmpValue;
1865             getValue(id, value, true);
1866             if (value.type == TypedValue.TYPE_STRING) {
1867                 return loadXmlResourceParser(value.string.toString(), id,
1868                         value.assetCookie, type);
1869             }
1870             throw new NotFoundException(
1871                     "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
1872                     + Integer.toHexString(value.type) + " is not valid");
1873         }
1874     }
1875 
loadXmlResourceParser(String file, int id, int assetCookie, String type)1876     /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
1877             int assetCookie, String type) throws NotFoundException {
1878         if (id != 0) {
1879             try {
1880                 // These may be compiled...
1881                 synchronized (mCachedXmlBlockIds) {
1882                     // First see if this block is in our cache.
1883                     final int num = mCachedXmlBlockIds.length;
1884                     for (int i=0; i<num; i++) {
1885                         if (mCachedXmlBlockIds[i] == id) {
1886                             //System.out.println("**** REUSING XML BLOCK!  id="
1887                             //                   + id + ", index=" + i);
1888                             return mCachedXmlBlocks[i].newParser();
1889                         }
1890                     }
1891 
1892                     // Not in the cache, create a new block and put it at
1893                     // the next slot in the cache.
1894                     XmlBlock block = mAssets.openXmlBlockAsset(
1895                             assetCookie, file);
1896                     if (block != null) {
1897                         int pos = mLastCachedXmlBlockIndex+1;
1898                         if (pos >= num) pos = 0;
1899                         mLastCachedXmlBlockIndex = pos;
1900                         XmlBlock oldBlock = mCachedXmlBlocks[pos];
1901                         if (oldBlock != null) {
1902                             oldBlock.close();
1903                         }
1904                         mCachedXmlBlockIds[pos] = id;
1905                         mCachedXmlBlocks[pos] = block;
1906                         //System.out.println("**** CACHING NEW XML BLOCK!  id="
1907                         //                   + id + ", index=" + pos);
1908                         return block.newParser();
1909                     }
1910                 }
1911             } catch (Exception e) {
1912                 NotFoundException rnf = new NotFoundException(
1913                         "File " + file + " from xml type " + type + " resource ID #0x"
1914                         + Integer.toHexString(id));
1915                 rnf.initCause(e);
1916                 throw rnf;
1917             }
1918         }
1919 
1920         throw new NotFoundException(
1921                 "File " + file + " from xml type " + type + " resource ID #0x"
1922                 + Integer.toHexString(id));
1923     }
1924 
1925     /**
1926      * Returns the display adjusted for the Resources' metrics.
1927      * @hide
1928      */
getDefaultDisplay(Display defaultDisplay)1929     public Display getDefaultDisplay(Display defaultDisplay) {
1930         if (mDefaultDisplay == null) {
1931             if (!mCompatibilityInfo.isScalingRequired() && mCompatibilityInfo.supportsScreen()) {
1932                 // the app supports the display. just use the default one.
1933                 mDefaultDisplay = defaultDisplay;
1934             } else {
1935                 // display needs adjustment.
1936                 mDefaultDisplay = Display.createMetricsBasedDisplay(
1937                         defaultDisplay.getDisplayId(), mMetrics);
1938             }
1939         }
1940         return mDefaultDisplay;
1941     }
1942 
getCachedStyledAttributes(int len)1943     private TypedArray getCachedStyledAttributes(int len) {
1944         synchronized (mTmpValue) {
1945             TypedArray attrs = mCachedStyledAttributes;
1946             if (attrs != null) {
1947                 mCachedStyledAttributes = null;
1948 
1949                 attrs.mLength = len;
1950                 int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
1951                 if (attrs.mData.length >= fullLen) {
1952                     return attrs;
1953                 }
1954                 attrs.mData = new int[fullLen];
1955                 attrs.mIndices = new int[1+len];
1956                 return attrs;
1957             }
1958             return new TypedArray(this,
1959                     new int[len*AssetManager.STYLE_NUM_ENTRIES],
1960                     new int[1+len], len);
1961         }
1962     }
1963 
Resources()1964     private Resources() {
1965         mAssets = AssetManager.getSystem();
1966         // NOTE: Intentionally leaving this uninitialized (all values set
1967         // to zero), so that anyone who tries to do something that requires
1968         // metrics will get a very wrong value.
1969         mConfiguration.setToDefaults();
1970         mMetrics.setToDefaults();
1971         updateConfiguration(null, null);
1972         mAssets.ensureStringBlocks();
1973         mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
1974     }
1975 }
1976