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