blob: 9bb3b75124f3ddd8ce423469d5f9c7d231ca7efb [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
19
Dianne Hackborn2269d1572010-02-24 19:54:22 -080020import com.android.internal.util.XmlUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021
22import org.xmlpull.v1.XmlPullParser;
23import org.xmlpull.v1.XmlPullParserException;
24
25import android.graphics.Movie;
26import android.graphics.drawable.Drawable;
27import android.graphics.drawable.ColorDrawable;
Dianne Hackborn3b3e1452009-09-24 19:22:12 -070028import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.Bundle;
30import android.os.SystemProperties;
31import android.util.AttributeSet;
32import android.util.DisplayMetrics;
33import android.util.Log;
34import android.util.SparseArray;
35import android.util.TypedValue;
Romain Guyfdbf6a72009-06-18 15:13:40 -070036import android.util.LongSparseArray;
Mitsuru Oshimaddd12532009-07-14 10:41:13 -070037import android.view.Display;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39import java.io.IOException;
40import java.io.InputStream;
41import java.lang.ref.WeakReference;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080042import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
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 */
49public 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
Dianne Hackborn3b3e1452009-09-24 19:22:12 -070055 // 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
Dianne Hackborn55339952009-11-01 21:16:59 -080058 + ("REL".equals(Build.VERSION.CODENAME) ? 0 : 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 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.
Romain Guyfdbf6a72009-06-18 15:13:40 -070065 private static final LongSparseArray<Drawable.ConstantState> sPreloadedDrawables
66 = new LongSparseArray<Drawable.ConstantState>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 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.
Romain Guyfdbf6a72009-06-18 15:13:40 -070074 private final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
75 = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 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;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -070090
Dianne Hackborna53b8282009-07-17 11:13:48 -070091 private CompatibilityInfo mCompatibilityInfo;
Mitsuru Oshimaddd12532009-07-14 10:41:13 -070092 private Display mDefaultDisplay;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -070093
Romain Guyfdbf6a72009-06-18 15:13:40 -070094 private static final LongSparseArray<Object> EMPTY_ARRAY = new LongSparseArray<Object>() {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -070095 @Override
Romain Guyfdbf6a72009-06-18 15:13:40 -070096 public void put(long k, Object o) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -070097 throw new UnsupportedOperationException();
98 }
99 @Override
Romain Guyfdbf6a72009-06-18 15:13:40 -0700100 public void append(long k, Object o) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700101 throw new UnsupportedOperationException();
102 }
103 };
104
105 @SuppressWarnings("unchecked")
Romain Guyfdbf6a72009-06-18 15:13:40 -0700106 private static <T> LongSparseArray<T> emptySparseArray() {
107 return (LongSparseArray<T>) EMPTY_ARRAY;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700108 }
109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 /**
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 {
115 public NotFoundException() {
116 }
117
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 */
133 public Resources(AssetManager assets, DisplayMetrics metrics,
134 Configuration config) {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700135 this(assets, metrics, config, (CompatibilityInfo) null);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700136 }
137
138 /**
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700139 * Creates a new Resources object with CompatibilityInfo.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700140 *
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).
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700146 * @param compInfo this resource's compatibility info. It will use the default compatibility
147 * info when it's null.
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700148 * @hide
149 */
150 public Resources(AssetManager assets, DisplayMetrics metrics,
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700151 Configuration config, CompatibilityInfo compInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 mAssets = assets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 mMetrics.setToDefaults();
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700154 if (compInfo == null) {
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700155 mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
Mitsuru Oshima64f59342009-06-21 00:03:11 -0700156 } else {
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700157 mCompatibilityInfo = compInfo;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700158 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700159 updateConfiguration(config, metrics);
160 assets.ensureStringBlocks();
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700161 }
162
163 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 * 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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
Andy Stadlerf8a7cea2009-04-10 16:24:47 -0700805 * with resources whose value is the name of an asset file -- that is, it can be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 * 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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1195 public void dump(int priority, String tag, String prefix) {
1196 AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1197 }
1198
1199 protected void finalize() throws Throwable {
1200 super.finalize();
1201 mAssets.releaseTheme(mTheme);
1202 }
1203
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 */
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 */
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 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07001252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 /**
1254 * Store the newly updated configuration.
1255 */
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 }
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001263 if (mConfiguration.locale == null) {
1264 mConfiguration.locale = Locale.getDefault();
1265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 if (metrics != null) {
1267 mMetrics.setTo(metrics);
Dianne Hackborn723738c2009-06-25 19:48:04 -07001268 mMetrics.updateMetrics(mCompatibilityInfo,
1269 mConfiguration.orientation, mConfiguration.screenLayout);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 }
1271 mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 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;
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -07001291 if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 && 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,
Tobias Haamel27b28b32010-02-09 23:09:17 +01001301 mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 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"
Romain Guyfdbf6a72009-06-18 15:13:40 -07001316 + Long.toHexString(mDrawableCache.keyAt(i))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 + " / " + 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"
Romain Guyfdbf6a72009-06-18 15:13:40 -07001323 + Long.toHexString(mDrawableCache.keyAt(i))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 + " / " + 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 */
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 */
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 */
1372 public Configuration getConfiguration() {
1373 return mConfiguration;
1374 }
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001375
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 */
1383 public CompatibilityInfo getCompatibilityInfo() {
1384 return mCompatibilityInfo;
1385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386
1387 /**
Dianne Hackborna53b8282009-07-17 11:13:48 -07001388 * This is just for testing.
1389 * @hide
1390 */
1391 public void setCompatibilityInfo(CompatibilityInfo ci) {
1392 mCompatibilityInfo = ci;
1393 updateConfiguration(mConfiguration, mMetrics);
1394 }
1395
1396 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 * 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
1645 public final void finishPreloading() {
1646 if (mPreloading) {
1647 mPreloading = false;
1648 flushLayoutCache();
1649 }
1650 }
1651
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
Romain Guyfdbf6a72009-06-18 15:13:40 -07001663 final long key = (((long) value.assetCookie) << 32) | value.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 Drawable dr = getCachedDrawable(key);
1665
1666 if (dr != null) {
1667 return dr;
1668 }
1669
Dianne Hackborn8cae1242009-09-10 14:32:16 -07001670 Drawable.ConstantState cs = sPreloadedDrawables.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 if (cs != null) {
Dianne Hackbornc2974802009-09-13 18:22:19 -07001672 dr = cs.newDrawable(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 } 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(
Dianne Hackborn19382ac2009-09-11 21:13:37 -07001707 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 // System.out.println("Opened file " + file + ": " + is);
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07001709 dr = Drawable.createFromResourceStream(this, value, is,
1710 file, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 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) {
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001729 sPreloadedDrawables.put(key, cs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 } 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
Romain Guyfdbf6a72009-06-18 15:13:40 -07001744 private Drawable getCachedDrawable(long key) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 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);
Dianne Hackbornc2974802009-09-13 18:22:19 -07001753 return entry.newDrawable(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
1755 else { // our entry has been purged
1756 mDrawableCache.delete(key);
1757 }
1758 }
1759 }
1760 return null;
1761 }
1762
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
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
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
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
Mitsuru Oshimaddd12532009-07-14 10:41:13 -07001929 /**
1930 * Returns the display adjusted for the Resources' metrics.
1931 * @hide
1932 */
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 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
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();
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001977 mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 }
1979}