blob: 334d18018c9f9d1c6176b385e5f065181de37540 [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
Tor Norbyec91531a2015-04-01 17:41:55 -070019import android.annotation.AttrRes;
Tor Norbye80756e32015-03-02 09:39:27 -080020import android.annotation.ColorInt;
Tor Norbyec91531a2015-04-01 17:41:55 -070021import android.annotation.StyleRes;
22import android.annotation.StyleableRes;
Dianne Hackborn2269d1572010-02-24 19:54:22 -080023import com.android.internal.util.XmlUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25import org.xmlpull.v1.XmlPullParser;
26import org.xmlpull.v1.XmlPullParserException;
27
Alan Viverette45c4bbb2015-01-05 14:59:19 -080028import android.animation.Animator;
29import android.animation.StateListAnimator;
Tor Norbye7b9c9122013-05-30 16:48:33 -070030import android.annotation.AnimRes;
31import android.annotation.AnyRes;
32import android.annotation.ArrayRes;
33import android.annotation.BoolRes;
34import android.annotation.ColorRes;
35import android.annotation.DimenRes;
36import android.annotation.DrawableRes;
37import android.annotation.FractionRes;
38import android.annotation.IntegerRes;
39import android.annotation.LayoutRes;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080040import android.annotation.NonNull;
Alan Viverette3b5c4272014-05-20 13:20:42 -070041import android.annotation.Nullable;
Tor Norbye7b9c9122013-05-30 16:48:33 -070042import android.annotation.PluralsRes;
43import android.annotation.RawRes;
44import android.annotation.StringRes;
45import android.annotation.XmlRes;
Dianne Hackbornebff8f92011-05-12 18:07:47 -070046import android.content.pm.ActivityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.graphics.Movie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.graphics.drawable.ColorDrawable;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080049import android.graphics.drawable.Drawable;
Masanori Oginoc7d9d272010-07-10 12:10:41 +090050import android.graphics.drawable.Drawable.ConstantState;
Dianne Hackborn3b3e1452009-09-24 19:22:12 -070051import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Bundle;
Romain Guy3b748a42013-04-17 18:54:38 -070053import android.os.Trace;
Alan Viverette75257ce2014-05-22 19:31:38 -070054import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.util.AttributeSet;
56import android.util.DisplayMetrics;
57import android.util.Log;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080058import android.util.LongSparseArray;
59import android.util.Pools.SynchronizedPool;
Dianne Hackborn2f0b1752011-05-31 17:59:49 -070060import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.util.TypedValue;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080062import android.view.ViewDebug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64import java.io.IOException;
65import java.io.InputStream;
66import java.lang.ref.WeakReference;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080067import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
Elliott Hughes1ad636c2010-07-01 16:51:48 -070069import libcore.icu.NativePluralRules;
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071/**
72 * Class for accessing an application's resources. This sits on top of the
Scott Mainf4f05b82011-01-07 14:38:23 -080073 * asset manager of the application (accessible through {@link #getAssets}) and
74 * provides a high-level API for getting typed data from the assets.
75 *
76 * <p>The Android resource system keeps track of all non-code assets associated with an
77 * application. You can use this class to access your application's resources. You can generally
78 * acquire the {@link android.content.res.Resources} instance associated with your application
79 * with {@link android.content.Context#getResources getResources()}.</p>
80 *
81 * <p>The Android SDK tools compile your application's resources into the application binary
82 * at build time. To use a resource, you must install it correctly in the source tree (inside
83 * your project's {@code res/} directory) and build your application. As part of the build
84 * process, the SDK tools generate symbols for each resource, which you can use in your application
85 * code to access the resources.</p>
86 *
87 * <p>Using application resources makes it easy to update various characteristics of your
88 * application without modifying code, and&mdash;by providing sets of alternative
89 * resources&mdash;enables you to optimize your application for a variety of device configurations
90 * (such as for different languages and screen sizes). This is an important aspect of developing
91 * Android applications that are compatible on different types of devices.</p>
92 *
93 * <p>For more information about using resources, see the documentation about <a
94 * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 */
96public class Resources {
97 static final String TAG = "Resources";
Alan Viverette562a6a82014-01-31 11:07:29 -080098
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 private static final boolean DEBUG_LOAD = false;
100 private static final boolean DEBUG_CONFIG = false;
101 private static final boolean TRACE_FOR_PRELOAD = false;
Dianne Hackborn9b44aae2011-09-02 19:17:16 -0700102 private static final boolean TRACE_FOR_MISS_PRELOAD = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Alan Viverette562a6a82014-01-31 11:07:29 -0800104 private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
105 ActivityInfo.CONFIG_LAYOUT_DIRECTION);
106
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700107 private static final int ID_OTHER = 0x01000004;
108
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800109 private static final Object sSync = new Object();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 // Information about preloaded resources. Note that they are not
112 // protected by a lock, because while preloading in zygote we are all
113 // single-threaded, and after that these are immutable.
Alan Viverette52b999f2014-03-24 18:00:26 -0700114 private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
115 private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
Alan Viverettea8636c92015-03-27 10:44:39 -0700116 = new LongSparseArray<>();
Alan Viverettee0f95f32015-04-01 13:10:18 -0700117 private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
118 sPreloadedColorStateLists = new LongSparseArray<>();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700119
Alan Viverette4325f8e2015-04-01 15:00:30 -0700120 private static final String CACHE_NOT_THEMED = "";
121 private static final String CACHE_NULL_THEME = "null_theme";
122
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700123 // Pool of TypedArrays targeted to this Resources object.
Alan Viverettea8636c92015-03-27 10:44:39 -0700124 final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700125
Alan Viveretteedc46642014-02-01 01:43:16 -0800126 // Used by BridgeResources in layoutlib
127 static Resources mSystem = null;
128
Dianne Hackborndde331c2012-08-03 14:01:57 -0700129 private static boolean sPreloaded;
130 private static int sPreloadedDensity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800132 // These are protected by mAccessLock.
Alan Viverette562a6a82014-01-31 11:07:29 -0800133 private final Object mAccessLock = new Object();
134 private final Configuration mTmpConfig = new Configuration();
Alan Viverette75257ce2014-05-22 19:31:38 -0700135 private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mDrawableCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700136 new ArrayMap<>();
Alan Viverette75257ce2014-05-22 19:31:38 -0700137 private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> mColorDrawableCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700138 new ArrayMap<>();
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800139 private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700140 new ConfigurationBoundResourceCache<>(this);
Yigit Boyard422dc32014-09-25 12:23:35 -0700141 private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700142 new ConfigurationBoundResourceCache<>(this);
Yigit Boyard422dc32014-09-25 12:23:35 -0700143 private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700144 new ConfigurationBoundResourceCache<>(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Alan Viverette562a6a82014-01-31 11:07:29 -0800146 private TypedValue mTmpValue = new TypedValue();
147 private boolean mPreloading;
148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 private int mLastCachedXmlBlockIndex = -1;
150 private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
151 private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
152
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700153 final AssetManager mAssets;
154 final DisplayMetrics mMetrics = new DisplayMetrics();
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 private final Configuration mConfiguration = new Configuration();
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700157 private NativePluralRules mPluralRule;
Craig Mautner48d0d182013-06-11 07:53:06 -0700158
159 private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
Alan Viverette52b999f2014-03-24 18:00:26 -0700160
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700161 static {
162 sPreloadedDrawables = new LongSparseArray[2];
Alan Viverettea8636c92015-03-27 10:44:39 -0700163 sPreloadedDrawables[0] = new LongSparseArray<>();
164 sPreloadedDrawables[1] = new LongSparseArray<>();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700165 }
166
Alan Viverette62599332014-04-01 14:57:39 -0700167 /**
168 * Returns the most appropriate default theme for the specified target SDK version.
Alan Viverette5effd7e2014-05-05 12:25:33 -0700169 * <ul>
170 * <li>Below API 11: Gingerbread
171 * <li>APIs 11 thru 14: Holo
172 * <li>APIs 14 thru XX: Device default dark
173 * <li>API XX and above: Device default light with dark action bar
174 * </ul>
Alan Viverette62599332014-04-01 14:57:39 -0700175 *
176 * @param curTheme The current theme, or 0 if not specified.
177 * @param targetSdkVersion The target SDK version.
178 * @return A theme resource identifier
179 * @hide
180 */
Alan Viverette5effd7e2014-05-05 12:25:33 -0700181 public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800182 return selectSystemTheme(curTheme, targetSdkVersion,
Alan Viverette5effd7e2014-05-05 12:25:33 -0700183 com.android.internal.R.style.Theme,
184 com.android.internal.R.style.Theme_Holo,
185 com.android.internal.R.style.Theme_DeviceDefault,
186 com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800187 }
Alan Viverette62599332014-04-01 14:57:39 -0700188
Alan Viverette5effd7e2014-05-05 12:25:33 -0700189 /** @hide */
190 public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
191 int dark, int deviceDefault) {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800192 if (curTheme != 0) {
193 return curTheme;
194 }
Alan Viverette5effd7e2014-05-05 12:25:33 -0700195 if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
196 return orig;
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800197 }
Alan Viverette5effd7e2014-05-05 12:25:33 -0700198 if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
199 return holo;
200 }
201 if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
202 return dark;
203 }
204 return deviceDefault;
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800205 }
Alan Viverette62599332014-04-01 14:57:39 -0700206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 /**
Yigit Boyard422dc32014-09-25 12:23:35 -0700208 * Used by AnimatorInflater.
209 *
210 * @hide
211 */
212 public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
213 return mAnimatorCache;
214 }
215
216 /**
217 * Used by AnimatorInflater.
218 *
219 * @hide
220 */
221 public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
222 return mStateListAnimatorCache;
223 }
224
225 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 * This exception is thrown by the resource APIs when a requested resource
227 * can not be found.
228 */
229 public static class NotFoundException extends RuntimeException {
230 public NotFoundException() {
231 }
232
233 public NotFoundException(String name) {
234 super(name);
235 }
236 }
237
238 /**
239 * Create a new Resources object on top of an existing set of assets in an
240 * AssetManager.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800241 *
242 * @param assets Previously created AssetManager.
243 * @param metrics Current display metrics to consider when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 * selecting/computing resource values.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800245 * @param config Desired device configuration to consider when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 * selecting/computing resource values (optional).
247 */
Romain Guy5d911c32012-04-12 16:25:17 -0700248 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
Wale Ogunwale60454db2015-01-23 16:05:07 -0800249 this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700250 }
251
252 /**
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700253 * Creates a new Resources object with CompatibilityInfo.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800254 *
255 * @param assets Previously created AssetManager.
256 * @param metrics Current display metrics to consider when
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700257 * selecting/computing resource values.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800258 * @param config Desired device configuration to consider when
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700259 * selecting/computing resource values (optional).
Craig Mautner48d0d182013-06-11 07:53:06 -0700260 * @param compatInfo this resource's compatibility info. Must not be null.
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700261 * @hide
262 */
Craig Mautner48d0d182013-06-11 07:53:06 -0700263 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
Wale Ogunwale60454db2015-01-23 16:05:07 -0800264 CompatibilityInfo compatInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 mAssets = assets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 mMetrics.setToDefaults();
Adam Lesinski79a8ffe2013-09-19 20:33:15 -0700267 if (compatInfo != null) {
268 mCompatibilityInfo = compatInfo;
269 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700270 updateConfiguration(config, metrics);
271 assets.ensureStringBlocks();
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700272 }
273
274 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 * Return a global shared Resources object that provides access to only
Wale Ogunwale60454db2015-01-23 16:05:07 -0800276 * system resources (no application resources), and is not configured for
277 * the current screen (can not use dimension units, does not change based
278 * on orientation, etc).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 */
280 public static Resources getSystem() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800281 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 Resources ret = mSystem;
283 if (ret == null) {
284 ret = new Resources();
285 mSystem = ret;
286 }
287
288 return ret;
289 }
290 }
291
292 /**
293 * Return the string value associated with a particular resource ID. The
294 * returned object will be a String if this is a plain string; it will be
295 * some other type of CharSequence if it is styled.
296 * {@more}
297 *
298 * @param id The desired resource identifier, as generated by the aapt
299 * tool. This integer encodes the package, type, and resource
300 * entry. The value 0 is an invalid identifier.
301 *
302 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
303 *
304 * @return CharSequence The string data associated with the resource, plus
305 * possibly styled text information.
306 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700307 public CharSequence getText(@StringRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 CharSequence res = mAssets.getResourceText(id);
309 if (res != null) {
310 return res;
311 }
312 throw new NotFoundException("String resource ID #0x"
313 + Integer.toHexString(id));
314 }
315
316 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800317 * Returns the character sequence necessary for grammatically correct pluralization
318 * of the given resource ID for the given quantity.
319 * Note that the character sequence is selected based solely on grammatical necessity,
320 * and that such rules differ between languages. Do not assume you know which string
321 * will be returned for a given quantity. See
322 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
323 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700324 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 * @param id The desired resource identifier, as generated by the aapt
326 * tool. This integer encodes the package, type, and resource
327 * entry. The value 0 is an invalid identifier.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700328 * @param quantity The number used to get the correct string for the current language's
329 * plural rules.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 *
331 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
332 *
333 * @return CharSequence The string data associated with the resource, plus
334 * possibly styled text information.
335 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700336 public CharSequence getQuantityText(@PluralsRes int id, int quantity)
337 throws NotFoundException {
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700338 NativePluralRules rule = getPluralRule();
339 CharSequence res = mAssets.getResourceBagText(id,
340 attrForQuantityCode(rule.quantityForInt(quantity)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 if (res != null) {
342 return res;
343 }
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700344 res = mAssets.getResourceBagText(id, ID_OTHER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 if (res != null) {
346 return res;
347 }
348 throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
349 + " quantity=" + quantity
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700350 + " item=" + stringForQuantityCode(rule.quantityForInt(quantity)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
352
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700353 private NativePluralRules getPluralRule() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800354 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 if (mPluralRule == null) {
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700356 mPluralRule = NativePluralRules.forLocale(mConfiguration.locale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 }
358 return mPluralRule;
359 }
360 }
361
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700362 private static int attrForQuantityCode(int quantityCode) {
363 switch (quantityCode) {
364 case NativePluralRules.ZERO: return 0x01000005;
365 case NativePluralRules.ONE: return 0x01000006;
366 case NativePluralRules.TWO: return 0x01000007;
367 case NativePluralRules.FEW: return 0x01000008;
368 case NativePluralRules.MANY: return 0x01000009;
369 default: return ID_OTHER;
370 }
371 }
372
373 private static String stringForQuantityCode(int quantityCode) {
374 switch (quantityCode) {
375 case NativePluralRules.ZERO: return "zero";
376 case NativePluralRules.ONE: return "one";
377 case NativePluralRules.TWO: return "two";
378 case NativePluralRules.FEW: return "few";
379 case NativePluralRules.MANY: return "many";
380 default: return "other";
381 }
382 }
383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 /**
385 * Return the string value associated with a particular resource ID. It
386 * will be stripped of any styled text information.
387 * {@more}
388 *
389 * @param id The desired resource identifier, as generated by the aapt
390 * tool. This integer encodes the package, type, and resource
391 * entry. The value 0 is an invalid identifier.
392 *
393 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
394 *
395 * @return String The string data associated with the resource,
396 * stripped of styled text information.
397 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700398 public String getString(@StringRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 CharSequence res = getText(id);
400 if (res != null) {
401 return res.toString();
402 }
403 throw new NotFoundException("String resource ID #0x"
404 + Integer.toHexString(id));
405 }
406
407
408 /**
409 * Return the string value associated with a particular resource ID,
410 * substituting the format arguments as defined in {@link java.util.Formatter}
411 * and {@link java.lang.String#format}. It will be stripped of any styled text
412 * information.
413 * {@more}
414 *
415 * @param id The desired resource identifier, as generated by the aapt
416 * tool. This integer encodes the package, type, and resource
417 * entry. The value 0 is an invalid identifier.
418 *
419 * @param formatArgs The format arguments that will be used for substitution.
420 *
421 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
422 *
423 * @return String The string data associated with the resource,
424 * stripped of styled text information.
425 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700426 public String getString(@StringRes int id, Object... formatArgs)
427 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 String raw = getString(id);
429 return String.format(mConfiguration.locale, raw, formatArgs);
430 }
431
432 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800433 * Formats the string necessary for grammatically correct pluralization
434 * of the given resource ID for the given quantity, using the given arguments.
435 * Note that the string is selected based solely on grammatical necessity,
436 * and that such rules differ between languages. Do not assume you know which string
437 * will be returned for a given quantity. See
438 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
439 * for more detail.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 *
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800441 * <p>Substitution of format arguments works as if using
442 * {@link java.util.Formatter} and {@link java.lang.String#format}.
443 * The resulting string will be stripped of any styled text information.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700444 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 * @param id The desired resource identifier, as generated by the aapt
446 * tool. This integer encodes the package, type, and resource
447 * entry. The value 0 is an invalid identifier.
448 * @param quantity The number used to get the correct string for the current language's
449 * plural rules.
450 * @param formatArgs The format arguments that will be used for substitution.
451 *
452 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
453 *
454 * @return String The string data associated with the resource,
455 * stripped of styled text information.
456 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700457 public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 throws NotFoundException {
459 String raw = getQuantityText(id, quantity).toString();
460 return String.format(mConfiguration.locale, raw, formatArgs);
461 }
462
463 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800464 * Returns the string necessary for grammatically correct pluralization
465 * of the given resource ID for the given quantity.
466 * Note that the string is selected based solely on grammatical necessity,
467 * and that such rules differ between languages. Do not assume you know which string
468 * will be returned for a given quantity. See
469 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
470 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700471 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 * @param id The desired resource identifier, as generated by the aapt
473 * tool. This integer encodes the package, type, and resource
474 * entry. The value 0 is an invalid identifier.
475 * @param quantity The number used to get the correct string for the current language's
476 * plural rules.
477 *
478 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
479 *
480 * @return String The string data associated with the resource,
481 * stripped of styled text information.
482 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700483 public String getQuantityString(@PluralsRes int id, int quantity)
484 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 return getQuantityText(id, quantity).toString();
486 }
487
488 /**
489 * Return the string value associated with a particular resource ID. The
490 * returned object will be a String if this is a plain string; it will be
491 * some other type of CharSequence if it is styled.
492 *
493 * @param id The desired resource identifier, as generated by the aapt
494 * tool. This integer encodes the package, type, and resource
495 * entry. The value 0 is an invalid identifier.
496 *
497 * @param def The default CharSequence to return.
498 *
499 * @return CharSequence The string data associated with the resource, plus
500 * possibly styled text information, or def if id is 0 or not found.
501 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700502 public CharSequence getText(@StringRes int id, CharSequence def) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
504 return res != null ? res : def;
505 }
506
507 /**
508 * Return the styled text array associated with a particular resource ID.
509 *
510 * @param id The desired resource identifier, as generated by the aapt
511 * tool. This integer encodes the package, type, and resource
512 * entry. The value 0 is an invalid identifier.
513 *
514 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
515 *
516 * @return The styled text array associated with the resource.
517 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700518 public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 CharSequence[] res = mAssets.getResourceTextArray(id);
520 if (res != null) {
521 return res;
522 }
523 throw new NotFoundException("Text array resource ID #0x"
524 + Integer.toHexString(id));
525 }
526
527 /**
528 * Return the string array associated with a particular resource ID.
529 *
530 * @param id The desired resource identifier, as generated by the aapt
531 * tool. This integer encodes the package, type, and resource
532 * entry. The value 0 is an invalid identifier.
533 *
534 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
535 *
536 * @return The string array associated with the resource.
537 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700538 public String[] getStringArray(@ArrayRes int id)
539 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 String[] res = mAssets.getResourceStringArray(id);
541 if (res != null) {
542 return res;
543 }
544 throw new NotFoundException("String array resource ID #0x"
545 + Integer.toHexString(id));
546 }
547
548 /**
549 * Return the int array associated with a particular resource ID.
550 *
551 * @param id The desired resource identifier, as generated by the aapt
552 * tool. This integer encodes the package, type, and resource
553 * entry. The value 0 is an invalid identifier.
554 *
555 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
556 *
557 * @return The int array associated with the resource.
558 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700559 public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 int[] res = mAssets.getArrayIntResource(id);
561 if (res != null) {
562 return res;
563 }
564 throw new NotFoundException("Int array resource ID #0x"
565 + Integer.toHexString(id));
566 }
567
568 /**
569 * Return an array of heterogeneous values.
570 *
571 * @param id The desired resource identifier, as generated by the aapt
572 * tool. This integer encodes the package, type, and resource
573 * entry. The value 0 is an invalid identifier.
574 *
575 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
576 *
577 * @return Returns a TypedArray holding an array of the array values.
578 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
579 * when done with it.
580 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700581 public TypedArray obtainTypedArray(@ArrayRes int id)
582 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 int len = mAssets.getArraySize(id);
584 if (len < 0) {
585 throw new NotFoundException("Array resource ID #0x"
586 + Integer.toHexString(id));
587 }
588
Alan Viverette52b999f2014-03-24 18:00:26 -0700589 TypedArray array = TypedArray.obtain(this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 array.mLength = mAssets.retrieveArray(id, array.mData);
591 array.mIndices[0] = 0;
592
593 return array;
594 }
595
596 /**
597 * Retrieve a dimensional for a particular resource ID. Unit
598 * conversions are based on the current {@link DisplayMetrics} associated
599 * with the resources.
600 *
601 * @param id The desired resource identifier, as generated by the aapt
602 * tool. This integer encodes the package, type, and resource
603 * entry. The value 0 is an invalid identifier.
604 *
605 * @return Resource dimension value multiplied by the appropriate
606 * metric.
607 *
608 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
609 *
610 * @see #getDimensionPixelOffset
611 * @see #getDimensionPixelSize
612 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700613 public float getDimension(@DimenRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800614 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800616 if (value == null) {
617 mTmpValue = value = new TypedValue();
618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 getValue(id, value, true);
620 if (value.type == TypedValue.TYPE_DIMENSION) {
621 return TypedValue.complexToDimension(value.data, mMetrics);
622 }
623 throw new NotFoundException(
624 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
625 + Integer.toHexString(value.type) + " is not valid");
626 }
627 }
628
629 /**
630 * Retrieve a dimensional for a particular resource ID for use
631 * as an offset in raw pixels. This is the same as
632 * {@link #getDimension}, except the returned value is converted to
633 * integer pixels for you. An offset conversion involves simply
634 * truncating the base value to an integer.
635 *
636 * @param id The desired resource identifier, as generated by the aapt
637 * tool. This integer encodes the package, type, and resource
638 * entry. The value 0 is an invalid identifier.
639 *
640 * @return Resource dimension value multiplied by the appropriate
641 * metric and truncated to integer pixels.
642 *
643 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
644 *
645 * @see #getDimension
646 * @see #getDimensionPixelSize
647 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700648 public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800649 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800651 if (value == null) {
652 mTmpValue = value = new TypedValue();
653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 getValue(id, value, true);
655 if (value.type == TypedValue.TYPE_DIMENSION) {
656 return TypedValue.complexToDimensionPixelOffset(
657 value.data, mMetrics);
658 }
659 throw new NotFoundException(
660 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
661 + Integer.toHexString(value.type) + " is not valid");
662 }
663 }
664
665 /**
666 * Retrieve a dimensional for a particular resource ID for use
667 * as a size in raw pixels. This is the same as
668 * {@link #getDimension}, except the returned value is converted to
669 * integer pixels for use as a size. A size conversion involves
670 * rounding the base value, and ensuring that a non-zero base value
671 * is at least one pixel in size.
672 *
673 * @param id The desired resource identifier, as generated by the aapt
674 * tool. This integer encodes the package, type, and resource
675 * entry. The value 0 is an invalid identifier.
676 *
677 * @return Resource dimension value multiplied by the appropriate
678 * metric and truncated to integer pixels.
679 *
680 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
681 *
682 * @see #getDimension
683 * @see #getDimensionPixelOffset
684 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700685 public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800686 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800688 if (value == null) {
689 mTmpValue = value = new TypedValue();
690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 getValue(id, value, true);
692 if (value.type == TypedValue.TYPE_DIMENSION) {
693 return TypedValue.complexToDimensionPixelSize(
694 value.data, mMetrics);
695 }
696 throw new NotFoundException(
697 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
698 + Integer.toHexString(value.type) + " is not valid");
699 }
700 }
701
702 /**
703 * Retrieve a fractional unit for a particular resource ID.
704 *
705 * @param id The desired resource identifier, as generated by the aapt
706 * tool. This integer encodes the package, type, and resource
707 * entry. The value 0 is an invalid identifier.
708 * @param base The base value of this fraction. In other words, a
709 * standard fraction is multiplied by this value.
710 * @param pbase The parent base value of this fraction. In other
711 * words, a parent fraction (nn%p) is multiplied by this
712 * value.
713 *
714 * @return Attribute fractional value multiplied by the appropriate
715 * base value.
716 *
717 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
718 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700719 public float getFraction(@FractionRes int id, int base, int pbase) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800720 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800722 if (value == null) {
723 mTmpValue = value = new TypedValue();
724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 getValue(id, value, true);
726 if (value.type == TypedValue.TYPE_FRACTION) {
727 return TypedValue.complexToFraction(value.data, base, pbase);
728 }
729 throw new NotFoundException(
730 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
731 + Integer.toHexString(value.type) + " is not valid");
732 }
733 }
734
735 /**
736 * Return a drawable object associated with a particular resource ID.
737 * Various types of objects will be returned depending on the underlying
738 * resource -- for example, a solid color, PNG image, scalable image, etc.
739 * The Drawable API hides these implementation details.
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700740 *
741 * <p class="note"><strong>Note:</strong> Prior to
742 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function
743 * would not correctly retrieve the final configuration density when
744 * the resource ID passed here is an alias to another Drawable resource.
745 * This means that if the density configuration of the alias resource
746 * is different than the actual resource, the density of the returned
747 * Drawable would be incorrect, resulting in bad scaling. To work
748 * around this, you can instead retrieve the Drawable through
749 * {@link TypedArray#getDrawable TypedArray.getDrawable}. Use
750 * {@link android.content.Context#obtainStyledAttributes(int[])
751 * Context.obtainStyledAttributes} with
752 * an array containing the resource ID of interest to create the TypedArray.</p>
753 *
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700754 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
755 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
756 * or {@link #getDrawable(int, Theme)} passing the desired theme.</p>
757 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * @param id The desired resource identifier, as generated by the aapt
759 * tool. This integer encodes the package, type, and resource
760 * entry. The value 0 is an invalid identifier.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 * @return Drawable An object that can be used to draw this resource.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800762 * @throws NotFoundException Throws NotFoundException if the given ID does
763 * not exist.
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700764 * @see #getDrawable(int, Theme)
Alan Viverettec10e3962014-12-02 14:58:08 -0800765 * @deprecated Use {@link #getDrawable(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 */
Alan Viverettec10e3962014-12-02 14:58:08 -0800767 @Deprecated
768 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700769 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
Alan Viverette34a14f962014-08-15 16:13:15 -0700770 final Drawable d = getDrawable(id, null);
Alan Viverette7e0aaae2014-11-24 11:27:09 -0800771 if (d != null && d.canApplyTheme()) {
Alan Viverette34a14f962014-08-15 16:13:15 -0700772 Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
773 + "attributes! Consider using Resources.getDrawable(int, Theme) or "
774 + "Context.getDrawable(int).", new RuntimeException());
775 }
776 return d;
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800777 }
778
779 /**
780 * Return a drawable object associated with a particular resource ID and
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700781 * styled for the specified theme. Various types of objects will be
782 * returned depending on the underlying resource -- for example, a solid
783 * color, PNG image, scalable image, etc.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800784 *
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.
Alan Viverette3b5c4272014-05-20 13:20:42 -0700788 * @param theme The theme used to style the drawable attributes, may be {@code null}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800789 * @return Drawable An object that can be used to draw this resource.
790 * @throws NotFoundException Throws NotFoundException if the given ID does
791 * not exist.
792 */
Alan Viverettec10e3962014-12-02 14:58:08 -0800793 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700794 public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800795 TypedValue value;
796 synchronized (mAccessLock) {
797 value = mTmpValue;
798 if (value == null) {
799 value = new TypedValue();
800 } else {
801 mTmpValue = null;
802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 getValue(id, value, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800805 final Drawable res = loadDrawable(value, id, theme);
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800806 synchronized (mAccessLock) {
807 if (mTmpValue == null) {
808 mTmpValue = value;
809 }
810 }
811 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 }
813
814 /**
Kenny Root55fc8502010-10-28 14:47:01 -0700815 * Return a drawable object associated with a particular resource ID for the
816 * given screen density in DPI. This will set the drawable's density to be
817 * the device's density multiplied by the ratio of actual drawable density
818 * to requested density. This allows the drawable to be scaled up to the
819 * correct size if needed. Various types of objects will be returned
820 * depending on the underlying resource -- for example, a solid color, PNG
821 * image, scalable image, etc. The Drawable API hides these implementation
822 * details.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800823 *
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700824 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
825 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
826 * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired
827 * theme.</p>
828 *
Kenny Root55fc8502010-10-28 14:47:01 -0700829 * @param id The desired resource identifier, as generated by the aapt tool.
830 * This integer encodes the package, type, and resource entry.
831 * The value 0 is an invalid identifier.
832 * @param density the desired screen density indicated by the resource as
833 * found in {@link DisplayMetrics}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800834 * @return Drawable An object that can be used to draw this resource.
Kenny Root55fc8502010-10-28 14:47:01 -0700835 * @throws NotFoundException Throws NotFoundException if the given ID does
836 * not exist.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800837 * @see #getDrawableForDensity(int, int, Theme)
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800838 * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
Kenny Root55fc8502010-10-28 14:47:01 -0700839 */
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800840 @Deprecated
841 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700842 public Drawable getDrawableForDensity(@DrawableRes int id, int density) throws NotFoundException {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800843 return getDrawableForDensity(id, density, null);
844 }
845
846 /**
847 * Return a drawable object associated with a particular resource ID for the
848 * given screen density in DPI and styled for the specified theme.
849 *
850 * @param id The desired resource identifier, as generated by the aapt tool.
851 * This integer encodes the package, type, and resource entry.
852 * The value 0 is an invalid identifier.
853 * @param density The desired screen density indicated by the resource as
854 * found in {@link DisplayMetrics}.
Alan Viverette3b5c4272014-05-20 13:20:42 -0700855 * @param theme The theme used to style the drawable attributes, may be {@code null}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800856 * @return Drawable An object that can be used to draw this resource.
857 * @throws NotFoundException Throws NotFoundException if the given ID does
858 * not exist.
859 */
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800860 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700861 public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800862 TypedValue value;
863 synchronized (mAccessLock) {
864 value = mTmpValue;
865 if (value == null) {
866 value = new TypedValue();
867 } else {
868 mTmpValue = null;
869 }
Kenny Root55fc8502010-10-28 14:47:01 -0700870 getValueForDensity(id, density, value, true);
871
872 /*
873 * Pretend the requested density is actually the display density. If
874 * the drawable returned is not the requested density, then force it
875 * to be scaled later by dividing its density by the ratio of
876 * requested density to actual device density. Drawables that have
877 * undefined density or no density don't need to be handled here.
878 */
879 if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
880 if (value.density == density) {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700881 value.density = mMetrics.densityDpi;
Kenny Root55fc8502010-10-28 14:47:01 -0700882 } else {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700883 value.density = (value.density * mMetrics.densityDpi) / density;
Kenny Root55fc8502010-10-28 14:47:01 -0700884 }
885 }
Kenny Root55fc8502010-10-28 14:47:01 -0700886 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800887
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800888 final Drawable res = loadDrawable(value, id, theme);
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800889 synchronized (mAccessLock) {
890 if (mTmpValue == null) {
891 mTmpValue = value;
892 }
893 }
894 return res;
Kenny Root55fc8502010-10-28 14:47:01 -0700895 }
896
897 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 * Return a movie object associated with the particular resource ID.
899 * @param id The desired resource identifier, as generated by the aapt
900 * tool. This integer encodes the package, type, and resource
901 * entry. The value 0 is an invalid identifier.
902 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
903 *
904 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700905 public Movie getMovie(@RawRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 InputStream is = openRawResource(id);
907 Movie movie = Movie.decodeStream(is);
908 try {
909 is.close();
910 }
911 catch (java.io.IOException e) {
912 // don't care, since the return value is valid
913 }
914 return movie;
915 }
916
917 /**
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800918 * Returns a color integer associated with a particular resource ID. If the
919 * resource holds a complex {@link ColorStateList}, then the default color
920 * from the set is returned.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 *
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 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800926 * @throws NotFoundException Throws NotFoundException if the given ID does
927 * not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800929 * @return A single color value in the form 0xAARRGGBB.
930 * @deprecated Use {@link #getColor(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 */
Tor Norbye80756e32015-03-02 09:39:27 -0800932 @ColorInt
Alan Viverette4a357cd2015-03-18 18:37:18 -0700933 @Deprecated
Tor Norbye7b9c9122013-05-30 16:48:33 -0700934 public int getColor(@ColorRes int id) throws NotFoundException {
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800935 return getColor(id, null);
936 }
937
938 /**
939 * Returns a themed color integer associated with a particular resource ID.
940 * If the resource holds a complex {@link ColorStateList}, then the default
941 * color from the set is returned.
942 *
943 * @param id The desired resource identifier, as generated by the aapt
944 * tool. This integer encodes the package, type, and resource
945 * entry. The value 0 is an invalid identifier.
946 * @param theme The theme used to style the color attributes, may be
947 * {@code null}.
948 *
949 * @throws NotFoundException Throws NotFoundException if the given ID does
950 * not exist.
951 *
952 * @return A single color value in the form 0xAARRGGBB.
953 */
Tor Norbye80756e32015-03-02 09:39:27 -0800954 @ColorInt
Tor Norbye7b9c9122013-05-30 16:48:33 -0700955 public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800956 TypedValue value;
957 synchronized (mAccessLock) {
958 value = mTmpValue;
959 if (value == null) {
960 value = new TypedValue();
961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 getValue(id, value, true);
963 if (value.type >= TypedValue.TYPE_FIRST_INT
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800964 && value.type <= TypedValue.TYPE_LAST_INT) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800965 mTmpValue = value;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 return value.data;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800967 } else if (value.type != TypedValue.TYPE_STRING) {
968 throw new NotFoundException(
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800969 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
970 + Integer.toHexString(value.type) + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 }
Dianne Hackborne5b50a62013-02-11 16:18:42 -0800972 mTmpValue = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800974
975 final ColorStateList csl = loadColorStateList(value, id, theme);
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800976 synchronized (mAccessLock) {
977 if (mTmpValue == null) {
978 mTmpValue = value;
979 }
980 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800981
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800982 return csl.getDefaultColor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 }
984
985 /**
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800986 * Returns a color state list associated with a particular resource ID. The
987 * resource may contain either a single raw color value or a complex
988 * {@link ColorStateList} holding multiple possible colors.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 *
990 * @param id The desired resource identifier of a {@link ColorStateList},
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800991 * as generated by the aapt tool. This integer encodes the
992 * package, type, and resource entry. The value 0 is an invalid
993 * identifier.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800995 * @throws NotFoundException Throws NotFoundException if the given ID does
996 * not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800998 * @return A ColorStateList object containing either a single solid color
999 * or multiple colors that can be selected based on a state.
1000 * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 */
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001002 @Nullable
Alan Viverette4a357cd2015-03-18 18:37:18 -07001003 @Deprecated
Tor Norbye7b9c9122013-05-30 16:48:33 -07001004 public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001005 final ColorStateList csl = getColorStateList(id, null);
1006 if (csl != null && csl.canApplyTheme()) {
1007 Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
1008 + "unresolved theme attributes! Consider using "
1009 + "Resources.getColorStateList(int, Theme) or "
1010 + "Context.getColorStateList(int).", new RuntimeException());
1011 }
1012 return csl;
1013 }
1014
1015 /**
1016 * Returns a themed color state list associated with a particular resource
1017 * ID. The resource may contain either a single raw color value or a
1018 * complex {@link ColorStateList} holding multiple possible colors.
1019 *
1020 * @param id The desired resource identifier of a {@link ColorStateList},
1021 * as generated by the aapt tool. This integer encodes the
1022 * package, type, and resource entry. The value 0 is an invalid
1023 * identifier.
1024 * @param theme The theme used to style the color attributes, may be
1025 * {@code null}.
1026 *
1027 * @throws NotFoundException Throws NotFoundException if the given ID does
1028 * not exist.
1029 *
1030 * @return A themed ColorStateList object containing either a single solid
1031 * color or multiple colors that can be selected based on a state.
1032 */
1033 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -07001034 public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001035 throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001036 TypedValue value;
1037 synchronized (mAccessLock) {
1038 value = mTmpValue;
1039 if (value == null) {
1040 value = new TypedValue();
1041 } else {
1042 mTmpValue = null;
1043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 getValue(id, value, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001046
1047 final ColorStateList res = loadColorStateList(value, id, theme);
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001048 synchronized (mAccessLock) {
1049 if (mTmpValue == null) {
1050 mTmpValue = value;
1051 }
1052 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001053
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001054 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056
1057 /**
1058 * Return a boolean associated with a particular resource ID. This can be
1059 * used with any integral resource value, and will return true if it is
1060 * non-zero.
1061 *
1062 * @param id The desired resource identifier, as generated by the aapt
1063 * tool. This integer encodes the package, type, and resource
1064 * entry. The value 0 is an invalid identifier.
1065 *
1066 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1067 *
1068 * @return Returns the boolean value contained in the resource.
1069 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001070 public boolean getBoolean(@BoolRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001071 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001073 if (value == null) {
1074 mTmpValue = value = new TypedValue();
1075 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 getValue(id, value, true);
1077 if (value.type >= TypedValue.TYPE_FIRST_INT
1078 && value.type <= TypedValue.TYPE_LAST_INT) {
1079 return value.data != 0;
1080 }
1081 throw new NotFoundException(
1082 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
1083 + Integer.toHexString(value.type) + " is not valid");
1084 }
1085 }
1086
1087 /**
1088 * Return an integer associated with a particular resource ID.
1089 *
1090 * @param id The desired resource identifier, as generated by the aapt
1091 * tool. This integer encodes the package, type, and resource
1092 * entry. The value 0 is an invalid identifier.
1093 *
1094 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1095 *
1096 * @return Returns the integer value contained in the resource.
1097 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001098 public int getInteger(@IntegerRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001099 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 TypedValue value = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001101 if (value == null) {
1102 mTmpValue = value = new TypedValue();
1103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 getValue(id, value, true);
1105 if (value.type >= TypedValue.TYPE_FIRST_INT
1106 && value.type <= TypedValue.TYPE_LAST_INT) {
1107 return value.data;
1108 }
1109 throw new NotFoundException(
1110 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
1111 + Integer.toHexString(value.type) + " is not valid");
1112 }
1113 }
1114
1115 /**
Alan Viveretteb1e1dbf2014-08-07 17:17:43 -07001116 * Retrieve a floating-point value for a particular resource ID.
1117 *
1118 * @param id The desired resource identifier, as generated by the aapt
1119 * tool. This integer encodes the package, type, and resource
1120 * entry. The value 0 is an invalid identifier.
1121 *
1122 * @return Returns the floating-point value contained in the resource.
1123 *
1124 * @throws NotFoundException Throws NotFoundException if the given ID does
1125 * not exist or is not a floating-point value.
1126 * @hide Pending API council approval.
1127 */
1128 public float getFloat(int id) {
1129 synchronized (mAccessLock) {
1130 TypedValue value = mTmpValue;
1131 if (value == null) {
1132 mTmpValue = value = new TypedValue();
1133 }
1134 getValue(id, value, true);
1135 if (value.type == TypedValue.TYPE_FLOAT) {
1136 return value.getFloat();
1137 }
1138 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) + " type #0x"
1139 + Integer.toHexString(value.type) + " is not valid");
1140 }
1141 }
1142
1143 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 * Return an XmlResourceParser through which you can read a view layout
1145 * description for the given resource ID. This parser has limited
1146 * functionality -- in particular, you can't change its input, and only
1147 * the high-level events are available.
1148 *
1149 * <p>This function is really a simple wrapper for calling
1150 * {@link #getXml} with a layout resource.
1151 *
1152 * @param id The desired resource identifier, as generated by the aapt
1153 * tool. This integer encodes the package, type, and resource
1154 * entry. The value 0 is an invalid identifier.
1155 *
1156 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1157 *
1158 * @return A new parser object through which you can read
1159 * the XML data.
1160 *
1161 * @see #getXml
1162 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001163 public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 return loadXmlResourceParser(id, "layout");
1165 }
1166
1167 /**
1168 * Return an XmlResourceParser through which you can read an animation
1169 * description for the given resource ID. This parser has limited
1170 * functionality -- in particular, you can't change its input, and only
1171 * the high-level events are available.
1172 *
1173 * <p>This function is really a simple wrapper for calling
1174 * {@link #getXml} with an animation resource.
1175 *
1176 * @param id The desired resource identifier, as generated by the aapt
1177 * tool. This integer encodes the package, type, and resource
1178 * entry. The value 0 is an invalid identifier.
1179 *
1180 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1181 *
1182 * @return A new parser object through which you can read
1183 * the XML data.
1184 *
1185 * @see #getXml
1186 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001187 public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 return loadXmlResourceParser(id, "anim");
1189 }
1190
1191 /**
1192 * Return an XmlResourceParser through which you can read a generic XML
1193 * resource for the given resource ID.
1194 *
1195 * <p>The XmlPullParser implementation returned here has some limited
1196 * functionality. In particular, you can't change its input, and only
1197 * high-level parsing events are available (since the document was
1198 * pre-parsed for you at build time, which involved merging text and
1199 * stripping comments).
1200 *
1201 * @param id The desired resource identifier, as generated by the aapt
1202 * tool. This integer encodes the package, type, and resource
1203 * entry. The value 0 is an invalid identifier.
1204 *
1205 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1206 *
1207 * @return A new parser object through which you can read
1208 * the XML data.
1209 *
1210 * @see android.util.AttributeSet
1211 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001212 public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 return loadXmlResourceParser(id, "xml");
1214 }
1215
1216 /**
1217 * Open a data stream for reading a raw resource. This can only be used
1218 * with resources whose value is the name of an asset files -- that is, it can be
1219 * used to open drawable, sound, and raw resources; it will fail on string
1220 * and color resources.
1221 *
1222 * @param id The resource identifier to open, as generated by the appt
1223 * tool.
1224 *
1225 * @return InputStream Access to the resource data.
1226 *
1227 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1228 *
1229 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001230 public InputStream openRawResource(@RawRes int id) throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001231 TypedValue value;
1232 synchronized (mAccessLock) {
1233 value = mTmpValue;
1234 if (value == null) {
1235 value = new TypedValue();
1236 } else {
1237 mTmpValue = null;
1238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001240 InputStream res = openRawResource(id, value);
1241 synchronized (mAccessLock) {
1242 if (mTmpValue == null) {
1243 mTmpValue = value;
1244 }
1245 }
1246 return res;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248
1249 /**
1250 * Open a data stream for reading a raw resource. This can only be used
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001251 * 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 -08001252 * used to open drawable, sound, and raw resources; it will fail on string
1253 * and color resources.
1254 *
1255 * @param id The resource identifier to open, as generated by the appt tool.
1256 * @param value The TypedValue object to hold the resource information.
1257 *
1258 * @return InputStream Access to the resource data.
1259 *
1260 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001262 public InputStream openRawResource(@RawRes int id, TypedValue value)
1263 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 getValue(id, value, true);
1265
1266 try {
1267 return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
1268 AssetManager.ACCESS_STREAMING);
1269 } catch (Exception e) {
1270 NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
1271 " from drawable resource ID #0x" + Integer.toHexString(id));
1272 rnf.initCause(e);
1273 throw rnf;
1274 }
1275 }
1276
1277 /**
1278 * Open a file descriptor for reading a raw resource. This can only be used
1279 * with resources whose value is the name of an asset files -- that is, it can be
1280 * used to open drawable, sound, and raw resources; it will fail on string
1281 * and color resources.
1282 *
1283 * <p>This function only works for resources that are stored in the package
1284 * as uncompressed data, which typically includes things like mp3 files
1285 * and png images.
1286 *
1287 * @param id The resource identifier to open, as generated by the appt
1288 * tool.
1289 *
1290 * @return AssetFileDescriptor A new file descriptor you can use to read
1291 * the resource. This includes the file descriptor itself, as well as the
1292 * offset and length of data where the resource appears in the file. A
1293 * null is returned if the file exists but is compressed.
1294 *
1295 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1296 *
1297 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001298 public AssetFileDescriptor openRawResourceFd(@RawRes int id)
1299 throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001300 TypedValue value;
1301 synchronized (mAccessLock) {
1302 value = mTmpValue;
1303 if (value == null) {
1304 value = new TypedValue();
1305 } else {
1306 mTmpValue = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001307 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001308 getValue(id, value, true);
1309 }
1310 try {
1311 return mAssets.openNonAssetFd(
1312 value.assetCookie, value.string.toString());
1313 } catch (Exception e) {
1314 NotFoundException rnf = new NotFoundException(
1315 "File " + value.string.toString()
1316 + " from drawable resource ID #0x"
1317 + Integer.toHexString(id));
1318 rnf.initCause(e);
1319 throw rnf;
1320 } finally {
1321 synchronized (mAccessLock) {
1322 if (mTmpValue == null) {
1323 mTmpValue = value;
1324 }
1325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001326 }
1327 }
1328
1329 /**
1330 * Return the raw data associated with a particular resource ID.
1331 *
1332 * @param id The desired resource identifier, as generated by the aapt
1333 * tool. This integer encodes the package, type, and resource
1334 * entry. The value 0 is an invalid identifier.
1335 * @param outValue Object in which to place the resource data.
1336 * @param resolveRefs If true, a resource that is a reference to another
1337 * resource will be followed so that you receive the
1338 * actual final resource data. If false, the TypedValue
1339 * will be filled in with the reference itself.
1340 *
1341 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1342 *
1343 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001344 public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 throws NotFoundException {
Kenny Root55fc8502010-10-28 14:47:01 -07001346 boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 if (found) {
1348 return;
1349 }
1350 throw new NotFoundException("Resource ID #0x"
1351 + Integer.toHexString(id));
1352 }
1353
1354 /**
Kenny Root55fc8502010-10-28 14:47:01 -07001355 * Get the raw value associated with a resource with associated density.
1356 *
1357 * @param id resource identifier
1358 * @param density density in DPI
1359 * @param resolveRefs If true, a resource that is a reference to another
1360 * resource will be followed so that you receive the actual final
1361 * resource data. If false, the TypedValue will be filled in with
1362 * the reference itself.
1363 * @throws NotFoundException Throws NotFoundException if the given ID does
1364 * not exist.
1365 * @see #getValue(String, TypedValue, boolean)
Kenny Root55fc8502010-10-28 14:47:01 -07001366 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001367 public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
1368 boolean resolveRefs) throws NotFoundException {
Kenny Root55fc8502010-10-28 14:47:01 -07001369 boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
1370 if (found) {
1371 return;
1372 }
1373 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
1374 }
1375
1376 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 * Return the raw data associated with a particular resource ID.
1378 * See getIdentifier() for information on how names are mapped to resource
1379 * IDs, and getString(int) for information on how string resources are
1380 * retrieved.
1381 *
1382 * <p>Note: use of this function is discouraged. It is much more
1383 * efficient to retrieve resources by identifier than by name.
1384 *
1385 * @param name The name of the desired resource. This is passed to
1386 * getIdentifier() with a default type of "string".
1387 * @param outValue Object in which to place the resource data.
1388 * @param resolveRefs If true, a resource that is a reference to another
1389 * resource will be followed so that you receive the
1390 * actual final resource data. If false, the TypedValue
1391 * will be filled in with the reference itself.
1392 *
1393 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1394 *
1395 */
1396 public void getValue(String name, TypedValue outValue, boolean resolveRefs)
1397 throws NotFoundException {
1398 int id = getIdentifier(name, "string", null);
1399 if (id != 0) {
1400 getValue(id, outValue, resolveRefs);
1401 return;
1402 }
1403 throw new NotFoundException("String resource name " + name);
1404 }
1405
1406 /**
1407 * This class holds the current attribute values for a particular theme.
1408 * In other words, a Theme is a set of values for resource attributes;
1409 * these are used in conjunction with {@link TypedArray}
1410 * to resolve the final value for an attribute.
1411 *
1412 * <p>The Theme's attributes come into play in two ways: (1) a styled
1413 * attribute can explicit reference a value in the theme through the
1414 * "?themeAttribute" syntax; (2) if no value has been defined for a
1415 * particular styled attribute, as a last resort we will try to find that
1416 * attribute's value in the Theme.
1417 *
1418 * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
1419 * retrieve XML attributes with style and theme information applied.
1420 */
1421 public final class Theme {
1422 /**
1423 * Place new attribute values into the theme. The style resource
1424 * specified by <var>resid</var> will be retrieved from this Theme's
1425 * resources, its values placed into the Theme object.
1426 *
1427 * <p>The semantics of this function depends on the <var>force</var>
1428 * argument: If false, only values that are not already defined in
1429 * the theme will be copied from the system resource; otherwise, if
1430 * any of the style's attributes are already defined in the theme, the
1431 * current values in the theme will be overwritten.
1432 *
Alan Viverette75257ce2014-05-22 19:31:38 -07001433 * @param resId The resource ID of a style resource from which to
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 * obtain attribute values.
1435 * @param force If true, values in the style resource will always be
1436 * used in the theme; otherwise, they will only be used
1437 * if not already defined in the theme.
1438 */
Alan Viverette75257ce2014-05-22 19:31:38 -07001439 public void applyStyle(int resId, boolean force) {
1440 AssetManager.applyThemeStyle(mTheme, resId, force);
Alan Viverette52b999f2014-03-24 18:00:26 -07001441
Alan Viverette75257ce2014-05-22 19:31:38 -07001442 mThemeResId = resId;
1443 mKey += Integer.toHexString(resId) + (force ? "! " : " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 }
1445
1446 /**
1447 * Set this theme to hold the same contents as the theme
1448 * <var>other</var>. If both of these themes are from the same
1449 * Resources object, they will be identical after this function
1450 * returns. If they are from different Resources, only the resources
1451 * they have in common will be set in this theme.
1452 *
1453 * @param other The existing Theme to copy from.
1454 */
1455 public void setTo(Theme other) {
1456 AssetManager.copyTheme(mTheme, other.mTheme);
Alan Viverette52b999f2014-03-24 18:00:26 -07001457
Alan Viverette52b999f2014-03-24 18:00:26 -07001458 mThemeResId = other.mThemeResId;
Alan Viverette75257ce2014-05-22 19:31:38 -07001459 mKey = other.mKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
1461
1462 /**
John Spurlock330dd532012-12-18 12:03:11 -05001463 * Return a TypedArray holding the values defined by
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 * <var>Theme</var> which are listed in <var>attrs</var>.
1465 *
Scott Main183bf112012-08-13 19:12:13 -07001466 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1467 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 *
1469 * @param attrs The desired attributes.
1470 *
1471 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1472 *
1473 * @return Returns a TypedArray holding an array of the attribute values.
1474 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1475 * when done with it.
1476 *
1477 * @see Resources#obtainAttributes
1478 * @see #obtainStyledAttributes(int, int[])
1479 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1480 */
Tor Norbyec91531a2015-04-01 17:41:55 -07001481 public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001482 final int len = attrs.length;
Alan Viverette52b999f2014-03-24 18:00:26 -07001483 final TypedArray array = TypedArray.obtain(Resources.this, len);
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001484 array.mTheme = this;
Alan Viverette52b999f2014-03-24 18:00:26 -07001485 AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 return array;
1487 }
1488
1489 /**
John Spurlock330dd532012-12-18 12:03:11 -05001490 * Return a TypedArray holding the values defined by the style
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 * resource <var>resid</var> which are listed in <var>attrs</var>.
1492 *
Scott Main183bf112012-08-13 19:12:13 -07001493 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1494 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 *
1496 * @param resid The desired style resource.
1497 * @param attrs The desired attributes in the style.
1498 *
1499 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1500 *
1501 * @return Returns a TypedArray holding an array of the attribute values.
1502 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1503 * when done with it.
1504 *
1505 * @see Resources#obtainAttributes
1506 * @see #obtainStyledAttributes(int[])
1507 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1508 */
Tor Norbyec91531a2015-04-01 17:41:55 -07001509 public TypedArray obtainStyledAttributes(@StyleRes int resid, @StyleableRes int[] attrs)
1510 throws NotFoundException {
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001511 final int len = attrs.length;
Alan Viverette52b999f2014-03-24 18:00:26 -07001512 final TypedArray array = TypedArray.obtain(Resources.this, len);
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001513 array.mTheme = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 if (false) {
1515 int[] data = array.mData;
1516
1517 System.out.println("**********************************************************");
1518 System.out.println("**********************************************************");
1519 System.out.println("**********************************************************");
1520 System.out.println("Attributes:");
1521 String s = " Attrs:";
1522 int i;
1523 for (i=0; i<attrs.length; i++) {
1524 s = s + " 0x" + Integer.toHexString(attrs[i]);
1525 }
1526 System.out.println(s);
1527 s = " Found:";
1528 TypedValue value = new TypedValue();
1529 for (i=0; i<attrs.length; i++) {
1530 int d = i*AssetManager.STYLE_NUM_ENTRIES;
1531 value.type = data[d+AssetManager.STYLE_TYPE];
1532 value.data = data[d+AssetManager.STYLE_DATA];
1533 value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1534 value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1535 s = s + " 0x" + Integer.toHexString(attrs[i])
1536 + "=" + value;
1537 }
1538 System.out.println(s);
1539 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001540 AssetManager.applyStyle(mTheme, 0, resid, 0, attrs, array.mData, array.mIndices);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 return array;
1542 }
1543
1544 /**
John Spurlock330dd532012-12-18 12:03:11 -05001545 * Return a TypedArray holding the attribute values in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 * <var>set</var>
1547 * that are listed in <var>attrs</var>. In addition, if the given
1548 * AttributeSet specifies a style class (through the "style" attribute),
1549 * that style will be applied on top of the base attributes it defines.
1550 *
Scott Main183bf112012-08-13 19:12:13 -07001551 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1552 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 *
1554 * <p>When determining the final value of a particular attribute, there
1555 * are four inputs that come into play:</p>
1556 *
1557 * <ol>
1558 * <li> Any attribute values in the given AttributeSet.
1559 * <li> The style resource specified in the AttributeSet (named
1560 * "style").
1561 * <li> The default style specified by <var>defStyleAttr</var> and
1562 * <var>defStyleRes</var>
1563 * <li> The base values in this theme.
1564 * </ol>
1565 *
1566 * <p>Each of these inputs is considered in-order, with the first listed
1567 * taking precedence over the following ones. In other words, if in the
1568 * AttributeSet you have supplied <code>&lt;Button
1569 * textColor="#ff000000"&gt;</code>, then the button's text will
1570 * <em>always</em> be black, regardless of what is specified in any of
1571 * the styles.
1572 *
1573 * @param set The base set of attribute values. May be null.
1574 * @param attrs The desired attributes to be retrieved.
1575 * @param defStyleAttr An attribute in the current theme that contains a
1576 * reference to a style resource that supplies
John Spurlock330dd532012-12-18 12:03:11 -05001577 * defaults values for the TypedArray. Can be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 * 0 to not look for defaults.
1579 * @param defStyleRes A resource identifier of a style resource that
John Spurlock330dd532012-12-18 12:03:11 -05001580 * supplies default values for the TypedArray,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 * used only if defStyleAttr is 0 or can not be found
1582 * in the theme. Can be 0 to not look for defaults.
1583 *
1584 * @return Returns a TypedArray holding an array of the attribute values.
1585 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1586 * when done with it.
1587 *
1588 * @see Resources#obtainAttributes
1589 * @see #obtainStyledAttributes(int[])
1590 * @see #obtainStyledAttributes(int, int[])
1591 */
1592 public TypedArray obtainStyledAttributes(AttributeSet set,
Tor Norbyec91531a2015-04-01 17:41:55 -07001593 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001594 final int len = attrs.length;
Alan Viverette52b999f2014-03-24 18:00:26 -07001595 final TypedArray array = TypedArray.obtain(Resources.this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596
1597 // XXX note that for now we only work with compiled XML files.
1598 // To support generic XML files we will need to manually parse
1599 // out the attributes from the XML file (applying type information
1600 // contained in the resources and such).
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001601 final XmlBlock.Parser parser = (XmlBlock.Parser)set;
1602 AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1603 parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001605 array.mTheme = this;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 array.mXml = parser;
1607
1608 if (false) {
1609 int[] data = array.mData;
1610
1611 System.out.println("Attributes:");
1612 String s = " Attrs:";
1613 int i;
1614 for (i=0; i<set.getAttributeCount(); i++) {
1615 s = s + " " + set.getAttributeName(i);
1616 int id = set.getAttributeNameResource(i);
1617 if (id != 0) {
1618 s = s + "(0x" + Integer.toHexString(id) + ")";
1619 }
1620 s = s + "=" + set.getAttributeValue(i);
1621 }
1622 System.out.println(s);
1623 s = " Found:";
1624 TypedValue value = new TypedValue();
1625 for (i=0; i<attrs.length; i++) {
1626 int d = i*AssetManager.STYLE_NUM_ENTRIES;
1627 value.type = data[d+AssetManager.STYLE_TYPE];
1628 value.data = data[d+AssetManager.STYLE_DATA];
1629 value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
1630 value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
1631 s = s + " 0x" + Integer.toHexString(attrs[i])
1632 + "=" + value;
1633 }
1634 System.out.println(s);
1635 }
1636
1637 return array;
1638 }
1639
1640 /**
Alan Viverette52b999f2014-03-24 18:00:26 -07001641 * Retrieve the values for a set of attributes in the Theme. The
1642 * contents of the typed array are ultimately filled in by
1643 * {@link Resources#getValue}.
1644 *
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001645 * @param values The base set of attribute values, must be equal in
1646 * length to {@code attrs}. All values must be of type
1647 * {@link TypedValue#TYPE_ATTRIBUTE}.
Alan Viverette52b999f2014-03-24 18:00:26 -07001648 * @param attrs The desired attributes to be retrieved.
Alan Viverette52b999f2014-03-24 18:00:26 -07001649 * @return Returns a TypedArray holding an array of the attribute
1650 * values. Be sure to call {@link TypedArray#recycle()}
1651 * when done with it.
1652 * @hide
1653 */
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001654 @NonNull
1655 public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
Alan Viverette52b999f2014-03-24 18:00:26 -07001656 final int len = attrs.length;
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001657 if (values == null || len != values.length) {
Alan Viverette52b999f2014-03-24 18:00:26 -07001658 throw new IllegalArgumentException(
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001659 "Base attribute values must the same length as attrs");
Alan Viverette52b999f2014-03-24 18:00:26 -07001660 }
1661
1662 final TypedArray array = TypedArray.obtain(Resources.this, len);
Alan Viverette0cfb8772014-05-14 17:40:53 -07001663 AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
Alan Viverette52b999f2014-03-24 18:00:26 -07001664 array.mTheme = this;
1665 array.mXml = null;
1666
1667 return array;
1668 }
1669
1670 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 * Retrieve the value of an attribute in the Theme. The contents of
1672 * <var>outValue</var> are ultimately filled in by
1673 * {@link Resources#getValue}.
1674 *
1675 * @param resid The resource identifier of the desired theme
1676 * attribute.
1677 * @param outValue Filled in with the ultimate resource value supplied
1678 * by the attribute.
1679 * @param resolveRefs If true, resource references will be walked; if
1680 * false, <var>outValue</var> may be a
1681 * TYPE_REFERENCE. In either case, it will never
1682 * be a TYPE_ATTRIBUTE.
1683 *
1684 * @return boolean Returns true if the attribute was found and
1685 * <var>outValue</var> is valid, else false.
1686 */
Alan Viverette52b999f2014-03-24 18:00:26 -07001687 public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1689 if (false) {
1690 System.out.println(
1691 "resolveAttribute #" + Integer.toHexString(resid)
1692 + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type)
1693 + ", data=0x" + Integer.toHexString(outValue.data));
1694 }
1695 return got;
1696 }
1697
1698 /**
Jon Miranda042ad632014-09-03 17:57:35 -07001699 * Gets all of the attribute ids associated with this {@link Theme}. For debugging only.
1700 *
1701 * @return The int array containing attribute ids associated with this {@link Theme}.
1702 * @hide
1703 */
1704 public int[] getAllAttributes() {
1705 return mAssets.getStyleAttributes(getAppliedStyleResId());
1706 }
1707
1708 /**
Alan Viverette52b999f2014-03-24 18:00:26 -07001709 * Returns the resources to which this theme belongs.
1710 *
1711 * @return Resources to which this theme belongs.
1712 */
1713 public Resources getResources() {
1714 return Resources.this;
1715 }
1716
1717 /**
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001718 * Return a drawable object associated with a particular resource ID
1719 * and styled for the Theme.
1720 *
1721 * @param id The desired resource identifier, as generated by the aapt
1722 * tool. This integer encodes the package, type, and resource
1723 * entry. The value 0 is an invalid identifier.
1724 * @return Drawable An object that can be used to draw this resource.
1725 * @throws NotFoundException Throws NotFoundException if the given ID
1726 * does not exist.
1727 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001728 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001729 return Resources.this.getDrawable(id, this);
1730 }
1731
1732 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 * Print contents of this theme out to the log. For debugging only.
1734 *
1735 * @param priority The log priority to use.
1736 * @param tag The log tag to use.
1737 * @param prefix Text to prefix each line printed.
1738 */
1739 public void dump(int priority, String tag, String prefix) {
1740 AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1741 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001742
1743 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 protected void finalize() throws Throwable {
1745 super.finalize();
1746 mAssets.releaseTheme(mTheme);
1747 }
1748
1749 /*package*/ Theme() {
1750 mAssets = Resources.this.mAssets;
1751 mTheme = mAssets.createTheme();
1752 }
1753
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001754 @SuppressWarnings("hiding")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 private final AssetManager mAssets;
Ashok Bhat896043d2014-01-17 16:02:38 +00001756 private final long mTheme;
Alan Viverette52b999f2014-03-24 18:00:26 -07001757
Alan Viverette351f0c12014-03-28 15:25:27 -07001758 /** Resource identifier for the theme. */
Alan Viverette52b999f2014-03-24 18:00:26 -07001759 private int mThemeResId = 0;
Deepanshu Guptabfec73c2014-03-11 18:02:44 -07001760
Alan Viverette75257ce2014-05-22 19:31:38 -07001761 /** Unique key for the series of styles applied to this theme. */
1762 private String mKey = "";
1763
Deepanshu Guptabfec73c2014-03-11 18:02:44 -07001764 // Needed by layoutlib.
1765 /*package*/ long getNativeTheme() {
1766 return mTheme;
1767 }
1768
1769 /*package*/ int getAppliedStyleResId() {
1770 return mThemeResId;
1771 }
Alan Viverette75257ce2014-05-22 19:31:38 -07001772
1773 /*package*/ String getKey() {
1774 return mKey;
1775 }
Jon Miranda836c0a82014-08-11 12:32:26 -07001776
1777 private String getResourceNameFromHexString(String hexString) {
1778 return getResourceName(Integer.parseInt(hexString, 16));
1779 }
1780
1781 /**
1782 * Parses {@link #mKey} and returns a String array that holds pairs of adjacent Theme data:
1783 * resource name followed by whether or not it was forced, as specified by
1784 * {@link #applyStyle(int, boolean)}.
1785 *
1786 * @hide
1787 */
1788 @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
1789 public String[] getTheme() {
1790 String[] themeData = mKey.split(" ");
1791 String[] themes = new String[themeData.length * 2];
1792 String theme;
1793 boolean forced;
1794
1795 for (int i = 0, j = themeData.length - 1; i < themes.length; i += 2, --j) {
1796 theme = themeData[j];
1797 forced = theme.endsWith("!");
1798 themes[i] = forced ?
1799 getResourceNameFromHexString(theme.substring(0, theme.length() - 1)) :
1800 getResourceNameFromHexString(theme);
1801 themes[i + 1] = forced ? "forced" : "not forced";
1802 }
1803 return themes;
1804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 }
1806
1807 /**
1808 * Generate a new Theme object for this set of Resources. It initially
1809 * starts out empty.
Jon Miranda836c0a82014-08-11 12:32:26 -07001810 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 * @return Theme The newly created Theme container.
1812 */
1813 public final Theme newTheme() {
1814 return new Theme();
1815 }
1816
1817 /**
1818 * Retrieve a set of basic attribute values from an AttributeSet, not
1819 * performing styling of them using a theme and/or style resources.
Jon Miranda836c0a82014-08-11 12:32:26 -07001820 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 * @param set The current attribute values to retrieve.
1822 * @param attrs The specific attributes to be retrieved.
1823 * @return Returns a TypedArray holding an array of the attribute values.
1824 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1825 * when done with it.
1826 *
1827 * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1828 */
1829 public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1830 int len = attrs.length;
Alan Viverette52b999f2014-03-24 18:00:26 -07001831 TypedArray array = TypedArray.obtain(this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832
1833 // XXX note that for now we only work with compiled XML files.
1834 // To support generic XML files we will need to manually parse
1835 // out the attributes from the XML file (applying type information
1836 // contained in the resources and such).
1837 XmlBlock.Parser parser = (XmlBlock.Parser)set;
1838 mAssets.retrieveAttributes(parser.mParseState, attrs,
1839 array.mData, array.mIndices);
1840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 array.mXml = parser;
1842
1843 return array;
1844 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07001845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 /**
1847 * Store the newly updated configuration.
1848 */
1849 public void updateConfiguration(Configuration config,
1850 DisplayMetrics metrics) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001851 updateConfiguration(config, metrics, null);
1852 }
1853
1854 /**
1855 * @hide
1856 */
1857 public void updateConfiguration(Configuration config,
1858 DisplayMetrics metrics, CompatibilityInfo compat) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001859 synchronized (mAccessLock) {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001860 if (false) {
1861 Slog.i(TAG, "**** Updating config of " + this + ": old config is "
1862 + mConfiguration + " old compat is " + mCompatibilityInfo);
1863 Slog.i(TAG, "**** Updating config of " + this + ": new config is "
1864 + config + " new compat is " + compat);
1865 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001866 if (compat != null) {
1867 mCompatibilityInfo = compat;
1868 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 if (metrics != null) {
1870 mMetrics.setTo(metrics);
1871 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001872 // NOTE: We should re-arrange this code to create a Display
1873 // with the CompatibilityInfo that is used everywhere we deal
1874 // with the display in relation to this app, rather than
1875 // doing the conversion here. This impl should be okay because
1876 // we make sure to return a compatible display in the places
1877 // where there are public APIs to retrieve the display... but
1878 // it would be cleaner and more maintainble to just be
1879 // consistently dealing with a compatible display everywhere in
1880 // the framework.
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07001881 mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
1882
Alan Viverettea8636c92015-03-27 10:44:39 -07001883 final int configChanges = calcConfigChanges(config);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001884 if (mConfiguration.locale == null) {
1885 mConfiguration.locale = Locale.getDefault();
Fabrice Di Meglio5f797992012-06-15 20:16:41 -07001886 mConfiguration.setLayoutDirection(mConfiguration.locale);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001887 }
Dianne Hackborn756220b2012-08-14 16:45:30 -07001888 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
1889 mMetrics.densityDpi = mConfiguration.densityDpi;
1890 mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1891 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001892 mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 String locale = null;
1895 if (mConfiguration.locale != null) {
Deepanshu Gupta5cd9dde2014-07-14 15:50:49 -07001896 locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
Alan Viverettea8636c92015-03-27 10:44:39 -07001898
1899 final int width, height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 if (mMetrics.widthPixels >= mMetrics.heightPixels) {
1901 width = mMetrics.widthPixels;
1902 height = mMetrics.heightPixels;
1903 } else {
1904 //noinspection SuspiciousNameCombination
1905 width = mMetrics.heightPixels;
1906 //noinspection SuspiciousNameCombination
1907 height = mMetrics.widthPixels;
1908 }
Alan Viverettea8636c92015-03-27 10:44:39 -07001909
1910 final int keyboardHidden;
1911 if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
1912 && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
Alan Viverettea8636c92015-03-27 10:44:39 -07001914 } else {
1915 keyboardHidden = mConfiguration.keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
Alan Viverettea8636c92015-03-27 10:44:39 -07001917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001918 mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
1919 locale, mConfiguration.orientation,
1920 mConfiguration.touchscreen,
Dianne Hackborn908aecc2012-07-31 16:37:34 -07001921 mConfiguration.densityDpi, mConfiguration.keyboard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 keyboardHidden, mConfiguration.navigation, width, height,
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001923 mConfiguration.smallestScreenWidthDp,
Dianne Hackbornebff8f92011-05-12 18:07:47 -07001924 mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08001925 mConfiguration.screenLayout, mConfiguration.uiMode,
1926 Build.VERSION.RESOURCES_SDK_INT);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001927
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001928 if (DEBUG_CONFIG) {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001929 Slog.i(TAG, "**** Updating config of " + this + ": final config is " + mConfiguration
1930 + " final compat is " + mCompatibilityInfo);
1931 }
1932
Alan Viverette52b999f2014-03-24 18:00:26 -07001933 clearDrawableCachesLocked(mDrawableCache, configChanges);
1934 clearDrawableCachesLocked(mColorDrawableCache, configChanges);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001935 mColorStateListCache.onConfigurationChange(configChanges);
Yigit Boyard422dc32014-09-25 12:23:35 -07001936 mAnimatorCache.onConfigurationChange(configChanges);
1937 mStateListAnimatorCache.onConfigurationChange(configChanges);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 flushLayoutCache();
1940 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001941 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 if (mPluralRule != null) {
Elliott Hughes1ad636c2010-07-01 16:51:48 -07001943 mPluralRule = NativePluralRules.forLocale(config.locale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001944 }
1945 }
1946 }
1947
Yigit Boyard422dc32014-09-25 12:23:35 -07001948 /**
1949 * Called by ConfigurationBoundResourceCacheTest via reflection.
1950 */
1951 private int calcConfigChanges(Configuration config) {
1952 int configChanges = 0xfffffff;
1953 if (config != null) {
1954 mTmpConfig.setTo(config);
1955 int density = config.densityDpi;
1956 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
1957 density = mMetrics.noncompatDensityDpi;
1958 }
1959
1960 mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
1961
1962 if (mTmpConfig.locale == null) {
1963 mTmpConfig.locale = Locale.getDefault();
1964 mTmpConfig.setLayoutDirection(mTmpConfig.locale);
1965 }
1966 configChanges = mConfiguration.updateFrom(mTmpConfig);
1967 configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
1968 }
1969 return configChanges;
1970 }
1971
Alan Viverette52b999f2014-03-24 18:00:26 -07001972 private void clearDrawableCachesLocked(
Alan Viverette75257ce2014-05-22 19:31:38 -07001973 ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
1974 int configChanges) {
Alan Viverette52b999f2014-03-24 18:00:26 -07001975 final int N = caches.size();
1976 for (int i = 0; i < N; i++) {
1977 clearDrawableCacheLocked(caches.valueAt(i), configChanges);
1978 }
1979 }
1980
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001981 private void clearDrawableCacheLocked(
Alan Viverette52b999f2014-03-24 18:00:26 -07001982 LongSparseArray<WeakReference<ConstantState>> cache, int configChanges) {
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001983 if (DEBUG_CONFIG) {
1984 Log.d(TAG, "Cleaning up drawables config changes: 0x"
1985 + Integer.toHexString(configChanges));
1986 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001987 final int N = cache.size();
1988 for (int i = 0; i < N; i++) {
1989 final WeakReference<ConstantState> ref = cache.valueAt(i);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001990 if (ref != null) {
Alan Viverette52b999f2014-03-24 18:00:26 -07001991 final ConstantState cs = ref.get();
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001992 if (cs != null) {
1993 if (Configuration.needNewResources(
1994 configChanges, cs.getChangingConfigurations())) {
1995 if (DEBUG_CONFIG) {
1996 Log.d(TAG, "FLUSHING #0x"
Alan Viverette75257ce2014-05-22 19:31:38 -07001997 + Long.toHexString(cache.keyAt(i))
Masanori Oginoc7d9d272010-07-10 12:10:41 +09001998 + " / " + cs + " with changes: 0x"
1999 + Integer.toHexString(cs.getChangingConfigurations()));
2000 }
2001 cache.setValueAt(i, null);
2002 } else if (DEBUG_CONFIG) {
2003 Log.d(TAG, "(Keeping #0x"
2004 + Long.toHexString(cache.keyAt(i))
2005 + " / " + cs + " with changes: 0x"
2006 + Integer.toHexString(cs.getChangingConfigurations())
2007 + ")");
2008 }
2009 }
2010 }
2011 }
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002012 }
2013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 /**
Narayan Kamath21fc8ba2014-03-05 18:42:23 +00002015 * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
2016 * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
2017 *
2018 * All released versions of android prior to "L" used the deprecated language
2019 * tags, so we will need to support them for backwards compatibility.
2020 *
2021 * Note that this conversion needs to take place *after* the call to
2022 * {@code toLanguageTag} because that will convert all the deprecated codes to
2023 * the new ones, even if they're set manually.
2024 */
2025 private static String adjustLanguageTag(String languageTag) {
2026 final int separator = languageTag.indexOf('-');
2027 final String language;
2028 final String remainder;
2029
2030 if (separator == -1) {
2031 language = languageTag;
2032 remainder = "";
2033 } else {
2034 language = languageTag.substring(0, separator);
2035 remainder = languageTag.substring(separator);
2036 }
2037
Narayan Kamath4c6ce232014-07-18 16:09:36 +01002038 return Locale.adjustLanguageCode(language) + remainder;
Narayan Kamath21fc8ba2014-03-05 18:42:23 +00002039 }
2040
2041 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 * Update the system resources configuration if they have previously
2043 * been initialized.
2044 *
2045 * @hide
2046 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -04002047 public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
2048 CompatibilityInfo compat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 if (mSystem != null) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04002050 mSystem.updateConfiguration(config, metrics, compat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 //Log.i(TAG, "Updated system resources " + mSystem
2052 // + ": " + mSystem.getConfiguration());
2053 }
2054 }
2055
2056 /**
2057 * Return the current display metrics that are in effect for this resource
2058 * object. The returned object should be treated as read-only.
2059 *
2060 * @return The resource's current display metrics.
2061 */
2062 public DisplayMetrics getDisplayMetrics() {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002063 if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
2064 + "x" + mMetrics.heightPixels + " " + mMetrics.density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 return mMetrics;
2066 }
2067
2068 /**
2069 * Return the current configuration that is in effect for this resource
2070 * object. The returned object should be treated as read-only.
2071 *
2072 * @return The resource's current configuration.
2073 */
2074 public Configuration getConfiguration() {
2075 return mConfiguration;
2076 }
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002077
2078 /**
2079 * Return the compatibility mode information for the application.
2080 * The returned object should be treated as read-only.
2081 *
Dianne Hackborn3904d032011-05-27 12:09:11 -07002082 * @return compatibility info.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002083 * @hide
2084 */
2085 public CompatibilityInfo getCompatibilityInfo() {
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07002086 return mCompatibilityInfo;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088
2089 /**
Dianne Hackborna53b8282009-07-17 11:13:48 -07002090 * This is just for testing.
2091 * @hide
2092 */
2093 public void setCompatibilityInfo(CompatibilityInfo ci) {
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07002094 if (ci != null) {
2095 mCompatibilityInfo = ci;
2096 updateConfiguration(mConfiguration, mMetrics);
2097 }
Dianne Hackborna53b8282009-07-17 11:13:48 -07002098 }
2099
2100 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 * Return a resource identifier for the given resource name. A fully
2102 * qualified resource name is of the form "package:type/entry". The first
2103 * two components (package and type) are optional if defType and
2104 * defPackage, respectively, are specified here.
2105 *
2106 * <p>Note: use of this function is discouraged. It is much more
2107 * efficient to retrieve resources by identifier than by name.
2108 *
2109 * @param name The name of the desired resource.
2110 * @param defType Optional default resource type to find, if "type/" is
2111 * not included in the name. Can be null to require an
2112 * explicit type.
2113 * @param defPackage Optional default package to find, if "package:" is
2114 * not included in the name. Can be null to require an
2115 * explicit package.
2116 *
2117 * @return int The associated resource identifier. Returns 0 if no such
2118 * resource was found. (0 is not a valid resource ID.)
2119 */
2120 public int getIdentifier(String name, String defType, String defPackage) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002121 if (name == null) {
2122 throw new NullPointerException("name is null");
2123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 try {
2125 return Integer.parseInt(name);
2126 } catch (Exception e) {
2127 // Ignore
2128 }
2129 return mAssets.getResourceIdentifier(name, defType, defPackage);
2130 }
2131
2132 /**
Jeff Sharkey47b50332013-03-15 14:46:46 -07002133 * Return true if given resource identifier includes a package.
2134 *
2135 * @hide
2136 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002137 public static boolean resourceHasPackage(@AnyRes int resid) {
Jeff Sharkey47b50332013-03-15 14:46:46 -07002138 return (resid >>> 24) != 0;
2139 }
2140
2141 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 * Return the full name for a given resource identifier. This name is
2143 * a single string of the form "package:type/entry".
2144 *
2145 * @param resid The resource identifier whose name is to be retrieved.
2146 *
2147 * @return A string holding the name of the resource.
2148 *
2149 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2150 *
2151 * @see #getResourcePackageName
2152 * @see #getResourceTypeName
2153 * @see #getResourceEntryName
2154 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002155 public String getResourceName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 String str = mAssets.getResourceName(resid);
2157 if (str != null) return str;
2158 throw new NotFoundException("Unable to find resource ID #0x"
2159 + Integer.toHexString(resid));
2160 }
2161
2162 /**
2163 * Return the package name for a given resource identifier.
2164 *
2165 * @param resid The resource identifier whose package name is to be
2166 * retrieved.
2167 *
2168 * @return A string holding the package name of the resource.
2169 *
2170 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2171 *
2172 * @see #getResourceName
2173 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002174 public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 String str = mAssets.getResourcePackageName(resid);
2176 if (str != null) return str;
2177 throw new NotFoundException("Unable to find resource ID #0x"
2178 + Integer.toHexString(resid));
2179 }
2180
2181 /**
2182 * Return the type name for a given resource identifier.
2183 *
2184 * @param resid The resource identifier whose type name is to be
2185 * retrieved.
2186 *
2187 * @return A string holding the type name of the resource.
2188 *
2189 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2190 *
2191 * @see #getResourceName
2192 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002193 public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 String str = mAssets.getResourceTypeName(resid);
2195 if (str != null) return str;
2196 throw new NotFoundException("Unable to find resource ID #0x"
2197 + Integer.toHexString(resid));
2198 }
2199
2200 /**
2201 * Return the entry name for a given resource identifier.
2202 *
2203 * @param resid The resource identifier whose entry name is to be
2204 * retrieved.
2205 *
2206 * @return A string holding the entry name of the resource.
2207 *
2208 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2209 *
2210 * @see #getResourceName
2211 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002212 public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 String str = mAssets.getResourceEntryName(resid);
2214 if (str != null) return str;
2215 throw new NotFoundException("Unable to find resource ID #0x"
2216 + Integer.toHexString(resid));
2217 }
2218
2219 /**
2220 * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
2221 * an XML file. You call this when you are at the parent tag of the
Dianne Hackborndef15372010-08-15 12:43:52 -07002222 * 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 -08002223 * This will call {@link #parseBundleExtra} for each extra tag encountered.
2224 *
2225 * @param parser The parser from which to retrieve the extras.
2226 * @param outBundle A Bundle in which to place all parsed extras.
2227 * @throws XmlPullParserException
2228 * @throws IOException
2229 */
2230 public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
2231 throws XmlPullParserException, IOException {
2232 int outerDepth = parser.getDepth();
2233 int type;
2234 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2235 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2236 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2237 continue;
2238 }
2239
2240 String nodeName = parser.getName();
2241 if (nodeName.equals("extra")) {
2242 parseBundleExtra("extra", parser, outBundle);
2243 XmlUtils.skipCurrentTag(parser);
2244
2245 } else {
2246 XmlUtils.skipCurrentTag(parser);
2247 }
2248 }
2249 }
2250
2251 /**
2252 * Parse a name/value pair out of an XML tag holding that data. The
2253 * AttributeSet must be holding the data defined by
2254 * {@link android.R.styleable#Extra}. The following value types are supported:
2255 * <ul>
2256 * <li> {@link TypedValue#TYPE_STRING}:
2257 * {@link Bundle#putCharSequence Bundle.putCharSequence()}
2258 * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
2259 * {@link Bundle#putCharSequence Bundle.putBoolean()}
2260 * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
2261 * {@link Bundle#putCharSequence Bundle.putBoolean()}
2262 * <li> {@link TypedValue#TYPE_FLOAT}:
2263 * {@link Bundle#putCharSequence Bundle.putFloat()}
2264 * </ul>
2265 *
2266 * @param tagName The name of the tag these attributes come from; this is
2267 * only used for reporting error messages.
2268 * @param attrs The attributes from which to retrieve the name/value pair.
2269 * @param outBundle The Bundle in which to place the parsed value.
2270 * @throws XmlPullParserException If the attributes are not valid.
2271 */
2272 public void parseBundleExtra(String tagName, AttributeSet attrs,
2273 Bundle outBundle) throws XmlPullParserException {
2274 TypedArray sa = obtainAttributes(attrs,
2275 com.android.internal.R.styleable.Extra);
2276
2277 String name = sa.getString(
2278 com.android.internal.R.styleable.Extra_name);
2279 if (name == null) {
2280 sa.recycle();
2281 throw new XmlPullParserException("<" + tagName
2282 + "> requires an android:name attribute at "
2283 + attrs.getPositionDescription());
2284 }
2285
2286 TypedValue v = sa.peekValue(
2287 com.android.internal.R.styleable.Extra_value);
2288 if (v != null) {
2289 if (v.type == TypedValue.TYPE_STRING) {
2290 CharSequence cs = v.coerceToString();
2291 outBundle.putCharSequence(name, cs);
2292 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2293 outBundle.putBoolean(name, v.data != 0);
2294 } else if (v.type >= TypedValue.TYPE_FIRST_INT
2295 && v.type <= TypedValue.TYPE_LAST_INT) {
2296 outBundle.putInt(name, v.data);
2297 } else if (v.type == TypedValue.TYPE_FLOAT) {
2298 outBundle.putFloat(name, v.getFloat());
2299 } else {
2300 sa.recycle();
2301 throw new XmlPullParserException("<" + tagName
2302 + "> only supports string, integer, float, color, and boolean at "
2303 + attrs.getPositionDescription());
2304 }
2305 } else {
2306 sa.recycle();
2307 throw new XmlPullParserException("<" + tagName
2308 + "> requires an android:value or android:resource attribute at "
2309 + attrs.getPositionDescription());
2310 }
2311
2312 sa.recycle();
2313 }
2314
2315 /**
2316 * Retrieve underlying AssetManager storage for these resources.
2317 */
2318 public final AssetManager getAssets() {
2319 return mAssets;
2320 }
2321
2322 /**
2323 * Call this to remove all cached loaded layout resources from the
2324 * Resources object. Only intended for use with performance testing
2325 * tools.
2326 */
2327 public final void flushLayoutCache() {
2328 synchronized (mCachedXmlBlockIds) {
2329 // First see if this block is in our cache.
2330 final int num = mCachedXmlBlockIds.length;
2331 for (int i=0; i<num; i++) {
2332 mCachedXmlBlockIds[i] = -0;
2333 XmlBlock oldBlock = mCachedXmlBlocks[i];
2334 if (oldBlock != null) {
2335 oldBlock.close();
2336 }
2337 mCachedXmlBlocks[i] = null;
2338 }
2339 }
2340 }
2341
2342 /**
2343 * Start preloading of resource data using this Resources object. Only
2344 * for use by the zygote process for loading common system resources.
2345 * {@hide}
2346 */
2347 public final void startPreloading() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002348 synchronized (sSync) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002349 if (sPreloaded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 throw new IllegalStateException("Resources already preloaded");
2351 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002352 sPreloaded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353 mPreloading = true;
Dianne Hackborndde331c2012-08-03 14:01:57 -07002354 sPreloadedDensity = DisplayMetrics.DENSITY_DEVICE;
2355 mConfiguration.densityDpi = sPreloadedDensity;
2356 updateConfiguration(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002357 }
2358 }
2359
2360 /**
2361 * Called by zygote when it is done preloading resources, to change back
2362 * to normal Resources operation.
2363 */
2364 public final void finishPreloading() {
2365 if (mPreloading) {
2366 mPreloading = false;
2367 flushLayoutCache();
2368 }
2369 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002370
Romain Guy3b748a42013-04-17 18:54:38 -07002371 /**
2372 * @hide
2373 */
Alan Viverette52b999f2014-03-24 18:00:26 -07002374 public LongSparseArray<ConstantState> getPreloadedDrawables() {
Romain Guy3b748a42013-04-17 18:54:38 -07002375 return sPreloadedDrawables[0];
2376 }
2377
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002378 private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
2379 int resourceId, String name) {
2380 // We allow preloading of resources even if they vary by font scale (which
2381 // doesn't impact resource selection) or density (which we handle specially by
2382 // simply turning off all preloading), as well as any other configs specified
2383 // by the caller.
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002384 if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002385 ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002386 String resName;
2387 try {
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002388 resName = getResourceName(resourceId);
Dianne Hackborndde331c2012-08-03 14:01:57 -07002389 } catch (NotFoundException e) {
2390 resName = "?";
2391 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002392 // This should never happen in production, so we should log a
2393 // warning even if we're not debugging.
Dianne Hackborndde331c2012-08-03 14:01:57 -07002394 Log.w(TAG, "Preloaded " + name + " resource #0x"
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002395 + Integer.toHexString(resourceId)
Dianne Hackborndde331c2012-08-03 14:01:57 -07002396 + " (" + resName + ") that varies with configuration!!");
2397 return false;
2398 }
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -07002399 if (TRACE_FOR_PRELOAD) {
2400 String resName;
2401 try {
2402 resName = getResourceName(resourceId);
2403 } catch (NotFoundException e) {
2404 resName = "?";
2405 }
2406 Log.w(TAG, "Preloading " + name + " resource #0x"
2407 + Integer.toHexString(resourceId)
2408 + " (" + resName + ")");
2409 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002410 return true;
2411 }
2412
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002413 /*package*/ Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 if (TRACE_FOR_PRELOAD) {
2415 // Log only framework resources
2416 if ((id >>> 24) == 0x1) {
2417 final String name = getResourceName(id);
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002418 if (name != null) {
2419 Log.d("PreloadDrawable", name);
2420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002421 }
2422 }
2423
Alan Viverette52b999f2014-03-24 18:00:26 -07002424 final boolean isColorDrawable;
Alan Viverette75257ce2014-05-22 19:31:38 -07002425 final ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches;
Alan Viverette52b999f2014-03-24 18:00:26 -07002426 final long key;
2427 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
2428 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002429 isColorDrawable = true;
Alan Viverette52b999f2014-03-24 18:00:26 -07002430 caches = mColorDrawableCache;
2431 key = value.data;
2432 } else {
2433 isColorDrawable = false;
2434 caches = mDrawableCache;
2435 key = (((long) value.assetCookie) << 32) | value.data;
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002436 }
Romain Guy5f49c302012-09-06 16:33:31 -07002437
Alan Viverette52b999f2014-03-24 18:00:26 -07002438 // First, check whether we have a cached version of this drawable
Alan Viveretteb6f91522014-06-03 12:52:25 -07002439 // that was inflated against the specified theme.
Alan Viverette52b999f2014-03-24 18:00:26 -07002440 if (!mPreloading) {
2441 final Drawable cachedDrawable = getCachedDrawable(caches, key, theme);
2442 if (cachedDrawable != null) {
2443 return cachedDrawable;
2444 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002446
Alan Viverette4325f8e2015-04-01 15:00:30 -07002447 // Next, check preloaded drawables. These may contain unresolved theme
2448 // attributes.
Alan Viverette52b999f2014-03-24 18:00:26 -07002449 final ConstantState cs;
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002450 if (isColorDrawable) {
2451 cs = sPreloadedColorDrawables.get(key);
2452 } else {
2453 cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
2454 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002455
Alan Viverette4325f8e2015-04-01 15:00:30 -07002456 Drawable dr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 if (cs != null) {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002458 dr = cs.newDrawable(this);
Alan Viverette52b999f2014-03-24 18:00:26 -07002459 } else if (isColorDrawable) {
2460 dr = new ColorDrawable(value.data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 } else {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002462 dr = loadDrawableForCookie(value, id, null);
2463 }
2464
2465 // Determine if the drawable has unresolved theme attributes. If it
2466 // does, we'll need to apply a theme and store it in a theme-specific
2467 // cache.
2468 final String cacheKey;
2469 if (!dr.canApplyTheme()) {
2470 cacheKey = CACHE_NOT_THEMED;
2471 } else if (theme == null) {
2472 cacheKey = CACHE_NULL_THEME;
2473 } else {
2474 cacheKey = theme.getKey();
2475 dr = dr.mutate();
2476 dr.applyTheme(theme);
2477 dr.clearMutated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 }
2479
Alan Viveretteb6f91522014-06-03 12:52:25 -07002480 // If we were able to obtain a drawable, store it in the appropriate
Alan Viverette4325f8e2015-04-01 15:00:30 -07002481 // cache: preload, not themed, null theme, or theme-specific.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 if (dr != null) {
2483 dr.setChangingConfigurations(value.changingConfigurations);
Alan Viverette4325f8e2015-04-01 15:00:30 -07002484 cacheDrawable(value, isColorDrawable, caches, cacheKey, key, dr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002485 }
2486
2487 return dr;
2488 }
2489
Alan Viverette4325f8e2015-04-01 15:00:30 -07002490 private void cacheDrawable(TypedValue value, boolean isColorDrawable,
Alan Viverette75257ce2014-05-22 19:31:38 -07002491 ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
Alan Viverette4325f8e2015-04-01 15:00:30 -07002492 String cacheKey, long key, Drawable dr) {
Alan Viverette52b999f2014-03-24 18:00:26 -07002493 final ConstantState cs = dr.getConstantState();
2494 if (cs == null) {
2495 return;
2496 }
2497
Alan Viverette52b999f2014-03-24 18:00:26 -07002498 if (mPreloading) {
Alan Viverette52b999f2014-03-24 18:00:26 -07002499 final int changingConfigs = cs.getChangingConfigurations();
2500 if (isColorDrawable) {
2501 if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
2502 sPreloadedColorDrawables.put(key, cs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002504 } else {
2505 if (verifyPreloadConfig(
2506 changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
2507 if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
2508 // If this resource does not vary based on layout direction,
2509 // we can put it in all of the preload maps.
2510 sPreloadedDrawables[0].put(key, cs);
2511 sPreloadedDrawables[1].put(key, cs);
2512 } else {
2513 // Otherwise, only in the layout dir we loaded it for.
2514 sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
2515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 }
2517 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002518 } else {
2519 synchronized (mAccessLock) {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002520 LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(cacheKey);
Alan Viverette75257ce2014-05-22 19:31:38 -07002521 if (themedCache == null) {
Alan Viverette9267fda2014-12-08 12:20:01 -08002522 // Clean out the caches before we add more. This shouldn't
2523 // happen very often.
2524 pruneCaches(caches);
Alan Viverettea8636c92015-03-27 10:44:39 -07002525 themedCache = new LongSparseArray<>(1);
Alan Viverette4325f8e2015-04-01 15:00:30 -07002526 caches.put(cacheKey, themedCache);
Alan Viverette75257ce2014-05-22 19:31:38 -07002527 }
Alan Viverettea8636c92015-03-27 10:44:39 -07002528 themedCache.put(key, new WeakReference<>(cs));
Alan Viverette52b999f2014-03-24 18:00:26 -07002529 }
2530 }
2531 }
2532
2533 /**
Alan Viverette9267fda2014-12-08 12:20:01 -08002534 * Prunes empty caches from the cache map.
2535 *
2536 * @param caches The map of caches to prune.
2537 */
2538 private void pruneCaches(ArrayMap<String,
2539 LongSparseArray<WeakReference<ConstantState>>> caches) {
2540 final int N = caches.size();
2541 for (int i = N - 1; i >= 0; i--) {
Jeff Sharkeyc4ec5b62014-12-17 10:24:13 -08002542 final LongSparseArray<WeakReference<ConstantState>> cache = caches.valueAt(i);
Alan Viverette9267fda2014-12-08 12:20:01 -08002543 if (pruneCache(cache)) {
2544 caches.removeAt(i);
2545 }
2546 }
2547 }
2548
2549 /**
2550 * Prunes obsolete weak references from a cache, returning {@code true} if
2551 * the cache is empty and should be removed.
2552 *
2553 * @param cache The cache of weak references to prune.
2554 * @return {@code true} if the cache is empty and should be removed.
2555 */
2556 private boolean pruneCache(LongSparseArray<WeakReference<ConstantState>> cache) {
2557 final int N = cache.size();
2558 for (int i = N - 1; i >= 0; i--) {
2559 final WeakReference entry = cache.valueAt(i);
Alan Viveretted6ebb3a2015-01-05 11:09:29 -08002560 if (entry == null || entry.get() == null) {
Alan Viverette9267fda2014-12-08 12:20:01 -08002561 cache.removeAt(i);
2562 }
2563 }
2564 return cache.size() == 0;
2565 }
2566
2567 /**
Alan Viverette52b999f2014-03-24 18:00:26 -07002568 * Loads a drawable from XML or resources stream.
2569 */
2570 private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
2571 if (value.string == null) {
Alan Viverette0810b632014-05-01 14:42:56 -07002572 throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002573 + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
Alan Viverette52b999f2014-03-24 18:00:26 -07002574 }
2575
2576 final String file = value.string.toString();
2577
2578 if (TRACE_FOR_MISS_PRELOAD) {
2579 // Log only framework resources
2580 if ((id >>> 24) == 0x1) {
2581 final String name = getResourceName(id);
2582 if (name != null) {
2583 Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
2584 + ": " + name + " at " + file);
2585 }
2586 }
2587 }
2588
2589 if (DEBUG_LOAD) {
2590 Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
2591 }
2592
2593 final Drawable dr;
2594
2595 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
2596 try {
2597 if (file.endsWith(".xml")) {
2598 final XmlResourceParser rp = loadXmlResourceParser(
2599 file, id, value.assetCookie, "drawable");
Alan Viverette6dbe51b2014-06-02 16:39:04 -07002600 dr = Drawable.createFromXml(this, rp, theme);
Alan Viverette52b999f2014-03-24 18:00:26 -07002601 rp.close();
2602 } else {
2603 final InputStream is = mAssets.openNonAsset(
2604 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
Alan Viverette6dbe51b2014-06-02 16:39:04 -07002605 dr = Drawable.createFromResourceStream(this, value, is, file, null);
Alan Viverette52b999f2014-03-24 18:00:26 -07002606 is.close();
2607 }
2608 } catch (Exception e) {
2609 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2610 final NotFoundException rnf = new NotFoundException(
2611 "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
2612 rnf.initCause(e);
2613 throw rnf;
2614 }
2615 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2616
2617 return dr;
2618 }
2619
Alan Viverette75257ce2014-05-22 19:31:38 -07002620 private Drawable getCachedDrawable(
2621 ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
2622 long key, Theme theme) {
Alan Viverette52b999f2014-03-24 18:00:26 -07002623 synchronized (mAccessLock) {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002624 // First search theme-agnostic cache.
2625 final Drawable unthemedDrawable = getCachedDrawableLocked(
2626 caches, key, CACHE_NOT_THEMED);
2627 if (unthemedDrawable != null) {
2628 return unthemedDrawable;
Alan Viverette52b999f2014-03-24 18:00:26 -07002629 }
2630
Alan Viverette4325f8e2015-04-01 15:00:30 -07002631 // Next search theme-specific cache.
2632 final String themeKey = theme != null ? theme.getKey() : CACHE_NULL_THEME;
2633 return getCachedDrawableLocked(caches, key, themeKey);
Alan Viverette52b999f2014-03-24 18:00:26 -07002634 }
2635 }
2636
Alan Viverette4325f8e2015-04-01 15:00:30 -07002637 private Drawable getCachedDrawableLocked(
2638 ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
2639 long key, String themeKey) {
2640 final LongSparseArray<WeakReference<ConstantState>> cache = caches.get(themeKey);
2641 if (cache != null) {
2642 final ConstantState entry = getConstantStateLocked(cache, key);
Alan Viverette52b999f2014-03-24 18:00:26 -07002643 if (entry != null) {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002644 return entry.newDrawable(this);
Alan Viverette52b999f2014-03-24 18:00:26 -07002645 }
2646 }
2647 return null;
2648 }
2649
Alan Viverette4325f8e2015-04-01 15:00:30 -07002650 private ConstantState getConstantStateLocked(
Alan Viverette52b999f2014-03-24 18:00:26 -07002651 LongSparseArray<WeakReference<ConstantState>> drawableCache, long key) {
Alan Viverette4325f8e2015-04-01 15:00:30 -07002652 final WeakReference<ConstantState> wr = drawableCache.get(key);
2653 if (wr != null) {
2654 final ConstantState entry = wr.get();
2655 if (entry != null) {
2656 return entry;
2657 } else {
2658 // Our entry has been purged.
2659 drawableCache.delete(key);
2660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002661 }
2662 return null;
2663 }
2664
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002665 @Nullable
2666 ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 throws NotFoundException {
2668 if (TRACE_FOR_PRELOAD) {
2669 // Log only framework resources
2670 if ((id >>> 24) == 0x1) {
2671 final String name = getResourceName(id);
2672 if (name != null) android.util.Log.d("PreloadColorStateList", name);
2673 }
2674 }
2675
Romain Guy5d911c32012-04-12 16:25:17 -07002676 final long key = (((long) value.assetCookie) << 32) | value.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002677
2678 ColorStateList csl;
2679
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002680 // Handle inline color definitions.
2681 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
2682 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002683 final android.content.res.ConstantState<ColorStateList> factory =
2684 sPreloadedColorStateLists.get(key);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002685 if (factory != null) {
2686 return factory.newInstance();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 }
2688
2689 csl = ColorStateList.valueOf(value.data);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002692 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2693 "color")) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002694 sPreloadedColorStateLists.put(key, csl.getConstantState());
Dianne Hackborndde331c2012-08-03 14:01:57 -07002695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002696 }
2697
2698 return csl;
2699 }
2700
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002701 final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
2702
2703 csl = cache.get(key, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 if (csl != null) {
2705 return csl;
2706 }
2707
Alan Viverettee0f95f32015-04-01 13:10:18 -07002708 final android.content.res.ConstantState<ColorStateList> factory =
2709 sPreloadedColorStateLists.get(key);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002710 if (factory != null) {
2711 csl = factory.newInstance(this, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002712 }
2713
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002714 if (csl == null) {
2715 csl = loadColorStateListForCookie(value, id, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002716 }
2717
2718 if (csl != null) {
2719 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002720 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2721 "color")) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002722 sPreloadedColorStateLists.put(key, csl.getConstantState());
Dianne Hackborndde331c2012-08-03 14:01:57 -07002723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 } else {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002725 cache.put(key, theme, csl.getConstantState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 }
2727 }
2728
2729 return csl;
2730 }
2731
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002732 private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
2733 if (value.string == null) {
Alan Viverette6bbb47b2015-01-05 18:12:44 -08002734 throw new UnsupportedOperationException(
2735 "Can't convert to color state list: type=0x" + value.type);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002736 }
2737
2738 final String file = value.string.toString();
2739
2740 if (TRACE_FOR_MISS_PRELOAD) {
2741 // Log only framework resources
2742 if ((id >>> 24) == 0x1) {
2743 final String name = getResourceName(id);
2744 if (name != null) {
2745 Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
2746 + ": " + name + " at " + file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002747 }
2748 }
2749 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002750
2751 if (DEBUG_LOAD) {
2752 Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
2753 }
2754
2755 final ColorStateList csl;
2756
2757 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
2758 if (file.endsWith(".xml")) {
2759 try {
2760 final XmlResourceParser rp = loadXmlResourceParser(
2761 file, id, value.assetCookie, "colorstatelist");
2762 csl = ColorStateList.createFromXml(this, rp, theme);
2763 rp.close();
2764 } catch (Exception e) {
2765 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2766 final NotFoundException rnf = new NotFoundException(
2767 "File " + file + " from color state list resource ID #0x"
2768 + Integer.toHexString(id));
2769 rnf.initCause(e);
2770 throw rnf;
2771 }
2772 } else {
2773 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2774 throw new NotFoundException(
2775 "File " + file + " from drawable resource ID #0x"
2776 + Integer.toHexString(id) + ": .xml extension required");
2777 }
2778 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2779
2780 return csl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 }
2782
2783 /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
2784 throws NotFoundException {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002785 synchronized (mAccessLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 TypedValue value = mTmpValue;
Dianne Hackborne5b50a62013-02-11 16:18:42 -08002787 if (value == null) {
2788 mTmpValue = value = new TypedValue();
2789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 getValue(id, value, true);
2791 if (value.type == TypedValue.TYPE_STRING) {
2792 return loadXmlResourceParser(value.string.toString(), id,
2793 value.assetCookie, type);
2794 }
2795 throw new NotFoundException(
2796 "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
2797 + Integer.toHexString(value.type) + " is not valid");
2798 }
2799 }
2800
2801 /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
2802 int assetCookie, String type) throws NotFoundException {
2803 if (id != 0) {
2804 try {
2805 // These may be compiled...
2806 synchronized (mCachedXmlBlockIds) {
2807 // First see if this block is in our cache.
2808 final int num = mCachedXmlBlockIds.length;
2809 for (int i=0; i<num; i++) {
2810 if (mCachedXmlBlockIds[i] == id) {
2811 //System.out.println("**** REUSING XML BLOCK! id="
2812 // + id + ", index=" + i);
2813 return mCachedXmlBlocks[i].newParser();
2814 }
2815 }
2816
2817 // Not in the cache, create a new block and put it at
2818 // the next slot in the cache.
2819 XmlBlock block = mAssets.openXmlBlockAsset(
2820 assetCookie, file);
2821 if (block != null) {
2822 int pos = mLastCachedXmlBlockIndex+1;
2823 if (pos >= num) pos = 0;
2824 mLastCachedXmlBlockIndex = pos;
2825 XmlBlock oldBlock = mCachedXmlBlocks[pos];
2826 if (oldBlock != null) {
2827 oldBlock.close();
2828 }
2829 mCachedXmlBlockIds[pos] = id;
2830 mCachedXmlBlocks[pos] = block;
2831 //System.out.println("**** CACHING NEW XML BLOCK! id="
2832 // + id + ", index=" + pos);
2833 return block.newParser();
2834 }
2835 }
2836 } catch (Exception e) {
2837 NotFoundException rnf = new NotFoundException(
2838 "File " + file + " from xml type " + type + " resource ID #0x"
2839 + Integer.toHexString(id));
2840 rnf.initCause(e);
2841 throw rnf;
2842 }
2843 }
2844
2845 throw new NotFoundException(
2846 "File " + file + " from xml type " + type + " resource ID #0x"
2847 + Integer.toHexString(id));
2848 }
2849
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002850 /**
2851 * Obtains styled attributes from the theme, if available, or unstyled
2852 * resources if the theme is null.
2853 *
2854 * @hide
2855 */
2856 public static TypedArray obtainAttributes(
2857 Resources res, Theme theme, AttributeSet set, int[] attrs) {
2858 if (theme == null) {
2859 return res.obtainAttributes(set, attrs);
2860 }
2861 return theme.obtainStyledAttributes(set, attrs, 0, 0);
2862 }
2863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 private Resources() {
2865 mAssets = AssetManager.getSystem();
2866 // NOTE: Intentionally leaving this uninitialized (all values set
2867 // to zero), so that anyone who tries to do something that requires
2868 // metrics will get a very wrong value.
2869 mConfiguration.setToDefaults();
2870 mMetrics.setToDefaults();
2871 updateConfiguration(null, null);
2872 mAssets.ensureStringBlocks();
2873 }
2874}