blob: 42f4faf550bf8551eba6632549633bbcca473984 [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 Hackborn0acc1932013-04-12 17:49:17 -070019import android.os.Trace;
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -070020import android.view.View;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080021import com.android.internal.util.XmlUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
Dianne Hackbornebff8f92011-05-12 18:07:47 -070026import android.content.pm.ActivityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.graphics.Movie;
28import android.graphics.drawable.Drawable;
29import android.graphics.drawable.ColorDrawable;
Masanori Oginoc7d9d272010-07-10 12:10:41 +090030import android.graphics.drawable.Drawable.ConstantState;
Dianne Hackborn3b3e1452009-09-24 19:22:12 -070031import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.AttributeSet;
34import android.util.DisplayMetrics;
35import android.util.Log;
Dianne Hackborn2f0b1752011-05-31 17:59:49 -070036import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.util.TypedValue;
Romain Guyfdbf6a72009-06-18 15:13:40 -070038import android.util.LongSparseArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40import java.io.IOException;
41import java.io.InputStream;
42import java.lang.ref.WeakReference;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080043import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Elliott Hughes1ad636c2010-07-01 16:51:48 -070045import libcore.icu.NativePluralRules;
46
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047/**
48 * Class for accessing an application's resources. This sits on top of the
Scott Mainf4f05b82011-01-07 14:38:23 -080049 * asset manager of the application (accessible through {@link #getAssets}) and
50 * provides a high-level API for getting typed data from the assets.
51 *
52 * <p>The Android resource system keeps track of all non-code assets associated with an
53 * application. You can use this class to access your application's resources. You can generally
54 * acquire the {@link android.content.res.Resources} instance associated with your application
55 * with {@link android.content.Context#getResources getResources()}.</p>
56 *
57 * <p>The Android SDK tools compile your application's resources into the application binary
58 * at build time. To use a resource, you must install it correctly in the source tree (inside
59 * your project's {@code res/} directory) and build your application. As part of the build
60 * process, the SDK tools generate symbols for each resource, which you can use in your application
61 * code to access the resources.</p>
62 *
63 * <p>Using application resources makes it easy to update various characteristics of your
64 * application without modifying code, and&mdash;by providing sets of alternative
65 * resources&mdash;enables you to optimize your application for a variety of device configurations
66 * (such as for different languages and screen sizes). This is an important aspect of developing
67 * Android applications that are compatible on different types of devices.</p>
68 *
69 * <p>For more information about using resources, see the documentation about <a
70 * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 */
72public class Resources {
73 static final String TAG = "Resources";
74 private static final boolean DEBUG_LOAD = false;
75 private static final boolean DEBUG_CONFIG = false;
Dianne Hackbornab0f4852011-09-12 16:59:06 -070076 private static final boolean DEBUG_ATTRIBUTES_CACHE = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 private static final boolean TRACE_FOR_PRELOAD = false;
Dianne Hackborn9b44aae2011-09-02 19:17:16 -070078 private static final boolean TRACE_FOR_MISS_PRELOAD = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Elliott Hughes1ad636c2010-07-01 16:51:48 -070080 private static final int ID_OTHER = 0x01000004;
81
Dianne Hackborn50707cc2013-02-08 15:32:05 -080082 private static final Object sSync = new Object();
Xavier Ducrohet7f9f99ea2011-08-11 10:16:17 -070083 /*package*/ static Resources mSystem = null;
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -070084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 // Information about preloaded resources. Note that they are not
86 // protected by a lock, because while preloading in zygote we are all
87 // single-threaded, and after that these are immutable.
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -070088 private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
89 private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
Romain Guyfdbf6a72009-06-18 15:13:40 -070090 = new LongSparseArray<Drawable.ConstantState>();
Romain Guy5d911c32012-04-12 16:25:17 -070091 private static final LongSparseArray<ColorStateList> sPreloadedColorStateLists
92 = new LongSparseArray<ColorStateList>();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -070093
Dianne Hackborndde331c2012-08-03 14:01:57 -070094 private static boolean sPreloaded;
95 private static int sPreloadedDensity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
Dianne Hackborn50707cc2013-02-08 15:32:05 -080097 // These are protected by mAccessLock.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
Dianne Hackborn50707cc2013-02-08 15:32:05 -080099 /*package*/ final Object mAccessLock = new Object();
100 /*package*/ final Configuration mTmpConfig = new Configuration();
101 /*package*/ TypedValue mTmpValue = new TypedValue();
102 /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mDrawableCache
Romain Guyfdbf6a72009-06-18 15:13:40 -0700103 = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800104 /*package*/ final LongSparseArray<WeakReference<ColorStateList> > mColorStateListCache
Romain Guy5d911c32012-04-12 16:25:17 -0700105 = new LongSparseArray<WeakReference<ColorStateList> >();
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800106 /*package*/ final LongSparseArray<WeakReference<Drawable.ConstantState> > mColorDrawableCache
Masanori Oginoc7d9d272010-07-10 12:10:41 +0900107 = new LongSparseArray<WeakReference<Drawable.ConstantState> >();
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800108 /*package*/ boolean mPreloading;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
110 /*package*/ TypedArray mCachedStyledAttributes = null;
Dianne Hackbornab0f4852011-09-12 16:59:06 -0700111 RuntimeException mLastRetrievedAttrs = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
113 private int mLastCachedXmlBlockIndex = -1;
114 private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
115 private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
116
117 /*package*/ final AssetManager mAssets;
118 private final Configuration mConfiguration = new Configuration();
119 /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700120 private NativePluralRules mPluralRule;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700121
Dianne Hackborna53b8282009-07-17 11:13:48 -0700122 private CompatibilityInfo mCompatibilityInfo;
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -0700123
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700124 static {
125 sPreloadedDrawables = new LongSparseArray[2];
126 sPreloadedDrawables[0] = new LongSparseArray<Drawable.ConstantState>();
127 sPreloadedDrawables[1] = new LongSparseArray<Drawable.ConstantState>();
128 }
129
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800130 /** @hide */
131 public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
132 return selectSystemTheme(curTheme, targetSdkVersion,
Adam Powell6e90a362011-08-14 16:48:32 -0700133 com.android.internal.R.style.Theme,
134 com.android.internal.R.style.Theme_Holo,
135 com.android.internal.R.style.Theme_DeviceDefault);
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800136 }
137
138 /** @hide */
Adam Powell6e90a362011-08-14 16:48:32 -0700139 public static int selectSystemTheme(int curTheme, int targetSdkVersion,
140 int orig, int holo, int deviceDefault) {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800141 if (curTheme != 0) {
142 return curTheme;
143 }
144 if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
145 return orig;
146 }
Adam Powell6e90a362011-08-14 16:48:32 -0700147 if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
148 return holo;
149 }
150 return deviceDefault;
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800151 }
152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 /**
154 * This exception is thrown by the resource APIs when a requested resource
155 * can not be found.
156 */
157 public static class NotFoundException extends RuntimeException {
158 public NotFoundException() {
159 }
160
161 public NotFoundException(String name) {
162 super(name);
163 }
164 }
165
166 /**
167 * Create a new Resources object on top of an existing set of assets in an
168 * AssetManager.
169 *
170 * @param assets Previously created AssetManager.
171 * @param metrics Current display metrics to consider when
172 * selecting/computing resource values.
173 * @param config Desired device configuration to consider when
174 * selecting/computing resource values (optional).
175 */
Romain Guy5d911c32012-04-12 16:25:17 -0700176 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
177 this(assets, metrics, config, 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();
Dianne Hackborn3904d032011-05-27 12:09:11 -0700196 mCompatibilityInfo = compInfo;
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700197 updateConfiguration(config, metrics);
198 assets.ensureStringBlocks();
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700199 }
200
201 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 * Return a global shared Resources object that provides access to only
203 * system resources (no application resources), and is not configured for
204 * the current screen (can not use dimension units, does not change based
205 * on orientation, etc).
206 */
207 public static Resources getSystem() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800208 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 Resources ret = mSystem;
210 if (ret == null) {
211 ret = new Resources();
212 mSystem = ret;
213 }
214
215 return ret;
216 }
217 }
218
219 /**
220 * Return the string value associated with a particular resource ID. The
221 * returned object will be a String if this is a plain string; it will be
222 * some other type of CharSequence if it is styled.
223 * {@more}
224 *
225 * @param id The desired resource identifier, as generated by the aapt
226 * tool. This integer encodes the package, type, and resource
227 * entry. The value 0 is an invalid identifier.
228 *
229 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
230 *
231 * @return CharSequence The string data associated with the resource, plus
232 * possibly styled text information.
233 */
234 public CharSequence getText(int id) throws NotFoundException {
235 CharSequence res = mAssets.getResourceText(id);
236 if (res != null) {
237 return res;
238 }
239 throw new NotFoundException("String resource ID #0x"
240 + Integer.toHexString(id));
241 }
242
243 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800244 * Returns the character sequence necessary for grammatically correct pluralization
245 * of the given resource ID for the given quantity.
246 * Note that the character sequence is selected based solely on grammatical necessity,
247 * and that such rules differ between languages. Do not assume you know which string
248 * will be returned for a given quantity. See
249 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
250 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700251 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 * @param id The desired resource identifier, as generated by the aapt
253 * tool. This integer encodes the package, type, and resource
254 * entry. The value 0 is an invalid identifier.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700255 * @param quantity The number used to get the correct string for the current language's
256 * plural rules.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 *
258 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
259 *
260 * @return CharSequence The string data associated with the resource, plus
261 * possibly styled text information.
262 */
263 public CharSequence getQuantityText(int id, int quantity) throws NotFoundException {
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700264 NativePluralRules rule = getPluralRule();
265 CharSequence res = mAssets.getResourceBagText(id,
266 attrForQuantityCode(rule.quantityForInt(quantity)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 if (res != null) {
268 return res;
269 }
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700270 res = mAssets.getResourceBagText(id, ID_OTHER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 if (res != null) {
272 return res;
273 }
274 throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
275 + " quantity=" + quantity
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700276 + " item=" + stringForQuantityCode(rule.quantityForInt(quantity)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 }
278
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700279 private NativePluralRules getPluralRule() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800280 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 if (mPluralRule == null) {
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700282 mPluralRule = NativePluralRules.forLocale(mConfiguration.locale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 }
284 return mPluralRule;
285 }
286 }
287
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700288 private static int attrForQuantityCode(int quantityCode) {
289 switch (quantityCode) {
290 case NativePluralRules.ZERO: return 0x01000005;
291 case NativePluralRules.ONE: return 0x01000006;
292 case NativePluralRules.TWO: return 0x01000007;
293 case NativePluralRules.FEW: return 0x01000008;
294 case NativePluralRules.MANY: return 0x01000009;
295 default: return ID_OTHER;
296 }
297 }
298
299 private static String stringForQuantityCode(int quantityCode) {
300 switch (quantityCode) {
301 case NativePluralRules.ZERO: return "zero";
302 case NativePluralRules.ONE: return "one";
303 case NativePluralRules.TWO: return "two";
304 case NativePluralRules.FEW: return "few";
305 case NativePluralRules.MANY: return "many";
306 default: return "other";
307 }
308 }
309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 /**
311 * Return the string value associated with a particular resource ID. It
312 * will be stripped of any styled text information.
313 * {@more}
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 *
319 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
320 *
321 * @return String The string data associated with the resource,
322 * stripped of styled text information.
323 */
324 public String getString(int id) throws NotFoundException {
325 CharSequence res = getText(id);
326 if (res != null) {
327 return res.toString();
328 }
329 throw new NotFoundException("String resource ID #0x"
330 + Integer.toHexString(id));
331 }
332
333
334 /**
335 * Return the string value associated with a particular resource ID,
336 * substituting the format arguments as defined in {@link java.util.Formatter}
337 * and {@link java.lang.String#format}. It will be stripped of any styled text
338 * information.
339 * {@more}
340 *
341 * @param id The desired resource identifier, as generated by the aapt
342 * tool. This integer encodes the package, type, and resource
343 * entry. The value 0 is an invalid identifier.
344 *
345 * @param formatArgs The format arguments that will be used for substitution.
346 *
347 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
348 *
349 * @return String The string data associated with the resource,
350 * stripped of styled text information.
351 */
352 public String getString(int id, Object... formatArgs) throws NotFoundException {
353 String raw = getString(id);
354 return String.format(mConfiguration.locale, raw, formatArgs);
355 }
356
357 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800358 * Formats the string necessary for grammatically correct pluralization
359 * of the given resource ID for the given quantity, using the given arguments.
360 * Note that the string is selected based solely on grammatical necessity,
361 * and that such rules differ between languages. Do not assume you know which string
362 * will be returned for a given quantity. See
363 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
364 * for more detail.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 *
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800366 * <p>Substitution of format arguments works as if using
367 * {@link java.util.Formatter} and {@link java.lang.String#format}.
368 * The resulting string will be stripped of any styled text information.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700369 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 * @param id The desired resource identifier, as generated by the aapt
371 * tool. This integer encodes the package, type, and resource
372 * entry. The value 0 is an invalid identifier.
373 * @param quantity The number used to get the correct string for the current language's
374 * plural rules.
375 * @param formatArgs The format arguments that will be used for substitution.
376 *
377 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
378 *
379 * @return String The string data associated with the resource,
380 * stripped of styled text information.
381 */
382 public String getQuantityString(int id, int quantity, Object... formatArgs)
383 throws NotFoundException {
384 String raw = getQuantityText(id, quantity).toString();
385 return String.format(mConfiguration.locale, raw, formatArgs);
386 }
387
388 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800389 * Returns the string necessary for grammatically correct pluralization
390 * of the given resource ID for the given quantity.
391 * Note that the string is selected based solely on grammatical necessity,
392 * and that such rules differ between languages. Do not assume you know which string
393 * will be returned for a given quantity. See
394 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
395 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700396 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * @param id The desired resource identifier, as generated by the aapt
398 * tool. This integer encodes the package, type, and resource
399 * entry. The value 0 is an invalid identifier.
400 * @param quantity The number used to get the correct string for the current language's
401 * plural rules.
402 *
403 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
404 *
405 * @return String The string data associated with the resource,
406 * stripped of styled text information.
407 */
408 public String getQuantityString(int id, int quantity) throws NotFoundException {
409 return getQuantityText(id, quantity).toString();
410 }
411
412 /**
413 * Return the string value associated with a particular resource ID. The
414 * returned object will be a String if this is a plain string; it will be
415 * some other type of CharSequence if it is styled.
416 *
417 * @param id The desired resource identifier, as generated by the aapt
418 * tool. This integer encodes the package, type, and resource
419 * entry. The value 0 is an invalid identifier.
420 *
421 * @param def The default CharSequence to return.
422 *
423 * @return CharSequence The string data associated with the resource, plus
424 * possibly styled text information, or def if id is 0 or not found.
425 */
426 public CharSequence getText(int id, CharSequence def) {
427 CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
428 return res != null ? res : def;
429 }
430
431 /**
432 * Return the styled text array associated with a particular resource ID.
433 *
434 * @param id The desired resource identifier, as generated by the aapt
435 * tool. This integer encodes the package, type, and resource
436 * entry. The value 0 is an invalid identifier.
437 *
438 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
439 *
440 * @return The styled text array associated with the resource.
441 */
442 public CharSequence[] getTextArray(int id) throws NotFoundException {
443 CharSequence[] res = mAssets.getResourceTextArray(id);
444 if (res != null) {
445 return res;
446 }
447 throw new NotFoundException("Text array resource ID #0x"
448 + Integer.toHexString(id));
449 }
450
451 /**
452 * Return the string array associated with a particular resource ID.
453 *
454 * @param id The desired resource identifier, as generated by the aapt
455 * tool. This integer encodes the package, type, and resource
456 * entry. The value 0 is an invalid identifier.
457 *
458 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
459 *
460 * @return The string array associated with the resource.
461 */
462 public String[] getStringArray(int id) throws NotFoundException {
463 String[] res = mAssets.getResourceStringArray(id);
464 if (res != null) {
465 return res;
466 }
467 throw new NotFoundException("String array resource ID #0x"
468 + Integer.toHexString(id));
469 }
470
471 /**
472 * Return the int array associated with a particular resource ID.
473 *
474 * @param id The desired resource identifier, as generated by the aapt
475 * tool. This integer encodes the package, type, and resource
476 * entry. The value 0 is an invalid identifier.
477 *
478 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
479 *
480 * @return The int array associated with the resource.
481 */
482 public int[] getIntArray(int id) throws NotFoundException {
483 int[] res = mAssets.getArrayIntResource(id);
484 if (res != null) {
485 return res;
486 }
487 throw new NotFoundException("Int array resource ID #0x"
488 + Integer.toHexString(id));
489 }
490
491 /**
492 * Return an array of heterogeneous values.
493 *
494 * @param id The desired resource identifier, as generated by the aapt
495 * tool. This integer encodes the package, type, and resource
496 * entry. The value 0 is an invalid identifier.
497 *
498 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
499 *
500 * @return Returns a TypedArray holding an array of the array values.
501 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
502 * when done with it.
503 */
504 public TypedArray obtainTypedArray(int id) throws NotFoundException {
505 int len = mAssets.getArraySize(id);
506 if (len < 0) {
507 throw new NotFoundException("Array resource ID #0x"
508 + Integer.toHexString(id));
509 }
510
511 TypedArray array = getCachedStyledAttributes(len);
512 array.mLength = mAssets.retrieveArray(id, array.mData);
513 array.mIndices[0] = 0;
514
515 return array;
516 }
517
518 /**
519 * Retrieve a dimensional for a particular resource ID. Unit
520 * conversions are based on the current {@link DisplayMetrics} associated
521 * with the resources.
522 *
523 * @param id The desired resource identifier, as generated by the aapt
524 * tool. This integer encodes the package, type, and resource
525 * entry. The value 0 is an invalid identifier.
526 *
527 * @return Resource dimension value multiplied by the appropriate
528 * metric.
529 *
530 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
531 *
532 * @see #getDimensionPixelOffset
533 * @see #getDimensionPixelSize
534 */
535 public float getDimension(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800536 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800538 if (value == null) {
539 mTmpValue = value = new TypedValue();
540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 getValue(id, value, true);
542 if (value.type == TypedValue.TYPE_DIMENSION) {
543 return TypedValue.complexToDimension(value.data, mMetrics);
544 }
545 throw new NotFoundException(
546 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
547 + Integer.toHexString(value.type) + " is not valid");
548 }
549 }
550
551 /**
552 * Retrieve a dimensional for a particular resource ID for use
553 * as an offset in raw pixels. This is the same as
554 * {@link #getDimension}, except the returned value is converted to
555 * integer pixels for you. An offset conversion involves simply
556 * truncating the base value to an integer.
557 *
558 * @param id The desired resource identifier, as generated by the aapt
559 * tool. This integer encodes the package, type, and resource
560 * entry. The value 0 is an invalid identifier.
561 *
562 * @return Resource dimension value multiplied by the appropriate
563 * metric and truncated to integer pixels.
564 *
565 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
566 *
567 * @see #getDimension
568 * @see #getDimensionPixelSize
569 */
570 public int getDimensionPixelOffset(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800571 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800573 if (value == null) {
574 mTmpValue = value = new TypedValue();
575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 getValue(id, value, true);
577 if (value.type == TypedValue.TYPE_DIMENSION) {
578 return TypedValue.complexToDimensionPixelOffset(
579 value.data, mMetrics);
580 }
581 throw new NotFoundException(
582 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
583 + Integer.toHexString(value.type) + " is not valid");
584 }
585 }
586
587 /**
588 * Retrieve a dimensional for a particular resource ID for use
589 * as a size in raw pixels. This is the same as
590 * {@link #getDimension}, except the returned value is converted to
591 * integer pixels for use as a size. A size conversion involves
592 * rounding the base value, and ensuring that a non-zero base value
593 * is at least one pixel in size.
594 *
595 * @param id The desired resource identifier, as generated by the aapt
596 * tool. This integer encodes the package, type, and resource
597 * entry. The value 0 is an invalid identifier.
598 *
599 * @return Resource dimension value multiplied by the appropriate
600 * metric and truncated to integer pixels.
601 *
602 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
603 *
604 * @see #getDimension
605 * @see #getDimensionPixelOffset
606 */
607 public int getDimensionPixelSize(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800608 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800610 if (value == null) {
611 mTmpValue = value = new TypedValue();
612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 getValue(id, value, true);
614 if (value.type == TypedValue.TYPE_DIMENSION) {
615 return TypedValue.complexToDimensionPixelSize(
616 value.data, mMetrics);
617 }
618 throw new NotFoundException(
619 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
620 + Integer.toHexString(value.type) + " is not valid");
621 }
622 }
623
624 /**
625 * Retrieve a fractional unit for a particular resource ID.
626 *
627 * @param id The desired resource identifier, as generated by the aapt
628 * tool. This integer encodes the package, type, and resource
629 * entry. The value 0 is an invalid identifier.
630 * @param base The base value of this fraction. In other words, a
631 * standard fraction is multiplied by this value.
632 * @param pbase The parent base value of this fraction. In other
633 * words, a parent fraction (nn%p) is multiplied by this
634 * value.
635 *
636 * @return Attribute fractional value multiplied by the appropriate
637 * base value.
638 *
639 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
640 */
641 public float getFraction(int id, int base, int pbase) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800642 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800644 if (value == null) {
645 mTmpValue = value = new TypedValue();
646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 getValue(id, value, true);
648 if (value.type == TypedValue.TYPE_FRACTION) {
649 return TypedValue.complexToFraction(value.data, base, pbase);
650 }
651 throw new NotFoundException(
652 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
653 + Integer.toHexString(value.type) + " is not valid");
654 }
655 }
656
657 /**
658 * Return a drawable object associated with a particular resource ID.
659 * Various types of objects will be returned depending on the underlying
660 * resource -- for example, a solid color, PNG image, scalable image, etc.
661 * The Drawable API hides these implementation details.
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700662 *
663 * <p class="note"><strong>Note:</strong> Prior to
664 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function
665 * would not correctly retrieve the final configuration density when
666 * the resource ID passed here is an alias to another Drawable resource.
667 * This means that if the density configuration of the alias resource
668 * is different than the actual resource, the density of the returned
669 * Drawable would be incorrect, resulting in bad scaling. To work
670 * around this, you can instead retrieve the Drawable through
671 * {@link TypedArray#getDrawable TypedArray.getDrawable}. Use
672 * {@link android.content.Context#obtainStyledAttributes(int[])
673 * Context.obtainStyledAttributes} with
674 * an array containing the resource ID of interest to create the TypedArray.</p>
675 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 * @param id The desired resource identifier, as generated by the aapt
677 * tool. This integer encodes the package, type, and resource
678 * entry. The value 0 is an invalid identifier.
679 *
680 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
681 *
682 * @return Drawable An object that can be used to draw this resource.
683 */
684 public Drawable getDrawable(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800685 TypedValue value;
686 synchronized (mAccessLock) {
687 value = mTmpValue;
688 if (value == null) {
689 value = new TypedValue();
690 } else {
691 mTmpValue = null;
692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 getValue(id, value, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800695 Drawable res = loadDrawable(value, id);
696 synchronized (mAccessLock) {
697 if (mTmpValue == null) {
698 mTmpValue = value;
699 }
700 }
701 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
703
704 /**
Kenny Root55fc8502010-10-28 14:47:01 -0700705 * Return a drawable object associated with a particular resource ID for the
706 * given screen density in DPI. This will set the drawable's density to be
707 * the device's density multiplied by the ratio of actual drawable density
708 * to requested density. This allows the drawable to be scaled up to the
709 * correct size if needed. Various types of objects will be returned
710 * depending on the underlying resource -- for example, a solid color, PNG
711 * image, scalable image, etc. The Drawable API hides these implementation
712 * details.
713 *
714 * @param id The desired resource identifier, as generated by the aapt tool.
715 * This integer encodes the package, type, and resource entry.
716 * The value 0 is an invalid identifier.
717 * @param density the desired screen density indicated by the resource as
718 * found in {@link DisplayMetrics}.
719 * @throws NotFoundException Throws NotFoundException if the given ID does
720 * not exist.
721 * @return Drawable An object that can be used to draw this resource.
Kenny Root55fc8502010-10-28 14:47:01 -0700722 */
723 public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800724 TypedValue value;
725 synchronized (mAccessLock) {
726 value = mTmpValue;
727 if (value == null) {
728 value = new TypedValue();
729 } else {
730 mTmpValue = null;
731 }
Kenny Root55fc8502010-10-28 14:47:01 -0700732 getValueForDensity(id, density, value, true);
733
734 /*
735 * Pretend the requested density is actually the display density. If
736 * the drawable returned is not the requested density, then force it
737 * to be scaled later by dividing its density by the ratio of
738 * requested density to actual device density. Drawables that have
739 * undefined density or no density don't need to be handled here.
740 */
741 if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
742 if (value.density == density) {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700743 value.density = mMetrics.densityDpi;
Kenny Root55fc8502010-10-28 14:47:01 -0700744 } else {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700745 value.density = (value.density * mMetrics.densityDpi) / density;
Kenny Root55fc8502010-10-28 14:47:01 -0700746 }
747 }
Kenny Root55fc8502010-10-28 14:47:01 -0700748 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800749
750 Drawable res = loadDrawable(value, id);
751 synchronized (mAccessLock) {
752 if (mTmpValue == null) {
753 mTmpValue = value;
754 }
755 }
756 return res;
Kenny Root55fc8502010-10-28 14:47:01 -0700757 }
758
759 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 * Return a movie object associated with the particular resource ID.
761 * @param id The desired resource identifier, as generated by the aapt
762 * tool. This integer encodes the package, type, and resource
763 * entry. The value 0 is an invalid identifier.
764 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
765 *
766 */
767 public Movie getMovie(int id) throws NotFoundException {
768 InputStream is = openRawResource(id);
769 Movie movie = Movie.decodeStream(is);
770 try {
771 is.close();
772 }
773 catch (java.io.IOException e) {
774 // don't care, since the return value is valid
775 }
776 return movie;
777 }
778
779 /**
780 * Return a color integer associated with a particular resource ID.
781 * If the resource holds a complex
782 * {@link android.content.res.ColorStateList}, then the default color from
783 * the set is returned.
784 *
785 * @param id The desired resource identifier, as generated by the aapt
786 * tool. This integer encodes the package, type, and resource
787 * entry. The value 0 is an invalid identifier.
788 *
789 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
790 *
791 * @return Returns a single color value in the form 0xAARRGGBB.
792 */
793 public int getColor(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800794 TypedValue value;
795 synchronized (mAccessLock) {
796 value = mTmpValue;
797 if (value == null) {
798 value = new TypedValue();
799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 getValue(id, value, true);
801 if (value.type >= TypedValue.TYPE_FIRST_INT
802 && value.type <= TypedValue.TYPE_LAST_INT) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800803 mTmpValue = value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 return value.data;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800805 } else if (value.type != TypedValue.TYPE_STRING) {
806 throw new NotFoundException(
807 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
808 + Integer.toHexString(value.type) + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800810 mTmpValue = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800812 ColorStateList csl = loadColorStateList(value, id);
813 synchronized (mAccessLock) {
814 if (mTmpValue == null) {
815 mTmpValue = value;
816 }
817 }
818 return csl.getDefaultColor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 }
820
821 /**
822 * Return a color state list associated with a particular resource ID. The
823 * resource may contain either a single raw color value, or a complex
824 * {@link android.content.res.ColorStateList} holding multiple possible colors.
825 *
826 * @param id The desired resource identifier of a {@link ColorStateList},
827 * as generated by the aapt tool. This integer encodes the package, type, and resource
828 * entry. The value 0 is an invalid identifier.
829 *
830 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
831 *
832 * @return Returns a ColorStateList object containing either a single
833 * solid color or multiple colors that can be selected based on a state.
834 */
835 public ColorStateList getColorStateList(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800836 TypedValue value;
837 synchronized (mAccessLock) {
838 value = mTmpValue;
839 if (value == null) {
840 value = new TypedValue();
841 } else {
842 mTmpValue = null;
843 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 getValue(id, value, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800846 ColorStateList res = loadColorStateList(value, id);
847 synchronized (mAccessLock) {
848 if (mTmpValue == null) {
849 mTmpValue = value;
850 }
851 }
852 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854
855 /**
856 * Return a boolean associated with a particular resource ID. This can be
857 * used with any integral resource value, and will return true if it is
858 * non-zero.
859 *
860 * @param id The desired resource identifier, as generated by the aapt
861 * tool. This integer encodes the package, type, and resource
862 * entry. The value 0 is an invalid identifier.
863 *
864 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
865 *
866 * @return Returns the boolean value contained in the resource.
867 */
868 public boolean getBoolean(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800869 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800871 if (value == null) {
872 mTmpValue = value = new TypedValue();
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 getValue(id, value, true);
875 if (value.type >= TypedValue.TYPE_FIRST_INT
876 && value.type <= TypedValue.TYPE_LAST_INT) {
877 return value.data != 0;
878 }
879 throw new NotFoundException(
880 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
881 + Integer.toHexString(value.type) + " is not valid");
882 }
883 }
884
885 /**
886 * Return an integer associated with a particular resource ID.
887 *
888 * @param id The desired resource identifier, as generated by the aapt
889 * tool. This integer encodes the package, type, and resource
890 * entry. The value 0 is an invalid identifier.
891 *
892 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
893 *
894 * @return Returns the integer value contained in the resource.
895 */
896 public int getInteger(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800897 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800899 if (value == null) {
900 mTmpValue = value = new TypedValue();
901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 getValue(id, value, true);
903 if (value.type >= TypedValue.TYPE_FIRST_INT
904 && value.type <= TypedValue.TYPE_LAST_INT) {
905 return value.data;
906 }
907 throw new NotFoundException(
908 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
909 + Integer.toHexString(value.type) + " is not valid");
910 }
911 }
912
913 /**
914 * Return an XmlResourceParser through which you can read a view layout
915 * description for the given resource ID. This parser has limited
916 * functionality -- in particular, you can't change its input, and only
917 * the high-level events are available.
918 *
919 * <p>This function is really a simple wrapper for calling
920 * {@link #getXml} with a layout resource.
921 *
922 * @param id The desired resource identifier, as generated by the aapt
923 * tool. This integer encodes the package, type, and resource
924 * entry. The value 0 is an invalid identifier.
925 *
926 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
927 *
928 * @return A new parser object through which you can read
929 * the XML data.
930 *
931 * @see #getXml
932 */
933 public XmlResourceParser getLayout(int id) throws NotFoundException {
934 return loadXmlResourceParser(id, "layout");
935 }
936
937 /**
938 * Return an XmlResourceParser through which you can read an animation
939 * description for the given resource ID. This parser has limited
940 * functionality -- in particular, you can't change its input, and only
941 * the high-level events are available.
942 *
943 * <p>This function is really a simple wrapper for calling
944 * {@link #getXml} with an animation resource.
945 *
946 * @param id The desired resource identifier, as generated by the aapt
947 * tool. This integer encodes the package, type, and resource
948 * entry. The value 0 is an invalid identifier.
949 *
950 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
951 *
952 * @return A new parser object through which you can read
953 * the XML data.
954 *
955 * @see #getXml
956 */
957 public XmlResourceParser getAnimation(int id) throws NotFoundException {
958 return loadXmlResourceParser(id, "anim");
959 }
960
961 /**
962 * Return an XmlResourceParser through which you can read a generic XML
963 * resource for the given resource ID.
964 *
965 * <p>The XmlPullParser implementation returned here has some limited
966 * functionality. In particular, you can't change its input, and only
967 * high-level parsing events are available (since the document was
968 * pre-parsed for you at build time, which involved merging text and
969 * stripping comments).
970 *
971 * @param id The desired resource identifier, as generated by the aapt
972 * tool. This integer encodes the package, type, and resource
973 * entry. The value 0 is an invalid identifier.
974 *
975 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
976 *
977 * @return A new parser object through which you can read
978 * the XML data.
979 *
980 * @see android.util.AttributeSet
981 */
982 public XmlResourceParser getXml(int id) throws NotFoundException {
983 return loadXmlResourceParser(id, "xml");
984 }
985
986 /**
987 * Open a data stream for reading a raw resource. This can only be used
988 * with resources whose value is the name of an asset files -- that is, it can be
989 * used to open drawable, sound, and raw resources; it will fail on string
990 * and color resources.
991 *
992 * @param id The resource identifier to open, as generated by the appt
993 * tool.
994 *
995 * @return InputStream Access to the resource data.
996 *
997 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
998 *
999 */
1000 public InputStream openRawResource(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001001 TypedValue value;
1002 synchronized (mAccessLock) {
1003 value = mTmpValue;
1004 if (value == null) {
1005 value = new TypedValue();
1006 } else {
1007 mTmpValue = null;
1008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001010 InputStream res = openRawResource(id, value);
1011 synchronized (mAccessLock) {
1012 if (mTmpValue == null) {
1013 mTmpValue = value;
1014 }
1015 }
1016 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
1018
1019 /**
1020 * Open a data stream for reading a raw resource. This can only be used
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001021 * 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 -08001022 * used to open drawable, sound, and raw resources; it will fail on string
1023 * and color resources.
1024 *
1025 * @param id The resource identifier to open, as generated by the appt tool.
1026 * @param value The TypedValue object to hold the resource information.
1027 *
1028 * @return InputStream Access to the resource data.
1029 *
1030 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 */
1032 public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
1033 getValue(id, value, true);
1034
1035 try {
1036 return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
1037 AssetManager.ACCESS_STREAMING);
1038 } catch (Exception e) {
1039 NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
1040 " from drawable resource ID #0x" + Integer.toHexString(id));
1041 rnf.initCause(e);
1042 throw rnf;
1043 }
1044 }
1045
1046 /**
1047 * Open a file descriptor for reading a raw resource. This can only be used
1048 * with resources whose value is the name of an asset files -- that is, it can be
1049 * used to open drawable, sound, and raw resources; it will fail on string
1050 * and color resources.
1051 *
1052 * <p>This function only works for resources that are stored in the package
1053 * as uncompressed data, which typically includes things like mp3 files
1054 * and png images.
1055 *
1056 * @param id The resource identifier to open, as generated by the appt
1057 * tool.
1058 *
1059 * @return AssetFileDescriptor A new file descriptor you can use to read
1060 * the resource. This includes the file descriptor itself, as well as the
1061 * offset and length of data where the resource appears in the file. A
1062 * null is returned if the file exists but is compressed.
1063 *
1064 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1065 *
1066 */
1067 public AssetFileDescriptor openRawResourceFd(int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001068 TypedValue value;
1069 synchronized (mAccessLock) {
1070 value = mTmpValue;
1071 if (value == null) {
1072 value = new TypedValue();
1073 } else {
1074 mTmpValue = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001076 getValue(id, value, true);
1077 }
1078 try {
1079 return mAssets.openNonAssetFd(
1080 value.assetCookie, value.string.toString());
1081 } catch (Exception e) {
1082 NotFoundException rnf = new NotFoundException(
1083 "File " + value.string.toString()
1084 + " from drawable resource ID #0x"
1085 + Integer.toHexString(id));
1086 rnf.initCause(e);
1087 throw rnf;
1088 } finally {
1089 synchronized (mAccessLock) {
1090 if (mTmpValue == null) {
1091 mTmpValue = value;
1092 }
1093 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 }
1095 }
1096
1097 /**
1098 * Return the raw data associated with a particular resource ID.
1099 *
1100 * @param id The desired resource identifier, as generated by the aapt
1101 * tool. This integer encodes the package, type, and resource
1102 * entry. The value 0 is an invalid identifier.
1103 * @param outValue Object in which to place the resource data.
1104 * @param resolveRefs If true, a resource that is a reference to another
1105 * resource will be followed so that you receive the
1106 * actual final resource data. If false, the TypedValue
1107 * will be filled in with the reference itself.
1108 *
1109 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1110 *
1111 */
1112 public void getValue(int id, TypedValue outValue, boolean resolveRefs)
1113 throws NotFoundException {
Kenny Root55fc8502010-10-28 14:47:01 -07001114 boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 if (found) {
1116 return;
1117 }
1118 throw new NotFoundException("Resource ID #0x"
1119 + Integer.toHexString(id));
1120 }
1121
1122 /**
Kenny Root55fc8502010-10-28 14:47:01 -07001123 * Get the raw value associated with a resource with associated density.
1124 *
1125 * @param id resource identifier
1126 * @param density density in DPI
1127 * @param resolveRefs If true, a resource that is a reference to another
1128 * resource will be followed so that you receive the actual final
1129 * resource data. If false, the TypedValue will be filled in with
1130 * the reference itself.
1131 * @throws NotFoundException Throws NotFoundException if the given ID does
1132 * not exist.
1133 * @see #getValue(String, TypedValue, boolean)
Kenny Root55fc8502010-10-28 14:47:01 -07001134 */
1135 public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs)
1136 throws NotFoundException {
1137 boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
1138 if (found) {
1139 return;
1140 }
1141 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
1142 }
1143
1144 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 * Return the raw data associated with a particular resource ID.
1146 * See getIdentifier() for information on how names are mapped to resource
1147 * IDs, and getString(int) for information on how string resources are
1148 * retrieved.
1149 *
1150 * <p>Note: use of this function is discouraged. It is much more
1151 * efficient to retrieve resources by identifier than by name.
1152 *
1153 * @param name The name of the desired resource. This is passed to
1154 * getIdentifier() with a default type of "string".
1155 * @param outValue Object in which to place the resource data.
1156 * @param resolveRefs If true, a resource that is a reference to another
1157 * resource will be followed so that you receive the
1158 * actual final resource data. If false, the TypedValue
1159 * will be filled in with the reference itself.
1160 *
1161 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1162 *
1163 */
1164 public void getValue(String name, TypedValue outValue, boolean resolveRefs)
1165 throws NotFoundException {
1166 int id = getIdentifier(name, "string", null);
1167 if (id != 0) {
1168 getValue(id, outValue, resolveRefs);
1169 return;
1170 }
1171 throw new NotFoundException("String resource name " + name);
1172 }
1173
1174 /**
1175 * This class holds the current attribute values for a particular theme.
1176 * In other words, a Theme is a set of values for resource attributes;
1177 * these are used in conjunction with {@link TypedArray}
1178 * to resolve the final value for an attribute.
1179 *
1180 * <p>The Theme's attributes come into play in two ways: (1) a styled
1181 * attribute can explicit reference a value in the theme through the
1182 * "?themeAttribute" syntax; (2) if no value has been defined for a
1183 * particular styled attribute, as a last resort we will try to find that
1184 * attribute's value in the Theme.
1185 *
1186 * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
1187 * retrieve XML attributes with style and theme information applied.
1188 */
1189 public final class Theme {
1190 /**
1191 * Place new attribute values into the theme. The style resource
1192 * specified by <var>resid</var> will be retrieved from this Theme's
1193 * resources, its values placed into the Theme object.
1194 *
1195 * <p>The semantics of this function depends on the <var>force</var>
1196 * argument: If false, only values that are not already defined in
1197 * the theme will be copied from the system resource; otherwise, if
1198 * any of the style's attributes are already defined in the theme, the
1199 * current values in the theme will be overwritten.
1200 *
1201 * @param resid The resource ID of a style resource from which to
1202 * obtain attribute values.
1203 * @param force If true, values in the style resource will always be
1204 * used in the theme; otherwise, they will only be used
1205 * if not already defined in the theme.
1206 */
1207 public void applyStyle(int resid, boolean force) {
1208 AssetManager.applyThemeStyle(mTheme, resid, force);
1209 }
1210
1211 /**
1212 * Set this theme to hold the same contents as the theme
1213 * <var>other</var>. If both of these themes are from the same
1214 * Resources object, they will be identical after this function
1215 * returns. If they are from different Resources, only the resources
1216 * they have in common will be set in this theme.
1217 *
1218 * @param other The existing Theme to copy from.
1219 */
1220 public void setTo(Theme other) {
1221 AssetManager.copyTheme(mTheme, other.mTheme);
1222 }
1223
1224 /**
John Spurlock330dd532012-12-18 12:03:11 -05001225 * Return a TypedArray holding the values defined by
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 * <var>Theme</var> which are listed in <var>attrs</var>.
1227 *
Scott Main183bf112012-08-13 19:12:13 -07001228 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1229 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 *
1231 * @param attrs The desired attributes.
1232 *
1233 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1234 *
1235 * @return Returns a TypedArray holding an array of the attribute values.
1236 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1237 * when done with it.
1238 *
1239 * @see Resources#obtainAttributes
1240 * @see #obtainStyledAttributes(int, int[])
1241 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1242 */
1243 public TypedArray obtainStyledAttributes(int[] attrs) {
1244 int len = attrs.length;
1245 TypedArray array = getCachedStyledAttributes(len);
1246 array.mRsrcs = attrs;
1247 AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
1248 array.mData, array.mIndices);
1249 return array;
1250 }
1251
1252 /**
John Spurlock330dd532012-12-18 12:03:11 -05001253 * Return a TypedArray holding the values defined by the style
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001254 * resource <var>resid</var> which are listed in <var>attrs</var>.
1255 *
Scott Main183bf112012-08-13 19:12:13 -07001256 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1257 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 *
1259 * @param resid The desired style resource.
1260 * @param attrs The desired attributes in the style.
1261 *
1262 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1263 *
1264 * @return Returns a TypedArray holding an array of the attribute values.
1265 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1266 * when done with it.
1267 *
1268 * @see Resources#obtainAttributes
1269 * @see #obtainStyledAttributes(int[])
1270 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1271 */
1272 public TypedArray obtainStyledAttributes(int resid, int[] attrs)
1273 throws NotFoundException {
1274 int len = attrs.length;
1275 TypedArray array = getCachedStyledAttributes(len);
1276 array.mRsrcs = attrs;
1277
1278 AssetManager.applyStyle(mTheme, 0, resid, 0, attrs,
1279 array.mData, array.mIndices);
1280 if (false) {
1281 int[] data = array.mData;
1282
1283 System.out.println("**********************************************************");
1284 System.out.println("**********************************************************");
1285 System.out.println("**********************************************************");
1286 System.out.println("Attributes:");
1287 String s = " Attrs:";
1288 int i;
1289 for (i=0; i<attrs.length; i++) {
1290 s = s + " 0x" + Integer.toHexString(attrs[i]);
1291 }
1292 System.out.println(s);
1293 s = " Found:";
1294 TypedValue value = new TypedValue();
1295 for (i=0; i<attrs.length; i++) {
1296 int d = i*AssetManager.STYLE_NUM_ENTRIES;
1297 value.type = data[d+AssetManager.STYLE_TYPE];
1298 value.data = data[d+AssetManager.STYLE_DATA];
1299 value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1300 value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1301 s = s + " 0x" + Integer.toHexString(attrs[i])
1302 + "=" + value;
1303 }
1304 System.out.println(s);
1305 }
1306 return array;
1307 }
1308
1309 /**
John Spurlock330dd532012-12-18 12:03:11 -05001310 * Return a TypedArray holding the attribute values in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 * <var>set</var>
1312 * that are listed in <var>attrs</var>. In addition, if the given
1313 * AttributeSet specifies a style class (through the "style" attribute),
1314 * that style will be applied on top of the base attributes it defines.
1315 *
Scott Main183bf112012-08-13 19:12:13 -07001316 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1317 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 *
1319 * <p>When determining the final value of a particular attribute, there
1320 * are four inputs that come into play:</p>
1321 *
1322 * <ol>
1323 * <li> Any attribute values in the given AttributeSet.
1324 * <li> The style resource specified in the AttributeSet (named
1325 * "style").
1326 * <li> The default style specified by <var>defStyleAttr</var> and
1327 * <var>defStyleRes</var>
1328 * <li> The base values in this theme.
1329 * </ol>
1330 *
1331 * <p>Each of these inputs is considered in-order, with the first listed
1332 * taking precedence over the following ones. In other words, if in the
1333 * AttributeSet you have supplied <code>&lt;Button
1334 * textColor="#ff000000"&gt;</code>, then the button's text will
1335 * <em>always</em> be black, regardless of what is specified in any of
1336 * the styles.
1337 *
1338 * @param set The base set of attribute values. May be null.
1339 * @param attrs The desired attributes to be retrieved.
1340 * @param defStyleAttr An attribute in the current theme that contains a
1341 * reference to a style resource that supplies
John Spurlock330dd532012-12-18 12:03:11 -05001342 * defaults values for the TypedArray. Can be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 * 0 to not look for defaults.
1344 * @param defStyleRes A resource identifier of a style resource that
John Spurlock330dd532012-12-18 12:03:11 -05001345 * supplies default values for the TypedArray,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 * used only if defStyleAttr is 0 or can not be found
1347 * in the theme. Can be 0 to not look for defaults.
1348 *
1349 * @return Returns a TypedArray holding an array of the attribute values.
1350 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1351 * when done with it.
1352 *
1353 * @see Resources#obtainAttributes
1354 * @see #obtainStyledAttributes(int[])
1355 * @see #obtainStyledAttributes(int, int[])
1356 */
1357 public TypedArray obtainStyledAttributes(AttributeSet set,
1358 int[] attrs, int defStyleAttr, int defStyleRes) {
1359 int len = attrs.length;
1360 TypedArray array = getCachedStyledAttributes(len);
1361
1362 // XXX note that for now we only work with compiled XML files.
1363 // To support generic XML files we will need to manually parse
1364 // out the attributes from the XML file (applying type information
1365 // contained in the resources and such).
1366 XmlBlock.Parser parser = (XmlBlock.Parser)set;
1367 AssetManager.applyStyle(
1368 mTheme, defStyleAttr, defStyleRes,
1369 parser != null ? parser.mParseState : 0, attrs,
1370 array.mData, array.mIndices);
1371
1372 array.mRsrcs = attrs;
1373 array.mXml = parser;
1374
1375 if (false) {
1376 int[] data = array.mData;
1377
1378 System.out.println("Attributes:");
1379 String s = " Attrs:";
1380 int i;
1381 for (i=0; i<set.getAttributeCount(); i++) {
1382 s = s + " " + set.getAttributeName(i);
1383 int id = set.getAttributeNameResource(i);
1384 if (id != 0) {
1385 s = s + "(0x" + Integer.toHexString(id) + ")";
1386 }
1387 s = s + "=" + set.getAttributeValue(i);
1388 }
1389 System.out.println(s);
1390 s = " Found:";
1391 TypedValue value = new TypedValue();
1392 for (i=0; i<attrs.length; i++) {
1393 int d = i*AssetManager.STYLE_NUM_ENTRIES;
1394 value.type = data[d+AssetManager.STYLE_TYPE];
1395 value.data = data[d+AssetManager.STYLE_DATA];
1396 value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1397 value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1398 s = s + " 0x" + Integer.toHexString(attrs[i])
1399 + "=" + value;
1400 }
1401 System.out.println(s);
1402 }
1403
1404 return array;
1405 }
1406
1407 /**
1408 * Retrieve the value of an attribute in the Theme. The contents of
1409 * <var>outValue</var> are ultimately filled in by
1410 * {@link Resources#getValue}.
1411 *
1412 * @param resid The resource identifier of the desired theme
1413 * attribute.
1414 * @param outValue Filled in with the ultimate resource value supplied
1415 * by the attribute.
1416 * @param resolveRefs If true, resource references will be walked; if
1417 * false, <var>outValue</var> may be a
1418 * TYPE_REFERENCE. In either case, it will never
1419 * be a TYPE_ATTRIBUTE.
1420 *
1421 * @return boolean Returns true if the attribute was found and
1422 * <var>outValue</var> is valid, else false.
1423 */
1424 public boolean resolveAttribute(int resid, TypedValue outValue,
1425 boolean resolveRefs) {
1426 boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1427 if (false) {
1428 System.out.println(
1429 "resolveAttribute #" + Integer.toHexString(resid)
1430 + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type)
1431 + ", data=0x" + Integer.toHexString(outValue.data));
1432 }
1433 return got;
1434 }
1435
1436 /**
1437 * Print contents of this theme out to the log. For debugging only.
1438 *
1439 * @param priority The log priority to use.
1440 * @param tag The log tag to use.
1441 * @param prefix Text to prefix each line printed.
1442 */
1443 public void dump(int priority, String tag, String prefix) {
1444 AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1445 }
1446
1447 protected void finalize() throws Throwable {
1448 super.finalize();
1449 mAssets.releaseTheme(mTheme);
1450 }
1451
1452 /*package*/ Theme() {
1453 mAssets = Resources.this.mAssets;
1454 mTheme = mAssets.createTheme();
1455 }
1456
1457 private final AssetManager mAssets;
1458 private final int mTheme;
1459 }
1460
1461 /**
1462 * Generate a new Theme object for this set of Resources. It initially
1463 * starts out empty.
1464 *
1465 * @return Theme The newly created Theme container.
1466 */
1467 public final Theme newTheme() {
1468 return new Theme();
1469 }
1470
1471 /**
1472 * Retrieve a set of basic attribute values from an AttributeSet, not
1473 * performing styling of them using a theme and/or style resources.
1474 *
1475 * @param set The current attribute values to retrieve.
1476 * @param attrs The specific attributes to be retrieved.
1477 * @return Returns a TypedArray holding an array of the attribute values.
1478 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1479 * when done with it.
1480 *
1481 * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1482 */
1483 public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1484 int len = attrs.length;
1485 TypedArray array = getCachedStyledAttributes(len);
1486
1487 // XXX note that for now we only work with compiled XML files.
1488 // To support generic XML files we will need to manually parse
1489 // out the attributes from the XML file (applying type information
1490 // contained in the resources and such).
1491 XmlBlock.Parser parser = (XmlBlock.Parser)set;
1492 mAssets.retrieveAttributes(parser.mParseState, attrs,
1493 array.mData, array.mIndices);
1494
1495 array.mRsrcs = attrs;
1496 array.mXml = parser;
1497
1498 return array;
1499 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07001500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 /**
1502 * Store the newly updated configuration.
1503 */
1504 public void updateConfiguration(Configuration config,
1505 DisplayMetrics metrics) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001506 updateConfiguration(config, metrics, null);
1507 }
1508
1509 /**
1510 * @hide
1511 */
1512 public void updateConfiguration(Configuration config,
1513 DisplayMetrics metrics, CompatibilityInfo compat) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001514 synchronized (mAccessLock) {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001515 if (false) {
1516 Slog.i(TAG, "**** Updating config of " + this + ": old config is "
1517 + mConfiguration + " old compat is " + mCompatibilityInfo);
1518 Slog.i(TAG, "**** Updating config of " + this + ": new config is "
1519 + config + " new compat is " + compat);
1520 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001521 if (compat != null) {
1522 mCompatibilityInfo = compat;
1523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 if (metrics != null) {
1525 mMetrics.setTo(metrics);
1526 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001527 // NOTE: We should re-arrange this code to create a Display
1528 // with the CompatibilityInfo that is used everywhere we deal
1529 // with the display in relation to this app, rather than
1530 // doing the conversion here. This impl should be okay because
1531 // we make sure to return a compatible display in the places
1532 // where there are public APIs to retrieve the display... but
1533 // it would be cleaner and more maintainble to just be
1534 // consistently dealing with a compatible display everywhere in
1535 // the framework.
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001536 if (mCompatibilityInfo != null) {
1537 mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
1538 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001539 int configChanges = 0xfffffff;
1540 if (config != null) {
1541 mTmpConfig.setTo(config);
Dianne Hackborn756220b2012-08-14 16:45:30 -07001542 int density = config.densityDpi;
1543 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1544 density = mMetrics.noncompatDensityDpi;
1545 }
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001546 if (mCompatibilityInfo != null) {
Dianne Hackborn756220b2012-08-14 16:45:30 -07001547 mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001548 }
1549 if (mTmpConfig.locale == null) {
1550 mTmpConfig.locale = Locale.getDefault();
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001551 mTmpConfig.setLayoutDirection(mTmpConfig.locale);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001552 }
1553 configChanges = mConfiguration.updateFrom(mTmpConfig);
1554 configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
1555 }
1556 if (mConfiguration.locale == null) {
1557 mConfiguration.locale = Locale.getDefault();
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001558 mConfiguration.setLayoutDirection(mConfiguration.locale);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001559 }
Dianne Hackborn756220b2012-08-14 16:45:30 -07001560 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
1561 mMetrics.densityDpi = mConfiguration.densityDpi;
1562 mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1563 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001564 mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 String locale = null;
1567 if (mConfiguration.locale != null) {
1568 locale = mConfiguration.locale.getLanguage();
1569 if (mConfiguration.locale.getCountry() != null) {
1570 locale += "-" + mConfiguration.locale.getCountry();
1571 }
1572 }
1573 int width, height;
1574 if (mMetrics.widthPixels >= mMetrics.heightPixels) {
1575 width = mMetrics.widthPixels;
1576 height = mMetrics.heightPixels;
1577 } else {
1578 //noinspection SuspiciousNameCombination
1579 width = mMetrics.heightPixels;
1580 //noinspection SuspiciousNameCombination
1581 height = mMetrics.widthPixels;
1582 }
1583 int keyboardHidden = mConfiguration.keyboardHidden;
Dianne Hackborn08d5b8f2010-08-04 11:12:40 -07001584 if (keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 && mConfiguration.hardKeyboardHidden
1586 == Configuration.HARDKEYBOARDHIDDEN_YES) {
1587 keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
1588 }
1589 mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
1590 locale, mConfiguration.orientation,
1591 mConfiguration.touchscreen,
Dianne Hackborn908aecc2012-07-31 16:37:34 -07001592 mConfiguration.densityDpi, mConfiguration.keyboard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 keyboardHidden, mConfiguration.navigation, width, height,
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001594 mConfiguration.smallestScreenWidthDp,
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001595 mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08001596 mConfiguration.screenLayout, mConfiguration.uiMode,
1597 Build.VERSION.RESOURCES_SDK_INT);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001598
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001599 if (DEBUG_CONFIG) {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001600 Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration
1601 + " final compat is " + mCompatibilityInfo);
1602 }
1603
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001604 clearDrawableCacheLocked(mDrawableCache, configChanges);
1605 clearDrawableCacheLocked(mColorDrawableCache, configChanges);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 mColorStateListCache.clear();
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001608
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 flushLayoutCache();
1610 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001611 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 if (mPluralRule != null) {
Elliott Hughes1ad636c2010-07-01 16:51:48 -07001613 mPluralRule = NativePluralRules.forLocale(config.locale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 }
1615 }
1616 }
1617
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001618 private void clearDrawableCacheLocked(
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001619 LongSparseArray<WeakReference<ConstantState>> cache,
1620 int configChanges) {
1621 int N = cache.size();
1622 if (DEBUG_CONFIG) {
1623 Log.d(TAG, "Cleaning up drawables config changes: 0x"
1624 + Integer.toHexString(configChanges));
1625 }
1626 for (int i=0; i<N; i++) {
1627 WeakReference<Drawable.ConstantState> ref = cache.valueAt(i);
1628 if (ref != null) {
1629 Drawable.ConstantState cs = ref.get();
1630 if (cs != null) {
1631 if (Configuration.needNewResources(
1632 configChanges, cs.getChangingConfigurations())) {
1633 if (DEBUG_CONFIG) {
1634 Log.d(TAG, "FLUSHING #0x"
1635 + Long.toHexString(mDrawableCache.keyAt(i))
1636 + " / " + cs + " with changes: 0x"
1637 + Integer.toHexString(cs.getChangingConfigurations()));
1638 }
1639 cache.setValueAt(i, null);
1640 } else if (DEBUG_CONFIG) {
1641 Log.d(TAG, "(Keeping #0x"
1642 + Long.toHexString(cache.keyAt(i))
1643 + " / " + cs + " with changes: 0x"
1644 + Integer.toHexString(cs.getChangingConfigurations())
1645 + ")");
1646 }
1647 }
1648 }
1649 }
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001650 }
1651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 /**
1653 * Update the system resources configuration if they have previously
1654 * been initialized.
1655 *
1656 * @hide
1657 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001658 public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
1659 CompatibilityInfo compat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 if (mSystem != null) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001661 mSystem.updateConfiguration(config, metrics, compat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 //Log.i(TAG, "Updated system resources " + mSystem
1663 // + ": " + mSystem.getConfiguration());
1664 }
1665 }
1666
1667 /**
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001668 * @hide
1669 */
1670 public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
1671 updateSystemConfiguration(config, metrics, null);
1672 }
1673
1674 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 * Return the current display metrics that are in effect for this resource
1676 * object. The returned object should be treated as read-only.
1677 *
1678 * @return The resource's current display metrics.
1679 */
1680 public DisplayMetrics getDisplayMetrics() {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001681 if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
1682 + "x" + mMetrics.heightPixels + " " + mMetrics.density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 return mMetrics;
1684 }
1685
1686 /**
1687 * Return the current configuration that is in effect for this resource
1688 * object. The returned object should be treated as read-only.
1689 *
1690 * @return The resource's current configuration.
1691 */
1692 public Configuration getConfiguration() {
1693 return mConfiguration;
1694 }
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001695
1696 /**
1697 * Return the compatibility mode information for the application.
1698 * The returned object should be treated as read-only.
1699 *
Dianne Hackborn3904d032011-05-27 12:09:11 -07001700 * @return compatibility info.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001701 * @hide
1702 */
1703 public CompatibilityInfo getCompatibilityInfo() {
Dianne Hackborn3904d032011-05-27 12:09:11 -07001704 return mCompatibilityInfo != null ? mCompatibilityInfo
1705 : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07001706 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707
1708 /**
Dianne Hackborna53b8282009-07-17 11:13:48 -07001709 * This is just for testing.
1710 * @hide
1711 */
1712 public void setCompatibilityInfo(CompatibilityInfo ci) {
1713 mCompatibilityInfo = ci;
1714 updateConfiguration(mConfiguration, mMetrics);
1715 }
1716
1717 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 * Return a resource identifier for the given resource name. A fully
1719 * qualified resource name is of the form "package:type/entry". The first
1720 * two components (package and type) are optional if defType and
1721 * defPackage, respectively, are specified here.
1722 *
1723 * <p>Note: use of this function is discouraged. It is much more
1724 * efficient to retrieve resources by identifier than by name.
1725 *
1726 * @param name The name of the desired resource.
1727 * @param defType Optional default resource type to find, if "type/" is
1728 * not included in the name. Can be null to require an
1729 * explicit type.
1730 * @param defPackage Optional default package to find, if "package:" is
1731 * not included in the name. Can be null to require an
1732 * explicit package.
1733 *
1734 * @return int The associated resource identifier. Returns 0 if no such
1735 * resource was found. (0 is not a valid resource ID.)
1736 */
1737 public int getIdentifier(String name, String defType, String defPackage) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001738 if (name == null) {
1739 throw new NullPointerException("name is null");
1740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 try {
1742 return Integer.parseInt(name);
1743 } catch (Exception e) {
1744 // Ignore
1745 }
1746 return mAssets.getResourceIdentifier(name, defType, defPackage);
1747 }
1748
1749 /**
Jeff Sharkey47b50332013-03-15 14:46:46 -07001750 * Return true if given resource identifier includes a package.
1751 *
1752 * @hide
1753 */
1754 public static boolean resourceHasPackage(int resid) {
1755 return (resid >>> 24) != 0;
1756 }
1757
1758 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 * Return the full name for a given resource identifier. This name is
1760 * a single string of the form "package:type/entry".
1761 *
1762 * @param resid The resource identifier whose name is to be retrieved.
1763 *
1764 * @return A string holding the name of the resource.
1765 *
1766 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1767 *
1768 * @see #getResourcePackageName
1769 * @see #getResourceTypeName
1770 * @see #getResourceEntryName
1771 */
1772 public String getResourceName(int resid) throws NotFoundException {
1773 String str = mAssets.getResourceName(resid);
1774 if (str != null) return str;
1775 throw new NotFoundException("Unable to find resource ID #0x"
1776 + Integer.toHexString(resid));
1777 }
1778
1779 /**
1780 * Return the package name for a given resource identifier.
1781 *
1782 * @param resid The resource identifier whose package name is to be
1783 * retrieved.
1784 *
1785 * @return A string holding the package name of the resource.
1786 *
1787 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1788 *
1789 * @see #getResourceName
1790 */
1791 public String getResourcePackageName(int resid) throws NotFoundException {
1792 String str = mAssets.getResourcePackageName(resid);
1793 if (str != null) return str;
1794 throw new NotFoundException("Unable to find resource ID #0x"
1795 + Integer.toHexString(resid));
1796 }
1797
1798 /**
1799 * Return the type name for a given resource identifier.
1800 *
1801 * @param resid The resource identifier whose type name is to be
1802 * retrieved.
1803 *
1804 * @return A string holding the type name of the resource.
1805 *
1806 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1807 *
1808 * @see #getResourceName
1809 */
1810 public String getResourceTypeName(int resid) throws NotFoundException {
1811 String str = mAssets.getResourceTypeName(resid);
1812 if (str != null) return str;
1813 throw new NotFoundException("Unable to find resource ID #0x"
1814 + Integer.toHexString(resid));
1815 }
1816
1817 /**
1818 * Return the entry name for a given resource identifier.
1819 *
1820 * @param resid The resource identifier whose entry name is to be
1821 * retrieved.
1822 *
1823 * @return A string holding the entry name of the resource.
1824 *
1825 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1826 *
1827 * @see #getResourceName
1828 */
1829 public String getResourceEntryName(int resid) throws NotFoundException {
1830 String str = mAssets.getResourceEntryName(resid);
1831 if (str != null) return str;
1832 throw new NotFoundException("Unable to find resource ID #0x"
1833 + Integer.toHexString(resid));
1834 }
1835
1836 /**
1837 * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
1838 * an XML file. You call this when you are at the parent tag of the
Dianne Hackborndef15372010-08-15 12:43:52 -07001839 * 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 -08001840 * This will call {@link #parseBundleExtra} for each extra tag encountered.
1841 *
1842 * @param parser The parser from which to retrieve the extras.
1843 * @param outBundle A Bundle in which to place all parsed extras.
1844 * @throws XmlPullParserException
1845 * @throws IOException
1846 */
1847 public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
1848 throws XmlPullParserException, IOException {
1849 int outerDepth = parser.getDepth();
1850 int type;
1851 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1852 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
1853 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1854 continue;
1855 }
1856
1857 String nodeName = parser.getName();
1858 if (nodeName.equals("extra")) {
1859 parseBundleExtra("extra", parser, outBundle);
1860 XmlUtils.skipCurrentTag(parser);
1861
1862 } else {
1863 XmlUtils.skipCurrentTag(parser);
1864 }
1865 }
1866 }
1867
1868 /**
1869 * Parse a name/value pair out of an XML tag holding that data. The
1870 * AttributeSet must be holding the data defined by
1871 * {@link android.R.styleable#Extra}. The following value types are supported:
1872 * <ul>
1873 * <li> {@link TypedValue#TYPE_STRING}:
1874 * {@link Bundle#putCharSequence Bundle.putCharSequence()}
1875 * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
1876 * {@link Bundle#putCharSequence Bundle.putBoolean()}
1877 * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
1878 * {@link Bundle#putCharSequence Bundle.putBoolean()}
1879 * <li> {@link TypedValue#TYPE_FLOAT}:
1880 * {@link Bundle#putCharSequence Bundle.putFloat()}
1881 * </ul>
1882 *
1883 * @param tagName The name of the tag these attributes come from; this is
1884 * only used for reporting error messages.
1885 * @param attrs The attributes from which to retrieve the name/value pair.
1886 * @param outBundle The Bundle in which to place the parsed value.
1887 * @throws XmlPullParserException If the attributes are not valid.
1888 */
1889 public void parseBundleExtra(String tagName, AttributeSet attrs,
1890 Bundle outBundle) throws XmlPullParserException {
1891 TypedArray sa = obtainAttributes(attrs,
1892 com.android.internal.R.styleable.Extra);
1893
1894 String name = sa.getString(
1895 com.android.internal.R.styleable.Extra_name);
1896 if (name == null) {
1897 sa.recycle();
1898 throw new XmlPullParserException("<" + tagName
1899 + "> requires an android:name attribute at "
1900 + attrs.getPositionDescription());
1901 }
1902
1903 TypedValue v = sa.peekValue(
1904 com.android.internal.R.styleable.Extra_value);
1905 if (v != null) {
1906 if (v.type == TypedValue.TYPE_STRING) {
1907 CharSequence cs = v.coerceToString();
1908 outBundle.putCharSequence(name, cs);
1909 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
1910 outBundle.putBoolean(name, v.data != 0);
1911 } else if (v.type >= TypedValue.TYPE_FIRST_INT
1912 && v.type <= TypedValue.TYPE_LAST_INT) {
1913 outBundle.putInt(name, v.data);
1914 } else if (v.type == TypedValue.TYPE_FLOAT) {
1915 outBundle.putFloat(name, v.getFloat());
1916 } else {
1917 sa.recycle();
1918 throw new XmlPullParserException("<" + tagName
1919 + "> only supports string, integer, float, color, and boolean at "
1920 + attrs.getPositionDescription());
1921 }
1922 } else {
1923 sa.recycle();
1924 throw new XmlPullParserException("<" + tagName
1925 + "> requires an android:value or android:resource attribute at "
1926 + attrs.getPositionDescription());
1927 }
1928
1929 sa.recycle();
1930 }
1931
1932 /**
1933 * Retrieve underlying AssetManager storage for these resources.
1934 */
1935 public final AssetManager getAssets() {
1936 return mAssets;
1937 }
1938
1939 /**
1940 * Call this to remove all cached loaded layout resources from the
1941 * Resources object. Only intended for use with performance testing
1942 * tools.
1943 */
1944 public final void flushLayoutCache() {
1945 synchronized (mCachedXmlBlockIds) {
1946 // First see if this block is in our cache.
1947 final int num = mCachedXmlBlockIds.length;
1948 for (int i=0; i<num; i++) {
1949 mCachedXmlBlockIds[i] = -0;
1950 XmlBlock oldBlock = mCachedXmlBlocks[i];
1951 if (oldBlock != null) {
1952 oldBlock.close();
1953 }
1954 mCachedXmlBlocks[i] = null;
1955 }
1956 }
1957 }
1958
1959 /**
1960 * Start preloading of resource data using this Resources object. Only
1961 * for use by the zygote process for loading common system resources.
1962 * {@hide}
1963 */
1964 public final void startPreloading() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001965 synchronized (sSync) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07001966 if (sPreloaded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 throw new IllegalStateException("Resources already preloaded");
1968 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07001969 sPreloaded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 mPreloading = true;
Dianne Hackborndde331c2012-08-03 14:01:57 -07001971 sPreloadedDensity = DisplayMetrics.DENSITY_DEVICE;
1972 mConfiguration.densityDpi = sPreloadedDensity;
1973 updateConfiguration(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 }
1975 }
1976
1977 /**
1978 * Called by zygote when it is done preloading resources, to change back
1979 * to normal Resources operation.
1980 */
1981 public final void finishPreloading() {
1982 if (mPreloading) {
1983 mPreloading = false;
1984 flushLayoutCache();
1985 }
1986 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07001987
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07001988 private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
1989 int resourceId, String name) {
1990 // We allow preloading of resources even if they vary by font scale (which
1991 // doesn't impact resource selection) or density (which we handle specially by
1992 // simply turning off all preloading), as well as any other configs specified
1993 // by the caller.
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07001994 if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07001995 ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07001996 String resName;
1997 try {
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07001998 resName = getResourceName(resourceId);
Dianne Hackborndde331c2012-08-03 14:01:57 -07001999 } catch (NotFoundException e) {
2000 resName = "?";
2001 }
2002 Log.w(TAG, "Preloaded " + name + " resource #0x"
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002003 + Integer.toHexString(resourceId)
Dianne Hackborndde331c2012-08-03 14:01:57 -07002004 + " (" + resName + ") that varies with configuration!!");
2005 return false;
2006 }
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -07002007 if (TRACE_FOR_PRELOAD) {
2008 String resName;
2009 try {
2010 resName = getResourceName(resourceId);
2011 } catch (NotFoundException e) {
2012 resName = "?";
2013 }
2014 Log.w(TAG, "Preloading " + name + " resource #0x"
2015 + Integer.toHexString(resourceId)
2016 + " (" + resName + ")");
2017 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002018 return true;
2019 }
2020
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002021 static private final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
2022 ActivityInfo.CONFIG_LAYOUT_DIRECTION);
2023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 /*package*/ Drawable loadDrawable(TypedValue value, int id)
2025 throws NotFoundException {
2026
2027 if (TRACE_FOR_PRELOAD) {
2028 // Log only framework resources
2029 if ((id >>> 24) == 0x1) {
2030 final String name = getResourceName(id);
2031 if (name != null) android.util.Log.d("PreloadDrawable", name);
2032 }
2033 }
2034
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002035 boolean isColorDrawable = false;
2036 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
2037 value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
2038 isColorDrawable = true;
2039 }
Romain Guy5f49c302012-09-06 16:33:31 -07002040 final long key = isColorDrawable ? value.data :
2041 (((long) value.assetCookie) << 32) | value.data;
2042
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002043 Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044
2045 if (dr != null) {
2046 return dr;
2047 }
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002048 Drawable.ConstantState cs;
2049 if (isColorDrawable) {
2050 cs = sPreloadedColorDrawables.get(key);
2051 } else {
2052 cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
2053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 if (cs != null) {
Dianne Hackbornc2974802009-09-13 18:22:19 -07002055 dr = cs.newDrawable(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 } else {
Romain Guy8f85e802011-12-14 19:23:32 -08002057 if (isColorDrawable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 dr = new ColorDrawable(value.data);
2059 }
2060
2061 if (dr == null) {
2062 if (value.string == null) {
2063 throw new NotFoundException(
2064 "Resource is not a Drawable (color or path): " + value);
2065 }
2066
2067 String file = value.string.toString();
2068
Dianne Hackborn9b44aae2011-09-02 19:17:16 -07002069 if (TRACE_FOR_MISS_PRELOAD) {
2070 // Log only framework resources
2071 if ((id >>> 24) == 0x1) {
2072 final String name = getResourceName(id);
2073 if (name != null) android.util.Log.d(TAG, "Loading framework drawable #"
2074 + Integer.toHexString(id) + ": " + name
2075 + " at " + file);
2076 }
2077 }
2078
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie "
2080 + value.assetCookie + ": " + file);
2081
2082 if (file.endsWith(".xml")) {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002083 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 try {
2085 XmlResourceParser rp = loadXmlResourceParser(
2086 file, id, value.assetCookie, "drawable");
2087 dr = Drawable.createFromXml(this, rp);
2088 rp.close();
2089 } catch (Exception e) {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002090 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 NotFoundException rnf = new NotFoundException(
2092 "File " + file + " from drawable resource ID #0x"
2093 + Integer.toHexString(id));
2094 rnf.initCause(e);
2095 throw rnf;
2096 }
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002097 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098
2099 } else {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002100 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 try {
2102 InputStream is = mAssets.openNonAsset(
Dianne Hackborn19382ac2009-09-11 21:13:37 -07002103 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 // System.out.println("Opened file " + file + ": " + is);
Dianne Hackborn7341d7a2009-08-14 11:37:52 -07002105 dr = Drawable.createFromResourceStream(this, value, is,
2106 file, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 is.close();
2108 // System.out.println("Created stream: " + dr);
2109 } catch (Exception e) {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002110 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 NotFoundException rnf = new NotFoundException(
2112 "File " + file + " from drawable resource ID #0x"
2113 + Integer.toHexString(id));
2114 rnf.initCause(e);
2115 throw rnf;
2116 }
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002117 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 }
2119 }
2120 }
2121
2122 if (dr != null) {
2123 dr.setChangingConfigurations(value.changingConfigurations);
2124 cs = dr.getConstantState();
2125 if (cs != null) {
2126 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002127 final int changingConfigs = cs.getChangingConfigurations();
2128 if (isColorDrawable) {
2129 if (verifyPreloadConfig(changingConfigs, 0, value.resourceId,
2130 "drawable")) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002131 sPreloadedColorDrawables.put(key, cs);
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002132 }
2133 } else {
2134 if (verifyPreloadConfig(changingConfigs,
2135 LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
2136 if ((changingConfigs&LAYOUT_DIR_CONFIG) == 0) {
2137 // If this resource does not vary based on layout direction,
2138 // we can put it in all of the preload maps.
2139 sPreloadedDrawables[0].put(key, cs);
2140 sPreloadedDrawables[1].put(key, cs);
2141 } else {
2142 // Otherwise, only in the layout dir we loaded it for.
2143 final LongSparseArray<Drawable.ConstantState> preloads
2144 = sPreloadedDrawables[mConfiguration.getLayoutDirection()];
2145 preloads.put(key, cs);
2146 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002147 }
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002149 } else {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002150 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 //Log.i(TAG, "Saving cached drawable @ #" +
2152 // Integer.toHexString(key.intValue())
2153 // + " in " + this + ": " + cs);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002154 if (isColorDrawable) {
2155 mColorDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
2156 } else {
2157 mDrawableCache.put(key, new WeakReference<Drawable.ConstantState>(cs));
2158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 }
2160 }
2161 }
2162 }
2163
2164 return dr;
2165 }
2166
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002167 private Drawable getCachedDrawable(
2168 LongSparseArray<WeakReference<ConstantState>> drawableCache,
2169 long key) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002170 synchronized (mAccessLock) {
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002171 WeakReference<Drawable.ConstantState> wr = drawableCache.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 if (wr != null) { // we have the key
2173 Drawable.ConstantState entry = wr.get();
2174 if (entry != null) {
2175 //Log.i(TAG, "Returning cached drawable @ #" +
2176 // Integer.toHexString(((Integer)key).intValue())
2177 // + " in " + this + ": " + entry);
Masanori Ogino708654c2010-07-20 18:55:51 +09002178 return entry.newDrawable(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
2180 else { // our entry has been purged
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002181 drawableCache.delete(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 }
2183 }
2184 }
2185 return null;
2186 }
2187
2188 /*package*/ ColorStateList loadColorStateList(TypedValue value, int id)
2189 throws NotFoundException {
2190 if (TRACE_FOR_PRELOAD) {
2191 // Log only framework resources
2192 if ((id >>> 24) == 0x1) {
2193 final String name = getResourceName(id);
2194 if (name != null) android.util.Log.d("PreloadColorStateList", name);
2195 }
2196 }
2197
Romain Guy5d911c32012-04-12 16:25:17 -07002198 final long key = (((long) value.assetCookie) << 32) | value.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199
2200 ColorStateList csl;
2201
2202 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
2203 value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
2204
Romain Guy5d911c32012-04-12 16:25:17 -07002205 csl = sPreloadedColorStateLists.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 if (csl != null) {
2207 return csl;
2208 }
2209
2210 csl = ColorStateList.valueOf(value.data);
2211 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002212 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2213 "color")) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002214 sPreloadedColorStateLists.put(key, csl);
2215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
2217
2218 return csl;
2219 }
2220
2221 csl = getCachedColorStateList(key);
2222 if (csl != null) {
2223 return csl;
2224 }
2225
Romain Guy5d911c32012-04-12 16:25:17 -07002226 csl = sPreloadedColorStateLists.get(key);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 if (csl != null) {
2228 return csl;
2229 }
2230
2231 if (value.string == null) {
2232 throw new NotFoundException(
2233 "Resource is not a ColorStateList (color or path): " + value);
2234 }
2235
2236 String file = value.string.toString();
2237
2238 if (file.endsWith(".xml")) {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002239 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 try {
2241 XmlResourceParser rp = loadXmlResourceParser(
2242 file, id, value.assetCookie, "colorstatelist");
2243 csl = ColorStateList.createFromXml(this, rp);
2244 rp.close();
2245 } catch (Exception e) {
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002246 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 NotFoundException rnf = new NotFoundException(
2248 "File " + file + " from color state list resource ID #0x"
2249 + Integer.toHexString(id));
2250 rnf.initCause(e);
2251 throw rnf;
2252 }
Dianne Hackborn0acc1932013-04-12 17:49:17 -07002253 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 } else {
2255 throw new NotFoundException(
2256 "File " + file + " from drawable resource ID #0x"
2257 + Integer.toHexString(id) + ": .xml extension required");
2258 }
2259
2260 if (csl != null) {
2261 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002262 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2263 "color")) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002264 sPreloadedColorStateLists.put(key, csl);
2265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002266 } else {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002267 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002268 //Log.i(TAG, "Saving cached color state list @ #" +
2269 // Integer.toHexString(key.intValue())
2270 // + " in " + this + ": " + csl);
Romain Guy5d911c32012-04-12 16:25:17 -07002271 mColorStateListCache.put(key, new WeakReference<ColorStateList>(csl));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002272 }
2273 }
2274 }
2275
2276 return csl;
2277 }
2278
Romain Guy5d911c32012-04-12 16:25:17 -07002279 private ColorStateList getCachedColorStateList(long key) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002280 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002281 WeakReference<ColorStateList> wr = mColorStateListCache.get(key);
2282 if (wr != null) { // we have the key
2283 ColorStateList entry = wr.get();
2284 if (entry != null) {
2285 //Log.i(TAG, "Returning cached color state list @ #" +
2286 // Integer.toHexString(((Integer)key).intValue())
2287 // + " in " + this + ": " + entry);
2288 return entry;
Romain Guy5d911c32012-04-12 16:25:17 -07002289 } else { // our entry has been purged
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 mColorStateListCache.delete(key);
2291 }
2292 }
2293 }
2294 return null;
2295 }
2296
2297 /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
2298 throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002299 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 TypedValue value = mTmpValue;
Dianne Hackborne5b50a62013-02-11 16:18:42 -08002301 if (value == null) {
2302 mTmpValue = value = new TypedValue();
2303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002304 getValue(id, value, true);
2305 if (value.type == TypedValue.TYPE_STRING) {
2306 return loadXmlResourceParser(value.string.toString(), id,
2307 value.assetCookie, type);
2308 }
2309 throw new NotFoundException(
2310 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
2311 + Integer.toHexString(value.type) + " is not valid");
2312 }
2313 }
2314
2315 /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
2316 int assetCookie, String type) throws NotFoundException {
2317 if (id != 0) {
2318 try {
2319 // These may be compiled...
2320 synchronized (mCachedXmlBlockIds) {
2321 // First see if this block is in our cache.
2322 final int num = mCachedXmlBlockIds.length;
2323 for (int i=0; i<num; i++) {
2324 if (mCachedXmlBlockIds[i] == id) {
2325 //System.out.println("**** REUSING XML BLOCK! id="
2326 // + id + ", index=" + i);
2327 return mCachedXmlBlocks[i].newParser();
2328 }
2329 }
2330
2331 // Not in the cache, create a new block and put it at
2332 // the next slot in the cache.
2333 XmlBlock block = mAssets.openXmlBlockAsset(
2334 assetCookie, file);
2335 if (block != null) {
2336 int pos = mLastCachedXmlBlockIndex+1;
2337 if (pos >= num) pos = 0;
2338 mLastCachedXmlBlockIndex = pos;
2339 XmlBlock oldBlock = mCachedXmlBlocks[pos];
2340 if (oldBlock != null) {
2341 oldBlock.close();
2342 }
2343 mCachedXmlBlockIds[pos] = id;
2344 mCachedXmlBlocks[pos] = block;
2345 //System.out.println("**** CACHING NEW XML BLOCK! id="
2346 // + id + ", index=" + pos);
2347 return block.newParser();
2348 }
2349 }
2350 } catch (Exception e) {
2351 NotFoundException rnf = new NotFoundException(
2352 "File " + file + " from xml type " + type + " resource ID #0x"
2353 + Integer.toHexString(id));
2354 rnf.initCause(e);
2355 throw rnf;
2356 }
2357 }
2358
2359 throw new NotFoundException(
2360 "File " + file + " from xml type " + type + " resource ID #0x"
2361 + Integer.toHexString(id));
2362 }
2363
2364 private TypedArray getCachedStyledAttributes(int len) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002365 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 TypedArray attrs = mCachedStyledAttributes;
2367 if (attrs != null) {
2368 mCachedStyledAttributes = null;
Dianne Hackbornab0f4852011-09-12 16:59:06 -07002369 if (DEBUG_ATTRIBUTES_CACHE) {
2370 mLastRetrievedAttrs = new RuntimeException("here");
2371 mLastRetrievedAttrs.fillInStackTrace();
2372 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002373
2374 attrs.mLength = len;
2375 int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
2376 if (attrs.mData.length >= fullLen) {
2377 return attrs;
2378 }
2379 attrs.mData = new int[fullLen];
2380 attrs.mIndices = new int[1+len];
2381 return attrs;
2382 }
Dianne Hackbornab0f4852011-09-12 16:59:06 -07002383 if (DEBUG_ATTRIBUTES_CACHE) {
2384 RuntimeException here = new RuntimeException("here");
2385 here.fillInStackTrace();
2386 if (mLastRetrievedAttrs != null) {
2387 Log.i(TAG, "Allocated new TypedArray of " + len + " in " + this, here);
2388 Log.i(TAG, "Last retrieved attributes here", mLastRetrievedAttrs);
2389 }
2390 mLastRetrievedAttrs = here;
2391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002392 return new TypedArray(this,
2393 new int[len*AssetManager.STYLE_NUM_ENTRIES],
2394 new int[1+len], len);
2395 }
2396 }
2397
2398 private Resources() {
2399 mAssets = AssetManager.getSystem();
2400 // NOTE: Intentionally leaving this uninitialized (all values set
2401 // to zero), so that anyone who tries to do something that requires
2402 // metrics will get a very wrong value.
2403 mConfiguration.setToDefaults();
2404 mMetrics.setToDefaults();
2405 updateConfiguration(null, null);
2406 mAssets.ensureStringBlocks();
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002407 mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 }
2409}