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