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