blob: 7b56eebf34acd8c6d7d859a2d9bc84fb288d227b [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
Alan Viverette45c4bbb2015-01-05 14:59:19 -080019import android.animation.Animator;
20import android.animation.StateListAnimator;
Tor Norbye7b9c9122013-05-30 16:48:33 -070021import android.annotation.AnimRes;
22import android.annotation.AnyRes;
23import android.annotation.ArrayRes;
Roozbeh Pournader47571c72015-09-01 14:07:04 -070024import android.annotation.AttrRes;
Tor Norbye7b9c9122013-05-30 16:48:33 -070025import android.annotation.BoolRes;
Roozbeh Pournader47571c72015-09-01 14:07:04 -070026import android.annotation.ColorInt;
Tor Norbye7b9c9122013-05-30 16:48:33 -070027import android.annotation.ColorRes;
28import android.annotation.DimenRes;
29import android.annotation.DrawableRes;
30import android.annotation.FractionRes;
31import android.annotation.IntegerRes;
32import android.annotation.LayoutRes;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080033import android.annotation.NonNull;
Alan Viverette3b5c4272014-05-20 13:20:42 -070034import android.annotation.Nullable;
Tor Norbye7b9c9122013-05-30 16:48:33 -070035import android.annotation.PluralsRes;
36import android.annotation.RawRes;
37import android.annotation.StringRes;
Roozbeh Pournader47571c72015-09-01 14:07:04 -070038import android.annotation.StyleRes;
39import android.annotation.StyleableRes;
Tor Norbye7b9c9122013-05-30 16:48:33 -070040import android.annotation.XmlRes;
Dianne Hackbornebff8f92011-05-12 18:07:47 -070041import android.content.pm.ActivityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.graphics.Movie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.graphics.drawable.ColorDrawable;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080044import android.graphics.drawable.Drawable;
Masanori Oginoc7d9d272010-07-10 12:10:41 +090045import android.graphics.drawable.Drawable.ConstantState;
Roozbeh Pournader47571c72015-09-01 14:07:04 -070046import android.graphics.drawable.DrawableInflater;
47import android.icu.text.PluralRules;
Dianne Hackborn3b3e1452009-09-24 19:22:12 -070048import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Bundle;
Romain Guy3b748a42013-04-17 18:54:38 -070050import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.util.AttributeSet;
52import android.util.DisplayMetrics;
Roozbeh Pournader47571c72015-09-01 14:07:04 -070053import android.util.LocaleList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.util.Log;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080055import android.util.LongSparseArray;
56import android.util.Pools.SynchronizedPool;
Dianne Hackborn2f0b1752011-05-31 17:59:49 -070057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.util.TypedValue;
Alan Viverette45c4bbb2015-01-05 14:59:19 -080059import android.view.ViewDebug;
Siva Velusamy0d857b92015-04-22 10:23:56 -070060import android.view.ViewHierarchyEncoder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Roozbeh Pournader47571c72015-09-01 14:07:04 -070062import com.android.internal.util.GrowingArrayUtils;
63import com.android.internal.util.XmlUtils;
64
65import org.xmlpull.v1.XmlPullParser;
66import org.xmlpull.v1.XmlPullParserException;
67
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import java.io.IOException;
69import java.io.InputStream;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080070import java.util.Locale;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72/**
73 * Class for accessing an application's resources. This sits on top of the
Scott Mainf4f05b82011-01-07 14:38:23 -080074 * asset manager of the application (accessible through {@link #getAssets}) and
75 * provides a high-level API for getting typed data from the assets.
76 *
77 * <p>The Android resource system keeps track of all non-code assets associated with an
78 * application. You can use this class to access your application's resources. You can generally
79 * acquire the {@link android.content.res.Resources} instance associated with your application
80 * with {@link android.content.Context#getResources getResources()}.</p>
81 *
82 * <p>The Android SDK tools compile your application's resources into the application binary
83 * at build time. To use a resource, you must install it correctly in the source tree (inside
84 * your project's {@code res/} directory) and build your application. As part of the build
85 * process, the SDK tools generate symbols for each resource, which you can use in your application
86 * code to access the resources.</p>
87 *
88 * <p>Using application resources makes it easy to update various characteristics of your
89 * application without modifying code, and&mdash;by providing sets of alternative
90 * resources&mdash;enables you to optimize your application for a variety of device configurations
91 * (such as for different languages and screen sizes). This is an important aspect of developing
92 * Android applications that are compatible on different types of devices.</p>
93 *
94 * <p>For more information about using resources, see the documentation about <a
95 * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 */
97public class Resources {
98 static final String TAG = "Resources";
Alan Viverette562a6a82014-01-31 11:07:29 -080099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final boolean DEBUG_LOAD = false;
101 private static final boolean DEBUG_CONFIG = false;
102 private static final boolean TRACE_FOR_PRELOAD = false;
Dianne Hackborn9b44aae2011-09-02 19:17:16 -0700103 private static final boolean TRACE_FOR_MISS_PRELOAD = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Alan Viverette562a6a82014-01-31 11:07:29 -0800105 private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
106 ActivityInfo.CONFIG_LAYOUT_DIRECTION);
107
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700108 private static final int ID_OTHER = 0x01000004;
109
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800110 private static final Object sSync = new Object();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 // Information about preloaded resources. Note that they are not
113 // protected by a lock, because while preloading in zygote we are all
114 // single-threaded, and after that these are immutable.
Alan Viverette52b999f2014-03-24 18:00:26 -0700115 private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
116 private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
Alan Viverettea8636c92015-03-27 10:44:39 -0700117 = new LongSparseArray<>();
Alan Viverettee0f95f32015-04-01 13:10:18 -0700118 private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
119 sPreloadedColorStateLists = new LongSparseArray<>();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700120
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700121 // Pool of TypedArrays targeted to this Resources object.
Alan Viverettea8636c92015-03-27 10:44:39 -0700122 final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700123
Alan Viveretteedc46642014-02-01 01:43:16 -0800124 // Used by BridgeResources in layoutlib
125 static Resources mSystem = null;
126
Dianne Hackborndde331c2012-08-03 14:01:57 -0700127 private static boolean sPreloaded;
Alan Viverette4d07bc92015-11-16 10:19:12 -0500128
129 /** Lock object used to protect access to caches and configuration. */
130 private final Object mAccessLock = new Object();
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 Configuration mTmpConfig = new Configuration();
Alan Viverettee54d2452015-05-06 10:41:43 -0700134 private final DrawableCache mDrawableCache = new DrawableCache(this);
135 private final DrawableCache mColorDrawableCache = new DrawableCache(this);
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800136 private final ConfigurationBoundResourceCache<ColorStateList> mColorStateListCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700137 new ConfigurationBoundResourceCache<>(this);
Yigit Boyard422dc32014-09-25 12:23:35 -0700138 private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700139 new ConfigurationBoundResourceCache<>(this);
Yigit Boyard422dc32014-09-25 12:23:35 -0700140 private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
Alan Viverettea8636c92015-03-27 10:44:39 -0700141 new ConfigurationBoundResourceCache<>(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400143 /** Used to inflate drawable objects from XML. */
144 private DrawableInflater mDrawableInflater;
145
Alan Viverette4d07bc92015-11-16 10:19:12 -0500146 /** Lock object used to protect access to {@link #mTmpValue}. */
147 private final Object mTmpValueLock = new Object();
148
149 /** Single-item pool used to minimize TypedValue allocations. */
Alan Viverette562a6a82014-01-31 11:07:29 -0800150 private TypedValue mTmpValue = new TypedValue();
Alan Viverette4d07bc92015-11-16 10:19:12 -0500151
Alan Viverette562a6a82014-01-31 11:07:29 -0800152 private boolean mPreloading;
153
Alan Viverette10979612016-01-06 15:27:35 -0500154 // Cyclical cache used for recently-accessed XML files.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private int mLastCachedXmlBlockIndex = -1;
Alan Viverette10979612016-01-06 15:27:35 -0500156 private final String[] mCachedXmlBlockFiles = new String[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
158
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700159 final AssetManager mAssets;
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400160 final ClassLoader mClassLoader;
Alan Viverette8b5b25b2014-09-13 19:30:11 -0700161 final DisplayMetrics mMetrics = new DisplayMetrics();
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 private final Configuration mConfiguration = new Configuration();
Roozbeh Pournaderdad10062015-12-14 16:15:52 -0800164 private Locale mResolvedLocale = null;
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100165 private PluralRules mPluralRule;
Craig Mautner48d0d182013-06-11 07:53:06 -0700166
167 private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
Alan Viverette52b999f2014-03-24 18:00:26 -0700168
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700169 static {
170 sPreloadedDrawables = new LongSparseArray[2];
Alan Viverettea8636c92015-03-27 10:44:39 -0700171 sPreloadedDrawables[0] = new LongSparseArray<>();
172 sPreloadedDrawables[1] = new LongSparseArray<>();
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -0700173 }
174
Alan Viverette62599332014-04-01 14:57:39 -0700175 /**
176 * Returns the most appropriate default theme for the specified target SDK version.
Alan Viverette5effd7e2014-05-05 12:25:33 -0700177 * <ul>
178 * <li>Below API 11: Gingerbread
179 * <li>APIs 11 thru 14: Holo
180 * <li>APIs 14 thru XX: Device default dark
181 * <li>API XX and above: Device default light with dark action bar
182 * </ul>
Alan Viverette62599332014-04-01 14:57:39 -0700183 *
184 * @param curTheme The current theme, or 0 if not specified.
185 * @param targetSdkVersion The target SDK version.
186 * @return A theme resource identifier
187 * @hide
188 */
Alan Viverette5effd7e2014-05-05 12:25:33 -0700189 public static int selectDefaultTheme(int curTheme, int targetSdkVersion) {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800190 return selectSystemTheme(curTheme, targetSdkVersion,
Alan Viverette5effd7e2014-05-05 12:25:33 -0700191 com.android.internal.R.style.Theme,
192 com.android.internal.R.style.Theme_Holo,
193 com.android.internal.R.style.Theme_DeviceDefault,
194 com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar);
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800195 }
Alan Viverette62599332014-04-01 14:57:39 -0700196
Alan Viverette5effd7e2014-05-05 12:25:33 -0700197 /** @hide */
198 public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo,
199 int dark, int deviceDefault) {
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800200 if (curTheme != 0) {
201 return curTheme;
202 }
Alan Viverette5effd7e2014-05-05 12:25:33 -0700203 if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) {
204 return orig;
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800205 }
Alan Viverette5effd7e2014-05-05 12:25:33 -0700206 if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
207 return holo;
208 }
209 if (targetSdkVersion < Build.VERSION_CODES.CUR_DEVELOPMENT) {
210 return dark;
211 }
212 return deviceDefault;
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800213 }
Alan Viverette62599332014-04-01 14:57:39 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 /**
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400216 * @return the inflater used to create drawable objects
217 * @hide Pending API finalization.
218 */
219 public final DrawableInflater getDrawableInflater() {
220 if (mDrawableInflater == null) {
221 mDrawableInflater = new DrawableInflater(this, mClassLoader);
222 }
223 return mDrawableInflater;
224 }
225
226 /**
Yigit Boyard422dc32014-09-25 12:23:35 -0700227 * Used by AnimatorInflater.
228 *
229 * @hide
230 */
231 public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
232 return mAnimatorCache;
233 }
234
235 /**
236 * Used by AnimatorInflater.
237 *
238 * @hide
239 */
240 public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
241 return mStateListAnimatorCache;
242 }
243
244 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 * This exception is thrown by the resource APIs when a requested resource
246 * can not be found.
247 */
248 public static class NotFoundException extends RuntimeException {
249 public NotFoundException() {
250 }
251
252 public NotFoundException(String name) {
253 super(name);
254 }
Alan Viverette4d07bc92015-11-16 10:19:12 -0500255
256 public NotFoundException(String name, Exception cause) {
257 super(name, cause);
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 }
260
261 /**
262 * Create a new Resources object on top of an existing set of assets in an
263 * AssetManager.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800264 *
265 * @param assets Previously created AssetManager.
266 * @param metrics Current display metrics to consider when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 * selecting/computing resource values.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800268 * @param config Desired device configuration to consider when
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 * selecting/computing resource values (optional).
270 */
Romain Guy5d911c32012-04-12 16:25:17 -0700271 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400272 this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700273 }
274
275 /**
Mitsuru Oshimaba3ba572009-07-08 18:49:26 -0700276 * Creates a new Resources object with CompatibilityInfo.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800277 *
278 * @param assets Previously created AssetManager.
279 * @param metrics Current display metrics to consider when
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700280 * selecting/computing resource values.
Wale Ogunwale60454db2015-01-23 16:05:07 -0800281 * @param config Desired device configuration to consider when
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700282 * selecting/computing resource values (optional).
Craig Mautner48d0d182013-06-11 07:53:06 -0700283 * @param compatInfo this resource's compatibility info. Must not be null.
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400284 * @param classLoader class loader for the package used to load custom
285 * resource classes, may be {@code null} to use system
286 * class loader
Mitsuru Oshima8169dae2009-04-28 18:12:09 -0700287 * @hide
288 */
Craig Mautner48d0d182013-06-11 07:53:06 -0700289 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400290 CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 mAssets = assets;
Alan Viverette02fc5fe2015-08-27 13:16:09 -0400292 mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 mMetrics.setToDefaults();
Adam Lesinski79a8ffe2013-09-19 20:33:15 -0700294 if (compatInfo != null) {
295 mCompatibilityInfo = compatInfo;
296 }
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700297 updateConfiguration(config, metrics);
298 assets.ensureStringBlocks();
Mitsuru Oshima569076c2009-07-02 20:06:08 -0700299 }
300
301 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 * Return a global shared Resources object that provides access to only
Wale Ogunwale60454db2015-01-23 16:05:07 -0800303 * system resources (no application resources), and is not configured for
304 * the current screen (can not use dimension units, does not change based
305 * on orientation, etc).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 */
307 public static Resources getSystem() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800308 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 Resources ret = mSystem;
310 if (ret == null) {
311 ret = new Resources();
312 mSystem = ret;
313 }
314
315 return ret;
316 }
317 }
318
319 /**
Roozbeh Pournaderdad10062015-12-14 16:15:52 -0800320 * Return the Locale resulting from locale negotiation between the Resources and the
321 * Configuration objects used to construct the Resources. The locale is used for retrieving
322 * resources as well as for determining plural rules.
323 */
324 @NonNull
325 public Locale getResolvedLocale() {
326 return mResolvedLocale;
327 }
328
329 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 * Return the string value associated with a particular resource ID. The
331 * returned object will be a String if this is a plain string; it will be
332 * some other type of CharSequence if it is styled.
333 * {@more}
334 *
335 * @param id The desired resource identifier, as generated by the aapt
336 * tool. This integer encodes the package, type, and resource
337 * entry. The value 0 is an invalid identifier.
338 *
339 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
340 *
341 * @return CharSequence The string data associated with the resource, plus
342 * possibly styled text information.
343 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700344 public CharSequence getText(@StringRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 CharSequence res = mAssets.getResourceText(id);
346 if (res != null) {
347 return res;
348 }
349 throw new NotFoundException("String resource ID #0x"
350 + Integer.toHexString(id));
351 }
352
353 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800354 * Returns the character sequence necessary for grammatically correct pluralization
355 * of the given resource ID for the given quantity.
356 * Note that the character sequence is selected based solely on grammatical necessity,
357 * and that such rules differ between languages. Do not assume you know which string
358 * will be returned for a given quantity. See
359 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
360 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700361 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 * @param id The desired resource identifier, as generated by the aapt
363 * tool. This integer encodes the package, type, and resource
364 * entry. The value 0 is an invalid identifier.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700365 * @param quantity The number used to get the correct string for the current language's
366 * plural rules.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 *
368 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
369 *
370 * @return CharSequence The string data associated with the resource, plus
371 * possibly styled text information.
372 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700373 public CharSequence getQuantityText(@PluralsRes int id, int quantity)
374 throws NotFoundException {
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100375 PluralRules rule = getPluralRule();
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700376 CharSequence res = mAssets.getResourceBagText(id,
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100377 attrForQuantityCode(rule.select(quantity)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 if (res != null) {
379 return res;
380 }
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700381 res = mAssets.getResourceBagText(id, ID_OTHER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 if (res != null) {
383 return res;
384 }
385 throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
386 + " quantity=" + quantity
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100387 + " item=" + rule.select(quantity));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 }
389
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100390 private PluralRules getPluralRule() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800391 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 if (mPluralRule == null) {
Roozbeh Pournaderdad10062015-12-14 16:15:52 -0800393 mPluralRule = PluralRules.forLocale(mResolvedLocale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 }
395 return mPluralRule;
396 }
397 }
398
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100399 private static int attrForQuantityCode(String quantityCode) {
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700400 switch (quantityCode) {
Rayhaan Jaufeerallyb27b3052015-07-15 15:25:15 +0100401 case PluralRules.KEYWORD_ZERO: return 0x01000005;
402 case PluralRules.KEYWORD_ONE: return 0x01000006;
403 case PluralRules.KEYWORD_TWO: return 0x01000007;
404 case PluralRules.KEYWORD_FEW: return 0x01000008;
405 case PluralRules.KEYWORD_MANY: return 0x01000009;
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700406 default: return ID_OTHER;
407 }
408 }
409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 /**
411 * Return the string value associated with a particular resource ID. It
412 * will be stripped of any styled text 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 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
420 *
421 * @return String The string data associated with the resource,
Alan Viveretteb4004df2015-04-29 16:55:42 -0700422 * stripped of styled text information.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 */
Alan Viveretteb4004df2015-04-29 16:55:42 -0700424 @NonNull
Tor Norbye7b9c9122013-05-30 16:48:33 -0700425 public String getString(@StringRes int id) throws NotFoundException {
Alan Viveretteb4004df2015-04-29 16:55:42 -0700426 final CharSequence res = getText(id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 if (res != null) {
428 return res.toString();
429 }
430 throw new NotFoundException("String resource ID #0x"
431 + Integer.toHexString(id));
432 }
433
434
435 /**
436 * Return the string value associated with a particular resource ID,
437 * substituting the format arguments as defined in {@link java.util.Formatter}
438 * and {@link java.lang.String#format}. It will be stripped of any styled text
439 * information.
440 * {@more}
441 *
442 * @param id The desired resource identifier, as generated by the aapt
443 * tool. This integer encodes the package, type, and resource
444 * entry. The value 0 is an invalid identifier.
445 *
446 * @param formatArgs The format arguments that will be used for substitution.
447 *
448 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
449 *
450 * @return String The string data associated with the resource,
Alan Viveretteb4004df2015-04-29 16:55:42 -0700451 * stripped of styled text information.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 */
Alan Viveretteb4004df2015-04-29 16:55:42 -0700453 @NonNull
454 public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
455 final String raw = getString(id);
Roozbeh Pournaderdad10062015-12-14 16:15:52 -0800456 return String.format(mResolvedLocale, raw, formatArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458
459 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800460 * Formats the string necessary for grammatically correct pluralization
461 * of the given resource ID for the given quantity, using the given arguments.
462 * Note that the string is selected based solely on grammatical necessity,
463 * and that such rules differ between languages. Do not assume you know which string
464 * will be returned for a given quantity. See
465 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
466 * for more detail.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 *
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800468 * <p>Substitution of format arguments works as if using
469 * {@link java.util.Formatter} and {@link java.lang.String#format}.
470 * The resulting string will be stripped of any styled text information.
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 * @param formatArgs The format arguments that will be used for substitution.
478 *
479 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
480 *
481 * @return String The string data associated with the resource,
482 * stripped of styled text information.
483 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700484 public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 throws NotFoundException {
486 String raw = getQuantityText(id, quantity).toString();
Roozbeh Pournaderdad10062015-12-14 16:15:52 -0800487 return String.format(mResolvedLocale, raw, formatArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 }
489
490 /**
Elliott Hughes95d5ab32013-03-08 11:26:57 -0800491 * Returns the string necessary for grammatically correct pluralization
492 * of the given resource ID for the given quantity.
493 * Note that the string is selected based solely on grammatical necessity,
494 * and that such rules differ between languages. Do not assume you know which string
495 * will be returned for a given quantity. See
496 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a>
497 * for more detail.
Elliott Hughes1ad636c2010-07-01 16:51:48 -0700498 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 * @param id The desired resource identifier, as generated by the aapt
500 * tool. This integer encodes the package, type, and resource
501 * entry. The value 0 is an invalid identifier.
502 * @param quantity The number used to get the correct string for the current language's
503 * plural rules.
504 *
505 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
506 *
507 * @return String The string data associated with the resource,
508 * stripped of styled text information.
509 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700510 public String getQuantityString(@PluralsRes int id, int quantity)
511 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 return getQuantityText(id, quantity).toString();
513 }
514
515 /**
516 * Return the string value associated with a particular resource ID. The
517 * returned object will be a String if this is a plain string; it will be
518 * some other type of CharSequence if it is styled.
519 *
520 * @param id The desired resource identifier, as generated by the aapt
521 * tool. This integer encodes the package, type, and resource
522 * entry. The value 0 is an invalid identifier.
523 *
524 * @param def The default CharSequence to return.
525 *
526 * @return CharSequence The string data associated with the resource, plus
527 * possibly styled text information, or def if id is 0 or not found.
528 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700529 public CharSequence getText(@StringRes int id, CharSequence def) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
531 return res != null ? res : def;
532 }
533
534 /**
535 * Return the styled text array associated with a particular resource ID.
536 *
537 * @param id The desired resource identifier, as generated by the aapt
538 * tool. This integer encodes the package, type, and resource
539 * entry. The value 0 is an invalid identifier.
540 *
541 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
542 *
543 * @return The styled text array associated with the resource.
544 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700545 public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 CharSequence[] res = mAssets.getResourceTextArray(id);
547 if (res != null) {
548 return res;
549 }
550 throw new NotFoundException("Text array resource ID #0x"
551 + Integer.toHexString(id));
552 }
553
554 /**
555 * Return the string array associated with a particular resource ID.
556 *
557 * @param id The desired resource identifier, as generated by the aapt
558 * tool. This integer encodes the package, type, and resource
559 * entry. The value 0 is an invalid identifier.
560 *
561 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
562 *
563 * @return The string array associated with the resource.
564 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700565 public String[] getStringArray(@ArrayRes int id)
566 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 String[] res = mAssets.getResourceStringArray(id);
568 if (res != null) {
569 return res;
570 }
571 throw new NotFoundException("String array resource ID #0x"
572 + Integer.toHexString(id));
573 }
574
575 /**
576 * Return the int array associated with a particular resource ID.
577 *
578 * @param id The desired resource identifier, as generated by the aapt
579 * tool. This integer encodes the package, type, and resource
580 * entry. The value 0 is an invalid identifier.
581 *
582 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
583 *
584 * @return The int array associated with the resource.
585 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700586 public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 int[] res = mAssets.getArrayIntResource(id);
588 if (res != null) {
589 return res;
590 }
591 throw new NotFoundException("Int array resource ID #0x"
592 + Integer.toHexString(id));
593 }
594
595 /**
596 * Return an array of heterogeneous values.
597 *
598 * @param id The desired resource identifier, as generated by the aapt
599 * tool. This integer encodes the package, type, and resource
600 * entry. The value 0 is an invalid identifier.
601 *
602 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
603 *
604 * @return Returns a TypedArray holding an array of the array values.
605 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
606 * when done with it.
607 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700608 public TypedArray obtainTypedArray(@ArrayRes int id)
609 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 int len = mAssets.getArraySize(id);
611 if (len < 0) {
612 throw new NotFoundException("Array resource ID #0x"
613 + Integer.toHexString(id));
614 }
615
Alan Viverette52b999f2014-03-24 18:00:26 -0700616 TypedArray array = TypedArray.obtain(this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 array.mLength = mAssets.retrieveArray(id, array.mData);
618 array.mIndices[0] = 0;
619
620 return array;
621 }
622
623 /**
624 * Retrieve a dimensional for a particular resource ID. Unit
625 * conversions are based on the current {@link DisplayMetrics} associated
626 * with the resources.
627 *
628 * @param id The desired resource identifier, as generated by the aapt
629 * tool. This integer encodes the package, type, and resource
630 * entry. The value 0 is an invalid identifier.
631 *
632 * @return Resource dimension value multiplied by the appropriate
633 * metric.
634 *
635 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
636 *
637 * @see #getDimensionPixelOffset
638 * @see #getDimensionPixelSize
639 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700640 public float getDimension(@DimenRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500641 final TypedValue value = obtainTempTypedValue(id);
642 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 if (value.type == TypedValue.TYPE_DIMENSION) {
644 return TypedValue.complexToDimension(value.data, mMetrics);
645 }
Alan Viverette4d07bc92015-11-16 10:19:12 -0500646 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
647 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
648 } finally {
649 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
651 }
652
653 /**
654 * Retrieve a dimensional for a particular resource ID for use
655 * as an offset in raw pixels. This is the same as
656 * {@link #getDimension}, except the returned value is converted to
657 * integer pixels for you. An offset conversion involves simply
658 * truncating the base value to an integer.
659 *
660 * @param id The desired resource identifier, as generated by the aapt
661 * tool. This integer encodes the package, type, and resource
662 * entry. The value 0 is an invalid identifier.
663 *
664 * @return Resource dimension value multiplied by the appropriate
665 * metric and truncated to integer pixels.
666 *
667 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
668 *
669 * @see #getDimension
670 * @see #getDimensionPixelSize
671 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700672 public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500673 final TypedValue value = obtainTempTypedValue(id);
674 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 if (value.type == TypedValue.TYPE_DIMENSION) {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500676 return TypedValue.complexToDimensionPixelOffset(value.data, mMetrics);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 }
Alan Viverette4d07bc92015-11-16 10:19:12 -0500678 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
679 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
680 } finally {
681 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683 }
684
685 /**
686 * Retrieve a dimensional for a particular resource ID for use
687 * as a size in raw pixels. This is the same as
688 * {@link #getDimension}, except the returned value is converted to
689 * integer pixels for use as a size. A size conversion involves
690 * rounding the base value, and ensuring that a non-zero base value
691 * is at least one pixel in size.
692 *
693 * @param id The desired resource identifier, as generated by the aapt
694 * tool. This integer encodes the package, type, and resource
695 * entry. The value 0 is an invalid identifier.
696 *
697 * @return Resource dimension value multiplied by the appropriate
698 * metric and truncated to integer pixels.
699 *
700 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
701 *
702 * @see #getDimension
703 * @see #getDimensionPixelOffset
704 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700705 public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500706 final TypedValue value = obtainTempTypedValue(id);
707 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 if (value.type == TypedValue.TYPE_DIMENSION) {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500709 return TypedValue.complexToDimensionPixelSize(value.data, mMetrics);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 }
Alan Viverette4d07bc92015-11-16 10:19:12 -0500711 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
712 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
713 } finally {
714 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716 }
717
718 /**
719 * Retrieve a fractional unit for a particular resource ID.
720 *
721 * @param id The desired resource identifier, as generated by the aapt
722 * tool. This integer encodes the package, type, and resource
723 * entry. The value 0 is an invalid identifier.
724 * @param base The base value of this fraction. In other words, a
725 * standard fraction is multiplied by this value.
726 * @param pbase The parent base value of this fraction. In other
727 * words, a parent fraction (nn%p) is multiplied by this
728 * value.
729 *
730 * @return Attribute fractional value multiplied by the appropriate
731 * base value.
732 *
733 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
734 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700735 public float getFraction(@FractionRes int id, int base, int pbase) {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500736 final TypedValue value = obtainTempTypedValue(id);
737 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 if (value.type == TypedValue.TYPE_FRACTION) {
739 return TypedValue.complexToFraction(value.data, base, pbase);
740 }
Alan Viverette4d07bc92015-11-16 10:19:12 -0500741 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
742 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
743 } finally {
744 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746 }
747
748 /**
749 * Return a drawable object associated with a particular resource ID.
750 * Various types of objects will be returned depending on the underlying
751 * resource -- for example, a solid color, PNG image, scalable image, etc.
752 * The Drawable API hides these implementation details.
Dianne Hackbornfb5c3db2012-05-18 15:24:24 -0700753 *
754 * <p class="note"><strong>Note:</strong> Prior to
755 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function
756 * would not correctly retrieve the final configuration density when
757 * the resource ID passed here is an alias to another Drawable resource.
758 * This means that if the density configuration of the alias resource
759 * is different than the actual resource, the density of the returned
760 * Drawable would be incorrect, resulting in bad scaling. To work
761 * around this, you can instead retrieve the Drawable through
762 * {@link TypedArray#getDrawable TypedArray.getDrawable}. Use
763 * {@link android.content.Context#obtainStyledAttributes(int[])
764 * Context.obtainStyledAttributes} with
765 * an array containing the resource ID of interest to create the TypedArray.</p>
766 *
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700767 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
768 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
769 * or {@link #getDrawable(int, Theme)} passing the desired theme.</p>
770 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 * @param id The desired resource identifier, as generated by the aapt
772 * tool. This integer encodes the package, type, and resource
773 * entry. The value 0 is an invalid identifier.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * @return Drawable An object that can be used to draw this resource.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800775 * @throws NotFoundException Throws NotFoundException if the given ID does
776 * not exist.
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700777 * @see #getDrawable(int, Theme)
Alan Viverettec10e3962014-12-02 14:58:08 -0800778 * @deprecated Use {@link #getDrawable(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 */
Alan Viverettec10e3962014-12-02 14:58:08 -0800780 @Deprecated
781 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700782 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
Alan Viverette34a14f962014-08-15 16:13:15 -0700783 final Drawable d = getDrawable(id, null);
Alan Viverette7e0aaae2014-11-24 11:27:09 -0800784 if (d != null && d.canApplyTheme()) {
Alan Viverette34a14f962014-08-15 16:13:15 -0700785 Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme "
786 + "attributes! Consider using Resources.getDrawable(int, Theme) or "
787 + "Context.getDrawable(int).", new RuntimeException());
788 }
789 return d;
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800790 }
791
792 /**
793 * Return a drawable object associated with a particular resource ID and
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700794 * styled for the specified theme. Various types of objects will be
795 * returned depending on the underlying resource -- for example, a solid
796 * color, PNG image, scalable image, etc.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800797 *
798 * @param id The desired resource identifier, as generated by the aapt
799 * tool. This integer encodes the package, type, and resource
800 * entry. The value 0 is an invalid identifier.
Alan Viverette3b5c4272014-05-20 13:20:42 -0700801 * @param theme The theme used to style the drawable attributes, may be {@code null}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800802 * @return Drawable An object that can be used to draw this resource.
803 * @throws NotFoundException Throws NotFoundException if the given ID does
804 * not exist.
805 */
Alan Viverettec10e3962014-12-02 14:58:08 -0800806 @Nullable
Alan Viverette4d07bc92015-11-16 10:19:12 -0500807 public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
808 throws NotFoundException {
809 final TypedValue value = obtainTempTypedValue(id);
810 try {
811 return loadDrawable(value, id, theme);
812 } finally {
813 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815 }
816
817 /**
Kenny Root55fc8502010-10-28 14:47:01 -0700818 * Return a drawable object associated with a particular resource ID for the
819 * given screen density in DPI. This will set the drawable's density to be
820 * the device's density multiplied by the ratio of actual drawable density
821 * to requested density. This allows the drawable to be scaled up to the
822 * correct size if needed. Various types of objects will be returned
823 * depending on the underlying resource -- for example, a solid color, PNG
824 * image, scalable image, etc. The Drawable API hides these implementation
825 * details.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800826 *
Alan Viverette6dbe51b2014-06-02 16:39:04 -0700827 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use
828 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)}
829 * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired
830 * theme.</p>
831 *
Kenny Root55fc8502010-10-28 14:47:01 -0700832 * @param id The desired resource identifier, as generated by the aapt tool.
833 * This integer encodes the package, type, and resource entry.
834 * The value 0 is an invalid identifier.
835 * @param density the desired screen density indicated by the resource as
836 * found in {@link DisplayMetrics}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800837 * @return Drawable An object that can be used to draw this resource.
Kenny Root55fc8502010-10-28 14:47:01 -0700838 * @throws NotFoundException Throws NotFoundException if the given ID does
839 * not exist.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800840 * @see #getDrawableForDensity(int, int, Theme)
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800841 * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead.
Kenny Root55fc8502010-10-28 14:47:01 -0700842 */
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800843 @Deprecated
844 @Nullable
Alan Viverette4d07bc92015-11-16 10:19:12 -0500845 public Drawable getDrawableForDensity(@DrawableRes int id, int density)
846 throws NotFoundException {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800847 return getDrawableForDensity(id, density, null);
848 }
849
850 /**
851 * Return a drawable object associated with a particular resource ID for the
852 * given screen density in DPI and styled for the specified theme.
853 *
854 * @param id The desired resource identifier, as generated by the aapt tool.
855 * This integer encodes the package, type, and resource entry.
856 * The value 0 is an invalid identifier.
857 * @param density The desired screen density indicated by the resource as
858 * found in {@link DisplayMetrics}.
Alan Viverette3b5c4272014-05-20 13:20:42 -0700859 * @param theme The theme used to style the drawable attributes, may be {@code null}.
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800860 * @return Drawable An object that can be used to draw this resource.
861 * @throws NotFoundException Throws NotFoundException if the given ID does
862 * not exist.
863 */
Alan Viverettea6f8b2c2014-12-02 15:26:33 -0800864 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -0700865 public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500866 final TypedValue value = obtainTempTypedValue(id);
867 try {
Kenny Root55fc8502010-10-28 14:47:01 -0700868 getValueForDensity(id, density, value, true);
869
Alan Viverette7941a7f2016-01-06 11:11:53 -0500870 // If the drawable's XML lives in our current density qualifier,
871 // it's okay to use a scaled version from the cache. Otherwise, we
872 // need to actually load the drawable from XML.
873 final boolean useCache = value.density == mMetrics.densityDpi;
874
Kenny Root55fc8502010-10-28 14:47:01 -0700875 /*
876 * Pretend the requested density is actually the display density. If
877 * the drawable returned is not the requested density, then force it
878 * to be scaled later by dividing its density by the ratio of
879 * requested density to actual device density. Drawables that have
880 * undefined density or no density don't need to be handled here.
881 */
882 if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
883 if (value.density == density) {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700884 value.density = mMetrics.densityDpi;
Kenny Root55fc8502010-10-28 14:47:01 -0700885 } else {
Dianne Hackborn908aecc2012-07-31 16:37:34 -0700886 value.density = (value.density * mMetrics.densityDpi) / density;
Kenny Root55fc8502010-10-28 14:47:01 -0700887 }
888 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800889
Alan Viverette7941a7f2016-01-06 11:11:53 -0500890 return loadDrawable(value, id, theme, useCache);
Alan Viverette4d07bc92015-11-16 10:19:12 -0500891 } finally {
892 releaseTempTypedValue(value);
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800893 }
Kenny Root55fc8502010-10-28 14:47:01 -0700894 }
895
896 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 * Return a movie object associated with the particular resource ID.
898 * @param id The desired resource identifier, as generated by the aapt
899 * tool. This integer encodes the package, type, and resource
900 * entry. The value 0 is an invalid identifier.
901 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
902 *
903 */
Tor Norbye7b9c9122013-05-30 16:48:33 -0700904 public Movie getMovie(@RawRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 InputStream is = openRawResource(id);
906 Movie movie = Movie.decodeStream(is);
907 try {
908 is.close();
909 }
910 catch (java.io.IOException e) {
911 // don't care, since the return value is valid
912 }
913 return movie;
914 }
915
916 /**
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800917 * Returns a color integer associated with a particular resource ID. If the
918 * resource holds a complex {@link ColorStateList}, then the default color
919 * from the set is returned.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 *
921 * @param id The desired resource identifier, as generated by the aapt
922 * tool. This integer encodes the package, type, and resource
923 * entry. The value 0 is an invalid identifier.
924 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800925 * @throws NotFoundException Throws NotFoundException if the given ID does
926 * not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800928 * @return A single color value in the form 0xAARRGGBB.
929 * @deprecated Use {@link #getColor(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 */
Tor Norbye80756e32015-03-02 09:39:27 -0800931 @ColorInt
Alan Viverette4a357cd2015-03-18 18:37:18 -0700932 @Deprecated
Tor Norbye7b9c9122013-05-30 16:48:33 -0700933 public int getColor(@ColorRes int id) throws NotFoundException {
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800934 return getColor(id, null);
935 }
936
937 /**
938 * Returns a themed color integer associated with a particular resource ID.
939 * If the resource holds a complex {@link ColorStateList}, then the default
940 * color from the set is returned.
941 *
942 * @param id The desired resource identifier, as generated by the aapt
943 * tool. This integer encodes the package, type, and resource
944 * entry. The value 0 is an invalid identifier.
945 * @param theme The theme used to style the color attributes, may be
946 * {@code null}.
947 *
948 * @throws NotFoundException Throws NotFoundException if the given ID does
949 * not exist.
950 *
951 * @return A single color value in the form 0xAARRGGBB.
952 */
Tor Norbye80756e32015-03-02 09:39:27 -0800953 @ColorInt
Tor Norbye7b9c9122013-05-30 16:48:33 -0700954 public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500955 final TypedValue value = obtainTempTypedValue(id);
956 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 if (value.type >= TypedValue.TYPE_FIRST_INT
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800958 && value.type <= TypedValue.TYPE_LAST_INT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 return value.data;
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800960 } else if (value.type != TypedValue.TYPE_STRING) {
Alan Viverette4d07bc92015-11-16 10:19:12 -0500961 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
962 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800964
Alan Viverette4d07bc92015-11-16 10:19:12 -0500965 final ColorStateList csl = loadColorStateList(value, id, theme);
966 return csl.getDefaultColor();
967 } finally {
968 releaseTempTypedValue(value);
Dianne Hackborn50707cc2013-02-08 15:32:05 -0800969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971
972 /**
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800973 * Returns a color state list associated with a particular resource ID. The
974 * resource may contain either a single raw color value or a complex
975 * {@link ColorStateList} holding multiple possible colors.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 *
977 * @param id The desired resource identifier of a {@link ColorStateList},
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800978 * as generated by the aapt tool. This integer encodes the
979 * package, type, and resource entry. The value 0 is an invalid
980 * identifier.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800982 * @throws NotFoundException Throws NotFoundException if the given ID does
983 * not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 *
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800985 * @return A ColorStateList object containing either a single solid color
986 * or multiple colors that can be selected based on a state.
987 * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 */
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800989 @Nullable
Alan Viverette4a357cd2015-03-18 18:37:18 -0700990 @Deprecated
Tor Norbye7b9c9122013-05-30 16:48:33 -0700991 public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
Alan Viverette45c4bbb2015-01-05 14:59:19 -0800992 final ColorStateList csl = getColorStateList(id, null);
993 if (csl != null && csl.canApplyTheme()) {
994 Log.w(TAG, "ColorStateList " + getResourceName(id) + " has "
995 + "unresolved theme attributes! Consider using "
996 + "Resources.getColorStateList(int, Theme) or "
997 + "Context.getColorStateList(int).", new RuntimeException());
998 }
999 return csl;
1000 }
1001
1002 /**
1003 * Returns a themed color state list associated with a particular resource
1004 * ID. The resource may contain either a single raw color value or a
1005 * complex {@link ColorStateList} holding multiple possible colors.
1006 *
1007 * @param id The desired resource identifier of a {@link ColorStateList},
1008 * as generated by the aapt tool. This integer encodes the
1009 * package, type, and resource entry. The value 0 is an invalid
1010 * identifier.
1011 * @param theme The theme used to style the color attributes, may be
1012 * {@code null}.
1013 *
1014 * @throws NotFoundException Throws NotFoundException if the given ID does
1015 * not exist.
1016 *
1017 * @return A themed ColorStateList object containing either a single solid
1018 * color or multiple colors that can be selected based on a state.
1019 */
1020 @Nullable
Tor Norbye7b9c9122013-05-30 16:48:33 -07001021 public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
Alan Viverette45c4bbb2015-01-05 14:59:19 -08001022 throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001023 final TypedValue value = obtainTempTypedValue(id);
1024 try {
1025 return loadColorStateList(value, id, theme);
1026 } finally {
1027 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 }
1029 }
1030
1031 /**
1032 * Return a boolean associated with a particular resource ID. This can be
1033 * used with any integral resource value, and will return true if it is
1034 * non-zero.
1035 *
1036 * @param id The desired resource identifier, as generated by the aapt
1037 * tool. This integer encodes the package, type, and resource
1038 * entry. The value 0 is an invalid identifier.
1039 *
1040 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1041 *
1042 * @return Returns the boolean value contained in the resource.
1043 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001044 public boolean getBoolean(@BoolRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001045 final TypedValue value = obtainTempTypedValue(id);
1046 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 if (value.type >= TypedValue.TYPE_FIRST_INT
Alan Viverette4d07bc92015-11-16 10:19:12 -05001048 && value.type <= TypedValue.TYPE_LAST_INT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 return value.data != 0;
1050 }
Alan Viverette4d07bc92015-11-16 10:19:12 -05001051 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1052 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1053 } finally {
1054 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056 }
1057
1058 /**
1059 * Return an integer associated with a particular resource ID.
1060 *
1061 * @param id The desired resource identifier, as generated by the aapt
1062 * tool. This integer encodes the package, type, and resource
1063 * entry. The value 0 is an invalid identifier.
1064 *
1065 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1066 *
1067 * @return Returns the integer value contained in the resource.
1068 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001069 public int getInteger(@IntegerRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001070 final TypedValue value = obtainTempTypedValue(id);
1071 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 if (value.type >= TypedValue.TYPE_FIRST_INT
Alan Viverette4d07bc92015-11-16 10:19:12 -05001073 && value.type <= TypedValue.TYPE_LAST_INT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 return value.data;
1075 }
Alan Viverette4d07bc92015-11-16 10:19:12 -05001076 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1077 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1078 } finally {
1079 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 }
1081 }
1082
1083 /**
Alan Viveretteb1e1dbf2014-08-07 17:17:43 -07001084 * Retrieve a floating-point value for a particular resource ID.
1085 *
1086 * @param id The desired resource identifier, as generated by the aapt
1087 * tool. This integer encodes the package, type, and resource
1088 * entry. The value 0 is an invalid identifier.
1089 *
1090 * @return Returns the floating-point value contained in the resource.
1091 *
1092 * @throws NotFoundException Throws NotFoundException if the given ID does
1093 * not exist or is not a floating-point value.
1094 * @hide Pending API council approval.
1095 */
1096 public float getFloat(int id) {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001097 final TypedValue value = obtainTempTypedValue(id);
1098 try {
Alan Viveretteb1e1dbf2014-08-07 17:17:43 -07001099 if (value.type == TypedValue.TYPE_FLOAT) {
1100 return value.getFloat();
1101 }
Alan Viverette4d07bc92015-11-16 10:19:12 -05001102 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
1103 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
1104 } finally {
1105 releaseTempTypedValue(value);
Alan Viveretteb1e1dbf2014-08-07 17:17:43 -07001106 }
1107 }
1108
1109 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 * Return an XmlResourceParser through which you can read a view layout
1111 * description for the given resource ID. This parser has limited
1112 * functionality -- in particular, you can't change its input, and only
1113 * the high-level events are available.
1114 *
1115 * <p>This function is really a simple wrapper for calling
1116 * {@link #getXml} with a layout resource.
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 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1123 *
1124 * @return A new parser object through which you can read
1125 * the XML data.
1126 *
1127 * @see #getXml
1128 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001129 public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 return loadXmlResourceParser(id, "layout");
1131 }
1132
1133 /**
1134 * Return an XmlResourceParser through which you can read an animation
1135 * description for the given resource ID. This parser has limited
1136 * functionality -- in particular, you can't change its input, and only
1137 * the high-level events are available.
1138 *
1139 * <p>This function is really a simple wrapper for calling
1140 * {@link #getXml} with an animation resource.
1141 *
1142 * @param id The desired resource identifier, as generated by the aapt
1143 * tool. This integer encodes the package, type, and resource
1144 * entry. The value 0 is an invalid identifier.
1145 *
1146 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1147 *
1148 * @return A new parser object through which you can read
1149 * the XML data.
1150 *
1151 * @see #getXml
1152 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001153 public XmlResourceParser getAnimation(@AnimRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 return loadXmlResourceParser(id, "anim");
1155 }
1156
1157 /**
1158 * Return an XmlResourceParser through which you can read a generic XML
1159 * resource for the given resource ID.
1160 *
1161 * <p>The XmlPullParser implementation returned here has some limited
1162 * functionality. In particular, you can't change its input, and only
1163 * high-level parsing events are available (since the document was
1164 * pre-parsed for you at build time, which involved merging text and
1165 * stripping comments).
1166 *
1167 * @param id The desired resource identifier, as generated by the aapt
1168 * tool. This integer encodes the package, type, and resource
1169 * entry. The value 0 is an invalid identifier.
1170 *
1171 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1172 *
1173 * @return A new parser object through which you can read
1174 * the XML data.
1175 *
1176 * @see android.util.AttributeSet
1177 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001178 public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 return loadXmlResourceParser(id, "xml");
1180 }
1181
1182 /**
1183 * Open a data stream for reading a raw resource. This can only be used
1184 * with resources whose value is the name of an asset files -- that is, it can be
1185 * used to open drawable, sound, and raw resources; it will fail on string
1186 * and color resources.
1187 *
1188 * @param id The resource identifier to open, as generated by the appt
1189 * tool.
1190 *
1191 * @return InputStream Access to the resource data.
1192 *
1193 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1194 *
1195 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001196 public InputStream openRawResource(@RawRes int id) throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001197 final TypedValue value = obtainTempTypedValue();
1198 try {
1199 return openRawResource(id, value);
1200 } finally {
1201 releaseTempTypedValue(value);
1202 }
1203 }
1204
1205 /**
1206 * Returns a TypedValue populated with data for the specified resource ID
1207 * that's suitable for temporary use. The obtained TypedValue should be
1208 * released using {@link #releaseTempTypedValue(TypedValue)}.
1209 *
1210 * @param id the resource ID for which data should be obtained
1211 * @return a populated typed value suitable for temporary use
1212 */
1213 private TypedValue obtainTempTypedValue(@AnyRes int id) {
1214 final TypedValue value = obtainTempTypedValue();
1215 getValue(id, value, true);
1216 return value;
1217 }
1218
1219 /**
1220 * Returns a TypedValue suitable for temporary use. The obtained TypedValue
1221 * should be released using {@link #releaseTempTypedValue(TypedValue)}.
1222 *
1223 * @return a typed value suitable for temporary use
1224 */
1225 private TypedValue obtainTempTypedValue() {
1226 TypedValue tmpValue = null;
1227 synchronized (mTmpValueLock) {
1228 if (mTmpValue != null) {
1229 tmpValue = mTmpValue;
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001230 mTmpValue = null;
1231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
Alan Viverette4d07bc92015-11-16 10:19:12 -05001233 if (tmpValue == null) {
1234 return new TypedValue();
1235 }
1236 return tmpValue;
1237 }
1238
1239 /**
1240 * Returns a TypedValue to the pool. After calling this method, the
1241 * specified TypedValue should no longer be accessed.
1242 *
1243 * @param value the typed value to return to the pool
1244 */
1245 private void releaseTempTypedValue(TypedValue value) {
1246 synchronized (mTmpValueLock) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001247 if (mTmpValue == null) {
1248 mTmpValue = value;
1249 }
1250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252
1253 /**
1254 * Open a data stream for reading a raw resource. This can only be used
Andy Stadlerf8a7cea2009-04-10 16:24:47 -07001255 * 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 -08001256 * used to open drawable, sound, and raw resources; it will fail on string
1257 * and color resources.
1258 *
1259 * @param id The resource identifier to open, as generated by the appt tool.
1260 * @param value The TypedValue object to hold the resource information.
1261 *
1262 * @return InputStream Access to the resource data.
1263 *
1264 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001266 public InputStream openRawResource(@RawRes int id, TypedValue value)
1267 throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268 getValue(id, value, true);
1269
1270 try {
1271 return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
1272 AssetManager.ACCESS_STREAMING);
1273 } catch (Exception e) {
1274 NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
1275 " from drawable resource ID #0x" + Integer.toHexString(id));
1276 rnf.initCause(e);
1277 throw rnf;
1278 }
1279 }
1280
1281 /**
1282 * Open a file descriptor for reading a raw resource. This can only be used
1283 * with resources whose value is the name of an asset files -- that is, it can be
1284 * used to open drawable, sound, and raw resources; it will fail on string
1285 * and color resources.
1286 *
1287 * <p>This function only works for resources that are stored in the package
1288 * as uncompressed data, which typically includes things like mp3 files
1289 * and png images.
1290 *
1291 * @param id The resource identifier to open, as generated by the appt
1292 * tool.
1293 *
1294 * @return AssetFileDescriptor A new file descriptor you can use to read
1295 * the resource. This includes the file descriptor itself, as well as the
1296 * offset and length of data where the resource appears in the file. A
1297 * null is returned if the file exists but is compressed.
1298 *
1299 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1300 *
1301 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001302 public AssetFileDescriptor openRawResourceFd(@RawRes int id)
1303 throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001304 final TypedValue value = obtainTempTypedValue(id);
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001305 try {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001306 return mAssets.openNonAssetFd(value.assetCookie, value.string.toString());
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001307 } catch (Exception e) {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001308 throw new NotFoundException("File " + value.string.toString() + " from drawable "
1309 + "resource ID #0x" + Integer.toHexString(id), e);
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001310 } finally {
Alan Viverette4d07bc92015-11-16 10:19:12 -05001311 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 }
1313 }
1314
1315 /**
1316 * Return the raw data associated with a particular resource ID.
1317 *
1318 * @param id The desired resource identifier, as generated by the aapt
1319 * tool. This integer encodes the package, type, and resource
1320 * entry. The value 0 is an invalid identifier.
1321 * @param outValue Object in which to place the resource data.
1322 * @param resolveRefs If true, a resource that is a reference to another
1323 * resource will be followed so that you receive the
1324 * actual final resource data. If false, the TypedValue
1325 * will be filled in with the reference itself.
1326 *
1327 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1328 *
1329 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001330 public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 throws NotFoundException {
Kenny Root55fc8502010-10-28 14:47:01 -07001332 boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 if (found) {
1334 return;
1335 }
1336 throw new NotFoundException("Resource ID #0x"
1337 + Integer.toHexString(id));
1338 }
1339
1340 /**
Kenny Root55fc8502010-10-28 14:47:01 -07001341 * Get the raw value associated with a resource with associated density.
1342 *
1343 * @param id resource identifier
1344 * @param density density in DPI
1345 * @param resolveRefs If true, a resource that is a reference to another
1346 * resource will be followed so that you receive the actual final
1347 * resource data. If false, the TypedValue will be filled in with
1348 * the reference itself.
1349 * @throws NotFoundException Throws NotFoundException if the given ID does
1350 * not exist.
1351 * @see #getValue(String, TypedValue, boolean)
Kenny Root55fc8502010-10-28 14:47:01 -07001352 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001353 public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
1354 boolean resolveRefs) throws NotFoundException {
Kenny Root55fc8502010-10-28 14:47:01 -07001355 boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
1356 if (found) {
1357 return;
1358 }
1359 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
1360 }
1361
1362 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 * Return the raw data associated with a particular resource ID.
1364 * See getIdentifier() for information on how names are mapped to resource
1365 * IDs, and getString(int) for information on how string resources are
1366 * retrieved.
1367 *
1368 * <p>Note: use of this function is discouraged. It is much more
1369 * efficient to retrieve resources by identifier than by name.
1370 *
1371 * @param name The name of the desired resource. This is passed to
1372 * getIdentifier() with a default type of "string".
1373 * @param outValue Object in which to place the resource data.
1374 * @param resolveRefs If true, a resource that is a reference to another
1375 * resource will be followed so that you receive the
1376 * actual final resource data. If false, the TypedValue
1377 * will be filled in with the reference itself.
1378 *
1379 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1380 *
1381 */
1382 public void getValue(String name, TypedValue outValue, boolean resolveRefs)
1383 throws NotFoundException {
1384 int id = getIdentifier(name, "string", null);
1385 if (id != 0) {
1386 getValue(id, outValue, resolveRefs);
1387 return;
1388 }
1389 throw new NotFoundException("String resource name " + name);
1390 }
1391
1392 /**
1393 * This class holds the current attribute values for a particular theme.
1394 * In other words, a Theme is a set of values for resource attributes;
1395 * these are used in conjunction with {@link TypedArray}
1396 * to resolve the final value for an attribute.
1397 *
1398 * <p>The Theme's attributes come into play in two ways: (1) a styled
1399 * attribute can explicit reference a value in the theme through the
1400 * "?themeAttribute" syntax; (2) if no value has been defined for a
1401 * particular styled attribute, as a last resort we will try to find that
1402 * attribute's value in the Theme.
1403 *
1404 * <p>You will normally use the {@link #obtainStyledAttributes} APIs to
1405 * retrieve XML attributes with style and theme information applied.
1406 */
1407 public final class Theme {
1408 /**
1409 * Place new attribute values into the theme. The style resource
1410 * specified by <var>resid</var> will be retrieved from this Theme's
1411 * resources, its values placed into the Theme object.
1412 *
1413 * <p>The semantics of this function depends on the <var>force</var>
1414 * argument: If false, only values that are not already defined in
1415 * the theme will be copied from the system resource; otherwise, if
1416 * any of the style's attributes are already defined in the theme, the
1417 * current values in the theme will be overwritten.
1418 *
Alan Viverette75257ce2014-05-22 19:31:38 -07001419 * @param resId The resource ID of a style resource from which to
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 * obtain attribute values.
1421 * @param force If true, values in the style resource will always be
1422 * used in the theme; otherwise, they will only be used
1423 * if not already defined in the theme.
1424 */
Alan Viverette75257ce2014-05-22 19:31:38 -07001425 public void applyStyle(int resId, boolean force) {
Alan Viverette395cd012015-08-11 17:27:04 -04001426 synchronized (mKey) {
1427 AssetManager.applyThemeStyle(mTheme, resId, force);
Alan Viverette52b999f2014-03-24 18:00:26 -07001428
Alan Viverette395cd012015-08-11 17:27:04 -04001429 mThemeResId = resId;
1430 mKey.append(resId, force);
1431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 }
1433
1434 /**
1435 * Set this theme to hold the same contents as the theme
1436 * <var>other</var>. If both of these themes are from the same
1437 * Resources object, they will be identical after this function
1438 * returns. If they are from different Resources, only the resources
1439 * they have in common will be set in this theme.
1440 *
1441 * @param other The existing Theme to copy from.
1442 */
1443 public void setTo(Theme other) {
Alan Viverette395cd012015-08-11 17:27:04 -04001444 synchronized (mKey) {
1445 synchronized (other.mKey) {
1446 AssetManager.copyTheme(mTheme, other.mTheme);
Alan Viverette52b999f2014-03-24 18:00:26 -07001447
Alan Viverette395cd012015-08-11 17:27:04 -04001448 mThemeResId = other.mThemeResId;
1449 mKey.setTo(other.getKey());
1450 }
1451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 }
1453
1454 /**
John Spurlock330dd532012-12-18 12:03:11 -05001455 * Return a TypedArray holding the values defined by
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 * <var>Theme</var> which are listed in <var>attrs</var>.
1457 *
Scott Main183bf112012-08-13 19:12:13 -07001458 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1459 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 *
1461 * @param attrs The desired attributes.
1462 *
1463 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1464 *
1465 * @return Returns a TypedArray holding an array of the attribute values.
1466 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1467 * when done with it.
1468 *
1469 * @see Resources#obtainAttributes
1470 * @see #obtainStyledAttributes(int, int[])
1471 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1472 */
Tor Norbyec91531a2015-04-01 17:41:55 -07001473 public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
Alan Viverette395cd012015-08-11 17:27:04 -04001474 synchronized (mKey) {
1475 final int len = attrs.length;
1476 final TypedArray array = TypedArray.obtain(Resources.this, len);
1477 array.mTheme = this;
1478 AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
1479 return array;
1480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 }
1482
1483 /**
John Spurlock330dd532012-12-18 12:03:11 -05001484 * Return a TypedArray holding the values defined by the style
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 * resource <var>resid</var> which are listed in <var>attrs</var>.
1486 *
Scott Main183bf112012-08-13 19:12:13 -07001487 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1488 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 *
Alan Viverette395cd012015-08-11 17:27:04 -04001490 * @param resId The desired style resource.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 * @param attrs The desired attributes in the style.
1492 *
1493 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
1494 *
1495 * @return Returns a TypedArray holding an array of the attribute values.
1496 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1497 * when done with it.
1498 *
1499 * @see Resources#obtainAttributes
1500 * @see #obtainStyledAttributes(int[])
1501 * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
1502 */
Alan Viverette395cd012015-08-11 17:27:04 -04001503 public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
Tor Norbyec91531a2015-04-01 17:41:55 -07001504 throws NotFoundException {
Alan Viverette395cd012015-08-11 17:27:04 -04001505 synchronized (mKey) {
1506 final int len = attrs.length;
1507 final TypedArray array = TypedArray.obtain(Resources.this, len);
1508 array.mTheme = this;
1509 AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
1510 return array;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 }
1513
1514 /**
John Spurlock330dd532012-12-18 12:03:11 -05001515 * Return a TypedArray holding the attribute values in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 * <var>set</var>
1517 * that are listed in <var>attrs</var>. In addition, if the given
1518 * AttributeSet specifies a style class (through the "style" attribute),
1519 * that style will be applied on top of the base attributes it defines.
1520 *
Scott Main183bf112012-08-13 19:12:13 -07001521 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
1522 * with the array.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 *
1524 * <p>When determining the final value of a particular attribute, there
1525 * are four inputs that come into play:</p>
1526 *
1527 * <ol>
1528 * <li> Any attribute values in the given AttributeSet.
1529 * <li> The style resource specified in the AttributeSet (named
1530 * "style").
1531 * <li> The default style specified by <var>defStyleAttr</var> and
1532 * <var>defStyleRes</var>
1533 * <li> The base values in this theme.
1534 * </ol>
1535 *
1536 * <p>Each of these inputs is considered in-order, with the first listed
1537 * taking precedence over the following ones. In other words, if in the
1538 * AttributeSet you have supplied <code>&lt;Button
1539 * textColor="#ff000000"&gt;</code>, then the button's text will
1540 * <em>always</em> be black, regardless of what is specified in any of
1541 * the styles.
1542 *
1543 * @param set The base set of attribute values. May be null.
1544 * @param attrs The desired attributes to be retrieved.
1545 * @param defStyleAttr An attribute in the current theme that contains a
1546 * reference to a style resource that supplies
John Spurlock330dd532012-12-18 12:03:11 -05001547 * defaults values for the TypedArray. Can be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 * 0 to not look for defaults.
1549 * @param defStyleRes A resource identifier of a style resource that
John Spurlock330dd532012-12-18 12:03:11 -05001550 * supplies default values for the TypedArray,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 * used only if defStyleAttr is 0 or can not be found
1552 * in the theme. Can be 0 to not look for defaults.
1553 *
1554 * @return Returns a TypedArray holding an array of the attribute values.
1555 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1556 * when done with it.
1557 *
1558 * @see Resources#obtainAttributes
1559 * @see #obtainStyledAttributes(int[])
1560 * @see #obtainStyledAttributes(int, int[])
1561 */
1562 public TypedArray obtainStyledAttributes(AttributeSet set,
Tor Norbyec91531a2015-04-01 17:41:55 -07001563 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
Alan Viverette395cd012015-08-11 17:27:04 -04001564 synchronized (mKey) {
1565 final int len = attrs.length;
1566 final TypedArray array = TypedArray.obtain(Resources.this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567
Alan Viverette395cd012015-08-11 17:27:04 -04001568 // XXX note that for now we only work with compiled XML files.
1569 // To support generic XML files we will need to manually parse
1570 // out the attributes from the XML file (applying type information
1571 // contained in the resources and such).
1572 final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1573 AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1574 parser != null ? parser.mParseState : 0,
1575 attrs, array.mData, array.mIndices);
1576 array.mTheme = this;
1577 array.mXml = parser;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578
Alan Viverette395cd012015-08-11 17:27:04 -04001579 return array;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 }
1582
1583 /**
Alan Viverette52b999f2014-03-24 18:00:26 -07001584 * Retrieve the values for a set of attributes in the Theme. The
1585 * contents of the typed array are ultimately filled in by
1586 * {@link Resources#getValue}.
1587 *
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001588 * @param values The base set of attribute values, must be equal in
1589 * length to {@code attrs}. All values must be of type
1590 * {@link TypedValue#TYPE_ATTRIBUTE}.
Alan Viverette52b999f2014-03-24 18:00:26 -07001591 * @param attrs The desired attributes to be retrieved.
Alan Viverette52b999f2014-03-24 18:00:26 -07001592 * @return Returns a TypedArray holding an array of the attribute
1593 * values. Be sure to call {@link TypedArray#recycle()}
1594 * when done with it.
1595 * @hide
1596 */
Alan Viverette7f4a63d2014-10-30 10:29:03 -07001597 @NonNull
1598 public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
Alan Viverette395cd012015-08-11 17:27:04 -04001599 synchronized (mKey) {
1600 final int len = attrs.length;
1601 if (values == null || len != values.length) {
1602 throw new IllegalArgumentException(
1603 "Base attribute values must the same length as attrs");
1604 }
1605
1606 final TypedArray array = TypedArray.obtain(Resources.this, len);
1607 AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1608 array.mTheme = this;
1609 array.mXml = null;
1610
1611 return array;
Alan Viverette52b999f2014-03-24 18:00:26 -07001612 }
Alan Viverette52b999f2014-03-24 18:00:26 -07001613 }
1614
1615 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 * Retrieve the value of an attribute in the Theme. The contents of
1617 * <var>outValue</var> are ultimately filled in by
1618 * {@link Resources#getValue}.
1619 *
1620 * @param resid The resource identifier of the desired theme
1621 * attribute.
1622 * @param outValue Filled in with the ultimate resource value supplied
1623 * by the attribute.
1624 * @param resolveRefs If true, resource references will be walked; if
1625 * false, <var>outValue</var> may be a
1626 * TYPE_REFERENCE. In either case, it will never
1627 * be a TYPE_ATTRIBUTE.
1628 *
1629 * @return boolean Returns true if the attribute was found and
1630 * <var>outValue</var> is valid, else false.
1631 */
Alan Viverette52b999f2014-03-24 18:00:26 -07001632 public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
Alan Viverette395cd012015-08-11 17:27:04 -04001633 synchronized (mKey) {
1634 return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 }
1637
1638 /**
Jon Miranda042ad632014-09-03 17:57:35 -07001639 * Gets all of the attribute ids associated with this {@link Theme}. For debugging only.
1640 *
1641 * @return The int array containing attribute ids associated with this {@link Theme}.
1642 * @hide
1643 */
1644 public int[] getAllAttributes() {
1645 return mAssets.getStyleAttributes(getAppliedStyleResId());
1646 }
1647
1648 /**
Alan Viverette52b999f2014-03-24 18:00:26 -07001649 * Returns the resources to which this theme belongs.
1650 *
1651 * @return Resources to which this theme belongs.
1652 */
1653 public Resources getResources() {
1654 return Resources.this;
1655 }
1656
1657 /**
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001658 * Return a drawable object associated with a particular resource ID
1659 * and styled for the Theme.
1660 *
1661 * @param id The desired resource identifier, as generated by the aapt
1662 * tool. This integer encodes the package, type, and resource
1663 * entry. The value 0 is an invalid identifier.
1664 * @return Drawable An object that can be used to draw this resource.
1665 * @throws NotFoundException Throws NotFoundException if the given ID
1666 * does not exist.
1667 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001668 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException {
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001669 return Resources.this.getDrawable(id, this);
1670 }
1671
1672 /**
Alan Viverettec1d52792015-05-05 09:49:03 -07001673 * Returns a bit mask of configuration changes that will impact this
1674 * theme (and thus require completely reloading it).
1675 *
1676 * @return a bit mask of configuration changes, as defined by
1677 * {@link ActivityInfo}
1678 * @see ActivityInfo
1679 */
1680 public int getChangingConfigurations() {
Alan Viverette395cd012015-08-11 17:27:04 -04001681 synchronized (mKey) {
1682 final int nativeChangingConfig =
1683 AssetManager.getThemeChangingConfigurations(mTheme);
1684 return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1685 }
Alan Viverettec1d52792015-05-05 09:49:03 -07001686 }
1687
1688 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 * Print contents of this theme out to the log. For debugging only.
1690 *
1691 * @param priority The log priority to use.
1692 * @param tag The log tag to use.
1693 * @param prefix Text to prefix each line printed.
1694 */
1695 public void dump(int priority, String tag, String prefix) {
Alan Viverette395cd012015-08-11 17:27:04 -04001696 synchronized (mKey) {
1697 AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001700
1701 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 protected void finalize() throws Throwable {
1703 super.finalize();
1704 mAssets.releaseTheme(mTheme);
1705 }
1706
1707 /*package*/ Theme() {
1708 mAssets = Resources.this.mAssets;
1709 mTheme = mAssets.createTheme();
1710 }
1711
Alan Viverettee54d2452015-05-06 10:41:43 -07001712 /** Unique key for the series of styles applied to this theme. */
1713 private final ThemeKey mKey = new ThemeKey();
1714
Alan Viverette8eea3ea2014-02-03 18:40:20 -08001715 @SuppressWarnings("hiding")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 private final AssetManager mAssets;
Ashok Bhat896043d2014-01-17 16:02:38 +00001717 private final long mTheme;
Alan Viverette52b999f2014-03-24 18:00:26 -07001718
Alan Viverette351f0c12014-03-28 15:25:27 -07001719 /** Resource identifier for the theme. */
Alan Viverette52b999f2014-03-24 18:00:26 -07001720 private int mThemeResId = 0;
Deepanshu Guptabfec73c2014-03-11 18:02:44 -07001721
1722 // Needed by layoutlib.
1723 /*package*/ long getNativeTheme() {
1724 return mTheme;
1725 }
1726
1727 /*package*/ int getAppliedStyleResId() {
1728 return mThemeResId;
1729 }
Alan Viverette75257ce2014-05-22 19:31:38 -07001730
Alan Viverettee54d2452015-05-06 10:41:43 -07001731 /*package*/ ThemeKey getKey() {
Alan Viverette75257ce2014-05-22 19:31:38 -07001732 return mKey;
1733 }
Jon Miranda836c0a82014-08-11 12:32:26 -07001734
1735 private String getResourceNameFromHexString(String hexString) {
1736 return getResourceName(Integer.parseInt(hexString, 16));
1737 }
1738
1739 /**
Alan Viverettee54d2452015-05-06 10:41:43 -07001740 * Parses {@link #mKey} and returns a String array that holds pairs of
1741 * adjacent Theme data: resource name followed by whether or not it was
1742 * forced, as specified by {@link #applyStyle(int, boolean)}.
Jon Miranda836c0a82014-08-11 12:32:26 -07001743 *
1744 * @hide
1745 */
1746 @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
1747 public String[] getTheme() {
Alan Viverette395cd012015-08-11 17:27:04 -04001748 synchronized (mKey) {
1749 final int N = mKey.mCount;
1750 final String[] themes = new String[N * 2];
1751 for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1752 final int resId = mKey.mResId[j];
1753 final boolean forced = mKey.mForce[j];
1754 try {
1755 themes[i] = getResourceName(resId);
1756 } catch (NotFoundException e) {
1757 themes[i] = Integer.toHexString(i);
1758 }
1759 themes[i + 1] = forced ? "forced" : "not forced";
Siva Velusamy0d857b92015-04-22 10:23:56 -07001760 }
Alan Viverette395cd012015-08-11 17:27:04 -04001761 return themes;
Jon Miranda836c0a82014-08-11 12:32:26 -07001762 }
Jon Miranda836c0a82014-08-11 12:32:26 -07001763 }
Alan Viverettee54d2452015-05-06 10:41:43 -07001764
Siva Velusamy0d857b92015-04-22 10:23:56 -07001765 /** @hide */
1766 public void encode(@NonNull ViewHierarchyEncoder encoder) {
1767 encoder.beginObject(this);
Alan Viveretteac674092015-05-08 11:04:47 -07001768 final String[] properties = getTheme();
Siva Velusamy0d857b92015-04-22 10:23:56 -07001769 for (int i = 0; i < properties.length; i += 2) {
1770 encoder.addProperty(properties[i], properties[i+1]);
1771 }
1772 encoder.endObject();
1773 }
1774
Alan Viverettee54d2452015-05-06 10:41:43 -07001775 /**
1776 * Rebases the theme against the parent Resource object's current
1777 * configuration by re-applying the styles passed to
1778 * {@link #applyStyle(int, boolean)}.
1779 *
1780 * @hide
1781 */
1782 public void rebase() {
Alan Viverette395cd012015-08-11 17:27:04 -04001783 synchronized (mKey) {
1784 AssetManager.clearTheme(mTheme);
Alan Viverettee54d2452015-05-06 10:41:43 -07001785
Alan Viverette395cd012015-08-11 17:27:04 -04001786 // Reapply the same styles in the same order.
1787 for (int i = 0; i < mKey.mCount; i++) {
1788 final int resId = mKey.mResId[i];
1789 final boolean force = mKey.mForce[i];
1790 AssetManager.applyThemeStyle(mTheme, resId, force);
1791 }
Alan Viverettee54d2452015-05-06 10:41:43 -07001792 }
1793 }
1794 }
1795
1796 static class ThemeKey implements Cloneable {
1797 int[] mResId;
1798 boolean[] mForce;
1799 int mCount;
1800
1801 private int mHashCode = 0;
1802
1803 public void append(int resId, boolean force) {
1804 if (mResId == null) {
1805 mResId = new int[4];
1806 }
1807
1808 if (mForce == null) {
1809 mForce = new boolean[4];
1810 }
1811
1812 mResId = GrowingArrayUtils.append(mResId, mCount, resId);
1813 mForce = GrowingArrayUtils.append(mForce, mCount, force);
1814 mCount++;
1815
1816 mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0);
1817 }
1818
1819 /**
1820 * Sets up this key as a deep copy of another key.
1821 *
1822 * @param other the key to deep copy into this key
1823 */
1824 public void setTo(ThemeKey other) {
1825 mResId = other.mResId == null ? null : other.mResId.clone();
1826 mForce = other.mForce == null ? null : other.mForce.clone();
1827 mCount = other.mCount;
1828 }
1829
1830 @Override
1831 public int hashCode() {
1832 return mHashCode;
1833 }
1834
1835 @Override
1836 public boolean equals(Object o) {
1837 if (this == o) {
1838 return true;
1839 }
1840
1841 if (o == null || getClass() != o.getClass() || hashCode() != o.hashCode()) {
1842 return false;
1843 }
1844
1845 final ThemeKey t = (ThemeKey) o;
1846 if (mCount != t.mCount) {
1847 return false;
1848 }
1849
1850 final int N = mCount;
1851 for (int i = 0; i < N; i++) {
1852 if (mResId[i] != t.mResId[i] || mForce[i] != t.mForce[i]) {
1853 return false;
1854 }
1855 }
1856
1857 return true;
1858 }
1859
1860 /**
1861 * @return a shallow copy of this key
1862 */
1863 @Override
1864 public ThemeKey clone() {
1865 final ThemeKey other = new ThemeKey();
1866 other.mResId = mResId;
1867 other.mForce = mForce;
1868 other.mCount = mCount;
John Reck4feb3262015-07-13 14:42:43 -07001869 other.mHashCode = mHashCode;
Alan Viverettee54d2452015-05-06 10:41:43 -07001870 return other;
1871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873
1874 /**
1875 * Generate a new Theme object for this set of Resources. It initially
1876 * starts out empty.
Jon Miranda836c0a82014-08-11 12:32:26 -07001877 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 * @return Theme The newly created Theme container.
1879 */
1880 public final Theme newTheme() {
1881 return new Theme();
1882 }
1883
1884 /**
1885 * Retrieve a set of basic attribute values from an AttributeSet, not
1886 * performing styling of them using a theme and/or style resources.
Jon Miranda836c0a82014-08-11 12:32:26 -07001887 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 * @param set The current attribute values to retrieve.
1889 * @param attrs The specific attributes to be retrieved.
1890 * @return Returns a TypedArray holding an array of the attribute values.
1891 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
1892 * when done with it.
1893 *
1894 * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
1895 */
1896 public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
1897 int len = attrs.length;
Alan Viverette52b999f2014-03-24 18:00:26 -07001898 TypedArray array = TypedArray.obtain(this, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899
1900 // XXX note that for now we only work with compiled XML files.
1901 // To support generic XML files we will need to manually parse
1902 // out the attributes from the XML file (applying type information
1903 // contained in the resources and such).
1904 XmlBlock.Parser parser = (XmlBlock.Parser)set;
1905 mAssets.retrieveAttributes(parser.mParseState, attrs,
1906 array.mData, array.mIndices);
1907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 array.mXml = parser;
1909
1910 return array;
1911 }
Mitsuru Oshimae5fb3282009-06-09 21:16:08 -07001912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 /**
1914 * Store the newly updated configuration.
1915 */
1916 public void updateConfiguration(Configuration config,
1917 DisplayMetrics metrics) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001918 updateConfiguration(config, metrics, null);
1919 }
1920
1921 /**
1922 * @hide
1923 */
1924 public void updateConfiguration(Configuration config,
1925 DisplayMetrics metrics, CompatibilityInfo compat) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08001926 synchronized (mAccessLock) {
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07001927 if (false) {
1928 Slog.i(TAG, "**** Updating config of " + this + ": old config is "
1929 + mConfiguration + " old compat is " + mCompatibilityInfo);
1930 Slog.i(TAG, "**** Updating config of " + this + ": new config is "
1931 + config + " new compat is " + compat);
1932 }
Dianne Hackborne2515ee2011-04-27 18:52:56 -04001933 if (compat != null) {
1934 mCompatibilityInfo = compat;
1935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 if (metrics != null) {
1937 mMetrics.setTo(metrics);
1938 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001939 // NOTE: We should re-arrange this code to create a Display
1940 // with the CompatibilityInfo that is used everywhere we deal
1941 // with the display in relation to this app, rather than
1942 // doing the conversion here. This impl should be okay because
1943 // we make sure to return a compatible display in the places
1944 // where there are public APIs to retrieve the display... but
1945 // it would be cleaner and more maintainble to just be
1946 // consistently dealing with a compatible display everywhere in
1947 // the framework.
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07001948 mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
1949
Alan Viverettea8636c92015-03-27 10:44:39 -07001950 final int configChanges = calcConfigChanges(config);
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08001951
Roozbeh Pournader47571c72015-09-01 14:07:04 -07001952 LocaleList locales = mConfiguration.getLocales();
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08001953 final boolean setLocalesToDefault = locales.isEmpty();
1954 if (setLocalesToDefault) {
Roozbeh Pournader47571c72015-09-01 14:07:04 -07001955 locales = LocaleList.getDefault();
1956 mConfiguration.setLocales(locales);
Dianne Hackborn5fd21692011-06-07 14:09:47 -07001957 }
Dianne Hackborn756220b2012-08-14 16:45:30 -07001958 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
1959 mMetrics.densityDpi = mConfiguration.densityDpi;
1960 mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1961 }
Dianne Hackborn2b31d532011-06-23 11:58:50 -07001962 mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
Mitsuru Oshima8169dae2009-04-28 18:12:09 -07001963
Alan Viverettea8636c92015-03-27 10:44:39 -07001964 final int width, height;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 if (mMetrics.widthPixels >= mMetrics.heightPixels) {
1966 width = mMetrics.widthPixels;
1967 height = mMetrics.heightPixels;
1968 } else {
1969 //noinspection SuspiciousNameCombination
1970 width = mMetrics.heightPixels;
1971 //noinspection SuspiciousNameCombination
1972 height = mMetrics.widthPixels;
1973 }
Alan Viverettea8636c92015-03-27 10:44:39 -07001974
1975 final int keyboardHidden;
1976 if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
1977 && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
Alan Viverettea8636c92015-03-27 10:44:39 -07001979 } else {
1980 keyboardHidden = mConfiguration.keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
Alan Viverettea8636c92015-03-27 10:44:39 -07001982
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08001983 if (setLocalesToDefault || mResolvedLocale == null
1984 || (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) {
Roozbeh Pournader1c686f22015-12-18 14:22:14 -08001985 if (locales.size() == 1) {
1986 // This is an optimization to avoid the JNI call(s) when the result of
Roozbeh Pournaderfb9236c2015-12-15 23:56:11 -08001987 // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
Roozbeh Pournader1c686f22015-12-18 14:22:14 -08001988 mResolvedLocale = locales.getPrimary();
1989 } else {
1990 String[] supportedLocales = mAssets.getNonSystemLocales();
1991 if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
1992 // We fallback to all locales (including system locales) if there was no
1993 // locale specifically supported by the assets. This is to properly support
1994 // apps that only rely on the shared system assets and don't need assets of
1995 // their own.
1996 supportedLocales = mAssets.getLocales();
1997 }
Roozbeh Pournaderfb9236c2015-12-15 23:56:11 -08001998 mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
Roozbeh Pournader1c686f22015-12-18 14:22:14 -08001999 }
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08002000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08002002 adjustLanguageTag(mResolvedLocale.toLanguageTag()),
Roozbeh Pournader47571c72015-09-01 14:07:04 -07002003 mConfiguration.orientation,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 mConfiguration.touchscreen,
Dianne Hackborn908aecc2012-07-31 16:37:34 -07002005 mConfiguration.densityDpi, mConfiguration.keyboard,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 keyboardHidden, mConfiguration.navigation, width, height,
Dianne Hackborn69cb8752011-05-19 18:13:32 -07002007 mConfiguration.smallestScreenWidthDp,
Dianne Hackbornebff8f92011-05-12 18:07:47 -07002008 mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
Dianne Hackborn3b81bc12011-01-15 11:50:52 -08002009 mConfiguration.screenLayout, mConfiguration.uiMode,
2010 Build.VERSION.RESOURCES_SDK_INT);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002011
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002012 if (DEBUG_CONFIG) {
Alan Viverette4d07bc92015-11-16 10:19:12 -05002013 Slog.i(TAG, "**** Updating config of " + this + ": final config is "
2014 + mConfiguration + " final compat is " + mCompatibilityInfo);
Dianne Hackborn2f0b1752011-05-31 17:59:49 -07002015 }
2016
Alan Viverettee54d2452015-05-06 10:41:43 -07002017 mDrawableCache.onConfigurationChange(configChanges);
2018 mColorDrawableCache.onConfigurationChange(configChanges);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002019 mColorStateListCache.onConfigurationChange(configChanges);
Yigit Boyard422dc32014-09-25 12:23:35 -07002020 mAnimatorCache.onConfigurationChange(configChanges);
2021 mStateListAnimatorCache.onConfigurationChange(configChanges);
Masanori Oginoc7d9d272010-07-10 12:10:41 +09002022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 flushLayoutCache();
2024 }
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002025 synchronized (sSync) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 if (mPluralRule != null) {
Roozbeh Pournaderdad10062015-12-14 16:15:52 -08002027 mPluralRule = PluralRules.forLocale(mResolvedLocale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 }
2029 }
2030 }
2031
Yigit Boyard422dc32014-09-25 12:23:35 -07002032 /**
2033 * Called by ConfigurationBoundResourceCacheTest via reflection.
2034 */
2035 private int calcConfigChanges(Configuration config) {
2036 int configChanges = 0xfffffff;
2037 if (config != null) {
2038 mTmpConfig.setTo(config);
2039 int density = config.densityDpi;
2040 if (density == Configuration.DENSITY_DPI_UNDEFINED) {
2041 density = mMetrics.noncompatDensityDpi;
2042 }
2043
2044 mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
2045
Roozbeh Pournader47571c72015-09-01 14:07:04 -07002046 if (mTmpConfig.getLocales().isEmpty()) {
2047 mTmpConfig.setLocales(LocaleList.getDefault());
Yigit Boyard422dc32014-09-25 12:23:35 -07002048 }
2049 configChanges = mConfiguration.updateFrom(mTmpConfig);
2050 configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
2051 }
2052 return configChanges;
2053 }
2054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 /**
Narayan Kamath21fc8ba2014-03-05 18:42:23 +00002056 * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
2057 * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
2058 *
2059 * All released versions of android prior to "L" used the deprecated language
2060 * tags, so we will need to support them for backwards compatibility.
2061 *
2062 * Note that this conversion needs to take place *after* the call to
2063 * {@code toLanguageTag} because that will convert all the deprecated codes to
2064 * the new ones, even if they're set manually.
2065 */
2066 private static String adjustLanguageTag(String languageTag) {
2067 final int separator = languageTag.indexOf('-');
2068 final String language;
2069 final String remainder;
2070
2071 if (separator == -1) {
2072 language = languageTag;
2073 remainder = "";
2074 } else {
2075 language = languageTag.substring(0, separator);
2076 remainder = languageTag.substring(separator);
2077 }
2078
Narayan Kamath4c6ce232014-07-18 16:09:36 +01002079 return Locale.adjustLanguageCode(language) + remainder;
Narayan Kamath21fc8ba2014-03-05 18:42:23 +00002080 }
2081
2082 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 * Update the system resources configuration if they have previously
2084 * been initialized.
2085 *
2086 * @hide
2087 */
Dianne Hackborne2515ee2011-04-27 18:52:56 -04002088 public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics,
2089 CompatibilityInfo compat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 if (mSystem != null) {
Dianne Hackborne2515ee2011-04-27 18:52:56 -04002091 mSystem.updateConfiguration(config, metrics, compat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002092 //Log.i(TAG, "Updated system resources " + mSystem
2093 // + ": " + mSystem.getConfiguration());
2094 }
2095 }
2096
2097 /**
2098 * Return the current display metrics that are in effect for this resource
2099 * object. The returned object should be treated as read-only.
2100 *
2101 * @return The resource's current display metrics.
2102 */
2103 public DisplayMetrics getDisplayMetrics() {
Dianne Hackborn5fd21692011-06-07 14:09:47 -07002104 if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
2105 + "x" + mMetrics.heightPixels + " " + mMetrics.density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 return mMetrics;
2107 }
2108
2109 /**
2110 * Return the current configuration that is in effect for this resource
2111 * object. The returned object should be treated as read-only.
2112 *
2113 * @return The resource's current configuration.
2114 */
2115 public Configuration getConfiguration() {
2116 return mConfiguration;
2117 }
Filip Gruszczynski23493322015-07-29 17:02:59 -07002118
2119 /** @hide */
2120 public Configuration[] getSizeConfigurations() {
2121 return mAssets.getSizeConfigurations();
2122 };
2123
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002124 /**
2125 * Return the compatibility mode information for the application.
2126 * The returned object should be treated as read-only.
2127 *
Dianne Hackborn3904d032011-05-27 12:09:11 -07002128 * @return compatibility info.
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002129 * @hide
2130 */
2131 public CompatibilityInfo getCompatibilityInfo() {
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07002132 return mCompatibilityInfo;
Mitsuru Oshima9189cab2009-06-03 11:19:12 -07002133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002134
2135 /**
Dianne Hackborna53b8282009-07-17 11:13:48 -07002136 * This is just for testing.
2137 * @hide
2138 */
2139 public void setCompatibilityInfo(CompatibilityInfo ci) {
Adam Lesinski79a8ffe2013-09-19 20:33:15 -07002140 if (ci != null) {
2141 mCompatibilityInfo = ci;
2142 updateConfiguration(mConfiguration, mMetrics);
2143 }
Dianne Hackborna53b8282009-07-17 11:13:48 -07002144 }
2145
2146 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 * Return a resource identifier for the given resource name. A fully
2148 * qualified resource name is of the form "package:type/entry". The first
2149 * two components (package and type) are optional if defType and
2150 * defPackage, respectively, are specified here.
2151 *
2152 * <p>Note: use of this function is discouraged. It is much more
2153 * efficient to retrieve resources by identifier than by name.
2154 *
2155 * @param name The name of the desired resource.
2156 * @param defType Optional default resource type to find, if "type/" is
2157 * not included in the name. Can be null to require an
2158 * explicit type.
2159 * @param defPackage Optional default package to find, if "package:" is
2160 * not included in the name. Can be null to require an
2161 * explicit package.
2162 *
2163 * @return int The associated resource identifier. Returns 0 if no such
2164 * resource was found. (0 is not a valid resource ID.)
2165 */
2166 public int getIdentifier(String name, String defType, String defPackage) {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002167 if (name == null) {
2168 throw new NullPointerException("name is null");
2169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 try {
2171 return Integer.parseInt(name);
2172 } catch (Exception e) {
2173 // Ignore
2174 }
2175 return mAssets.getResourceIdentifier(name, defType, defPackage);
2176 }
2177
2178 /**
Jeff Sharkey47b50332013-03-15 14:46:46 -07002179 * Return true if given resource identifier includes a package.
2180 *
2181 * @hide
2182 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002183 public static boolean resourceHasPackage(@AnyRes int resid) {
Jeff Sharkey47b50332013-03-15 14:46:46 -07002184 return (resid >>> 24) != 0;
2185 }
2186
2187 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 * Return the full name for a given resource identifier. This name is
2189 * a single string of the form "package:type/entry".
2190 *
2191 * @param resid The resource identifier whose name is to be retrieved.
2192 *
2193 * @return A string holding the name of the resource.
2194 *
2195 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2196 *
2197 * @see #getResourcePackageName
2198 * @see #getResourceTypeName
2199 * @see #getResourceEntryName
2200 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002201 public String getResourceName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 String str = mAssets.getResourceName(resid);
2203 if (str != null) return str;
2204 throw new NotFoundException("Unable to find resource ID #0x"
2205 + Integer.toHexString(resid));
2206 }
2207
2208 /**
2209 * Return the package name for a given resource identifier.
2210 *
2211 * @param resid The resource identifier whose package name is to be
2212 * retrieved.
2213 *
2214 * @return A string holding the package name of the resource.
2215 *
2216 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2217 *
2218 * @see #getResourceName
2219 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002220 public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 String str = mAssets.getResourcePackageName(resid);
2222 if (str != null) return str;
2223 throw new NotFoundException("Unable to find resource ID #0x"
2224 + Integer.toHexString(resid));
2225 }
2226
2227 /**
2228 * Return the type name for a given resource identifier.
2229 *
2230 * @param resid The resource identifier whose type name is to be
2231 * retrieved.
2232 *
2233 * @return A string holding the type name of the resource.
2234 *
2235 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2236 *
2237 * @see #getResourceName
2238 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002239 public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 String str = mAssets.getResourceTypeName(resid);
2241 if (str != null) return str;
2242 throw new NotFoundException("Unable to find resource ID #0x"
2243 + Integer.toHexString(resid));
2244 }
2245
2246 /**
2247 * Return the entry name for a given resource identifier.
2248 *
2249 * @param resid The resource identifier whose entry name is to be
2250 * retrieved.
2251 *
2252 * @return A string holding the entry name of the resource.
2253 *
2254 * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
2255 *
2256 * @see #getResourceName
2257 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07002258 public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 String str = mAssets.getResourceEntryName(resid);
2260 if (str != null) return str;
2261 throw new NotFoundException("Unable to find resource ID #0x"
2262 + Integer.toHexString(resid));
2263 }
2264
2265 /**
2266 * Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
2267 * an XML file. You call this when you are at the parent tag of the
Dianne Hackborndef15372010-08-15 12:43:52 -07002268 * 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 -08002269 * This will call {@link #parseBundleExtra} for each extra tag encountered.
2270 *
2271 * @param parser The parser from which to retrieve the extras.
2272 * @param outBundle A Bundle in which to place all parsed extras.
2273 * @throws XmlPullParserException
2274 * @throws IOException
2275 */
2276 public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)
2277 throws XmlPullParserException, IOException {
2278 int outerDepth = parser.getDepth();
2279 int type;
2280 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
2281 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
2282 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2283 continue;
2284 }
2285
2286 String nodeName = parser.getName();
2287 if (nodeName.equals("extra")) {
2288 parseBundleExtra("extra", parser, outBundle);
2289 XmlUtils.skipCurrentTag(parser);
2290
2291 } else {
2292 XmlUtils.skipCurrentTag(parser);
2293 }
2294 }
2295 }
2296
2297 /**
2298 * Parse a name/value pair out of an XML tag holding that data. The
2299 * AttributeSet must be holding the data defined by
2300 * {@link android.R.styleable#Extra}. The following value types are supported:
2301 * <ul>
2302 * <li> {@link TypedValue#TYPE_STRING}:
2303 * {@link Bundle#putCharSequence Bundle.putCharSequence()}
2304 * <li> {@link TypedValue#TYPE_INT_BOOLEAN}:
2305 * {@link Bundle#putCharSequence Bundle.putBoolean()}
2306 * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}:
2307 * {@link Bundle#putCharSequence Bundle.putBoolean()}
2308 * <li> {@link TypedValue#TYPE_FLOAT}:
2309 * {@link Bundle#putCharSequence Bundle.putFloat()}
2310 * </ul>
2311 *
2312 * @param tagName The name of the tag these attributes come from; this is
2313 * only used for reporting error messages.
2314 * @param attrs The attributes from which to retrieve the name/value pair.
2315 * @param outBundle The Bundle in which to place the parsed value.
2316 * @throws XmlPullParserException If the attributes are not valid.
2317 */
2318 public void parseBundleExtra(String tagName, AttributeSet attrs,
2319 Bundle outBundle) throws XmlPullParserException {
2320 TypedArray sa = obtainAttributes(attrs,
2321 com.android.internal.R.styleable.Extra);
2322
2323 String name = sa.getString(
2324 com.android.internal.R.styleable.Extra_name);
2325 if (name == null) {
2326 sa.recycle();
2327 throw new XmlPullParserException("<" + tagName
2328 + "> requires an android:name attribute at "
2329 + attrs.getPositionDescription());
2330 }
2331
2332 TypedValue v = sa.peekValue(
2333 com.android.internal.R.styleable.Extra_value);
2334 if (v != null) {
2335 if (v.type == TypedValue.TYPE_STRING) {
2336 CharSequence cs = v.coerceToString();
2337 outBundle.putCharSequence(name, cs);
2338 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
2339 outBundle.putBoolean(name, v.data != 0);
2340 } else if (v.type >= TypedValue.TYPE_FIRST_INT
2341 && v.type <= TypedValue.TYPE_LAST_INT) {
2342 outBundle.putInt(name, v.data);
2343 } else if (v.type == TypedValue.TYPE_FLOAT) {
2344 outBundle.putFloat(name, v.getFloat());
2345 } else {
2346 sa.recycle();
2347 throw new XmlPullParserException("<" + tagName
2348 + "> only supports string, integer, float, color, and boolean at "
2349 + attrs.getPositionDescription());
2350 }
2351 } else {
2352 sa.recycle();
2353 throw new XmlPullParserException("<" + tagName
2354 + "> requires an android:value or android:resource attribute at "
2355 + attrs.getPositionDescription());
2356 }
2357
2358 sa.recycle();
2359 }
2360
2361 /**
2362 * Retrieve underlying AssetManager storage for these resources.
2363 */
2364 public final AssetManager getAssets() {
2365 return mAssets;
2366 }
2367
2368 /**
2369 * Call this to remove all cached loaded layout resources from the
2370 * Resources object. Only intended for use with performance testing
2371 * tools.
2372 */
2373 public final void flushLayoutCache() {
Alan Viverette10979612016-01-06 15:27:35 -05002374 final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
2375 final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
2376 synchronized (cachedXmlBlockFiles) {
2377 final int num = cachedXmlBlockFiles.length;
2378 for (int i = 0; i < num; i++) {
2379 final XmlBlock oldBlock = cachedXmlBlocks[i];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002380 if (oldBlock != null) {
2381 oldBlock.close();
2382 }
Alan Viverette10979612016-01-06 15:27:35 -05002383 cachedXmlBlockFiles[i] = null;
2384 cachedXmlBlocks[i] = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002385 }
2386 }
2387 }
2388
2389 /**
2390 * Start preloading of resource data using this Resources object. Only
2391 * for use by the zygote process for loading common system resources.
2392 * {@hide}
2393 */
2394 public final void startPreloading() {
Dianne Hackborn50707cc2013-02-08 15:32:05 -08002395 synchronized (sSync) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002396 if (sPreloaded) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 throw new IllegalStateException("Resources already preloaded");
2398 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002399 sPreloaded = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 mPreloading = true;
Alan Viverette4d07bc92015-11-16 10:19:12 -05002401 mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
Dianne Hackborndde331c2012-08-03 14:01:57 -07002402 updateConfiguration(null, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002403 }
2404 }
2405
2406 /**
2407 * Called by zygote when it is done preloading resources, to change back
2408 * to normal Resources operation.
2409 */
2410 public final void finishPreloading() {
2411 if (mPreloading) {
2412 mPreloading = false;
2413 flushLayoutCache();
2414 }
2415 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002416
Romain Guy3b748a42013-04-17 18:54:38 -07002417 /**
2418 * @hide
2419 */
Alan Viverette52b999f2014-03-24 18:00:26 -07002420 public LongSparseArray<ConstantState> getPreloadedDrawables() {
Romain Guy3b748a42013-04-17 18:54:38 -07002421 return sPreloadedDrawables[0];
2422 }
2423
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002424 private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
2425 int resourceId, String name) {
2426 // We allow preloading of resources even if they vary by font scale (which
2427 // doesn't impact resource selection) or density (which we handle specially by
2428 // simply turning off all preloading), as well as any other configs specified
2429 // by the caller.
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002430 if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002431 ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
Dianne Hackborndde331c2012-08-03 14:01:57 -07002432 String resName;
2433 try {
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002434 resName = getResourceName(resourceId);
Dianne Hackborndde331c2012-08-03 14:01:57 -07002435 } catch (NotFoundException e) {
2436 resName = "?";
2437 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002438 // This should never happen in production, so we should log a
2439 // warning even if we're not debugging.
Dianne Hackborndde331c2012-08-03 14:01:57 -07002440 Log.w(TAG, "Preloaded " + name + " resource #0x"
Fabrice Di Megliodc25d252013-04-09 18:04:29 -07002441 + Integer.toHexString(resourceId)
Dianne Hackborndde331c2012-08-03 14:01:57 -07002442 + " (" + resName + ") that varies with configuration!!");
2443 return false;
2444 }
Fabrice Di Megliob9a13b82013-04-15 14:05:30 -07002445 if (TRACE_FOR_PRELOAD) {
2446 String resName;
2447 try {
2448 resName = getResourceName(resourceId);
2449 } catch (NotFoundException e) {
2450 resName = "?";
2451 }
2452 Log.w(TAG, "Preloading " + name + " resource #0x"
2453 + Integer.toHexString(resourceId)
2454 + " (" + resName + ")");
2455 }
Dianne Hackborndde331c2012-08-03 14:01:57 -07002456 return true;
2457 }
2458
Alan Viverette0f1c95e2015-06-05 10:17:21 -07002459 @Nullable
2460 Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
Alan Viverette7941a7f2016-01-06 11:11:53 -05002461 return loadDrawable(value, id, theme, true);
2462 }
2463
2464 @Nullable
2465 Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
2466 throws NotFoundException {
Alan Viverettec078c602015-12-08 14:49:13 -05002467 try {
2468 if (TRACE_FOR_PRELOAD) {
2469 // Log only framework resources
2470 if ((id >>> 24) == 0x1) {
2471 final String name = getResourceName(id);
2472 if (name != null) {
2473 Log.d("PreloadDrawable", name);
2474 }
Alan Viverette8eea3ea2014-02-03 18:40:20 -08002475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477
Alan Viverettec078c602015-12-08 14:49:13 -05002478 final boolean isColorDrawable;
2479 final DrawableCache caches;
2480 final long key;
2481 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
2482 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
2483 isColorDrawable = true;
2484 caches = mColorDrawableCache;
2485 key = value.data;
2486 } else {
2487 isColorDrawable = false;
2488 caches = mDrawableCache;
2489 key = (((long) value.assetCookie) << 32) | value.data;
Alan Viverette52b999f2014-03-24 18:00:26 -07002490 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002491
Alan Viverettec078c602015-12-08 14:49:13 -05002492 // First, check whether we have a cached version of this drawable
Alan Viverette7941a7f2016-01-06 11:11:53 -05002493 // that was inflated against the specified theme. Skip the cache if
2494 // we're currently preloading or we're not using the cache.
2495 if (!mPreloading && useCache) {
Alan Viverettec078c602015-12-08 14:49:13 -05002496 final Drawable cachedDrawable = caches.getInstance(key, theme);
2497 if (cachedDrawable != null) {
2498 return cachedDrawable;
2499 }
2500 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002501
Alan Viverette7941a7f2016-01-06 11:11:53 -05002502 // Next, check preloaded drawables. Preloaded drawables may contain
2503 // unresolved theme attributes.
Alan Viverettec078c602015-12-08 14:49:13 -05002504 final ConstantState cs;
2505 if (isColorDrawable) {
2506 cs = sPreloadedColorDrawables.get(key);
2507 } else {
2508 cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
2509 }
Alan Viverette4325f8e2015-04-01 15:00:30 -07002510
Alan Viverettec078c602015-12-08 14:49:13 -05002511 Drawable dr;
2512 if (cs != null) {
2513 dr = cs.newDrawable(this);
2514 } else if (isColorDrawable) {
2515 dr = new ColorDrawable(value.data);
2516 } else {
2517 dr = loadDrawableForCookie(value, id, null);
2518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519
Alan Viverettec078c602015-12-08 14:49:13 -05002520 // Determine if the drawable has unresolved theme attributes. If it
2521 // does, we'll need to apply a theme and store it in a theme-specific
2522 // cache.
2523 final boolean canApplyTheme = dr != null && dr.canApplyTheme();
2524 if (canApplyTheme && theme != null) {
2525 dr = dr.mutate();
2526 dr.applyTheme(theme);
2527 dr.clearMutated();
2528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529
Alan Viverettec078c602015-12-08 14:49:13 -05002530 // If we were able to obtain a drawable, store it in the appropriate
Alan Viverette7941a7f2016-01-06 11:11:53 -05002531 // cache: preload, not themed, null theme, or theme-specific. Don't
2532 // pollute the cache with drawables loaded from a foreign density.
2533 if (dr != null && useCache) {
Alan Viverettec078c602015-12-08 14:49:13 -05002534 dr.setChangingConfigurations(value.changingConfigurations);
2535 cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
2536 }
2537
2538 return dr;
2539 } catch (Exception e) {
2540 String name;
2541 try {
2542 name = getResourceName(id);
2543 } catch (NotFoundException e2) {
2544 name = "(missing name)";
2545 }
2546
2547 // The target drawable might fail to load for any number of
2548 // reasons, but we always want to include the resource name.
2549 // Since the client already expects this method to throw a
2550 // NotFoundException, just throw one of those.
2551 final NotFoundException nfe = new NotFoundException("Drawable " + name
2552 + " with resource ID #0x" + Integer.toHexString(id), e);
2553 nfe.setStackTrace(new StackTraceElement[0]);
2554 throw nfe;
2555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 }
2557
Alan Viverettee54d2452015-05-06 10:41:43 -07002558 private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
2559 Theme theme, boolean usesTheme, long key, Drawable dr) {
Alan Viverette52b999f2014-03-24 18:00:26 -07002560 final ConstantState cs = dr.getConstantState();
2561 if (cs == null) {
2562 return;
2563 }
2564
Alan Viverette52b999f2014-03-24 18:00:26 -07002565 if (mPreloading) {
Alan Viverette52b999f2014-03-24 18:00:26 -07002566 final int changingConfigs = cs.getChangingConfigurations();
2567 if (isColorDrawable) {
2568 if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
2569 sPreloadedColorDrawables.put(key, cs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002571 } else {
2572 if (verifyPreloadConfig(
2573 changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
2574 if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
2575 // If this resource does not vary based on layout direction,
2576 // we can put it in all of the preload maps.
2577 sPreloadedDrawables[0].put(key, cs);
2578 sPreloadedDrawables[1].put(key, cs);
2579 } else {
2580 // Otherwise, only in the layout dir we loaded it for.
2581 sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
2582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002583 }
2584 }
Alan Viverette52b999f2014-03-24 18:00:26 -07002585 } else {
2586 synchronized (mAccessLock) {
Alan Viverettee54d2452015-05-06 10:41:43 -07002587 caches.put(key, theme, cs, usesTheme);
Alan Viverette52b999f2014-03-24 18:00:26 -07002588 }
2589 }
2590 }
2591
2592 /**
2593 * Loads a drawable from XML or resources stream.
2594 */
2595 private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
2596 if (value.string == null) {
Alan Viverette0810b632014-05-01 14:42:56 -07002597 throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002598 + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
Alan Viverette52b999f2014-03-24 18:00:26 -07002599 }
2600
2601 final String file = value.string.toString();
2602
2603 if (TRACE_FOR_MISS_PRELOAD) {
2604 // Log only framework resources
2605 if ((id >>> 24) == 0x1) {
2606 final String name = getResourceName(id);
2607 if (name != null) {
2608 Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
2609 + ": " + name + " at " + file);
2610 }
2611 }
2612 }
2613
2614 if (DEBUG_LOAD) {
2615 Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
2616 }
2617
2618 final Drawable dr;
2619
2620 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
2621 try {
2622 if (file.endsWith(".xml")) {
2623 final XmlResourceParser rp = loadXmlResourceParser(
2624 file, id, value.assetCookie, "drawable");
Alan Viverette6dbe51b2014-06-02 16:39:04 -07002625 dr = Drawable.createFromXml(this, rp, theme);
Alan Viverette52b999f2014-03-24 18:00:26 -07002626 rp.close();
2627 } else {
2628 final InputStream is = mAssets.openNonAsset(
2629 value.assetCookie, file, AssetManager.ACCESS_STREAMING);
Alan Viverette6dbe51b2014-06-02 16:39:04 -07002630 dr = Drawable.createFromResourceStream(this, value, is, file, null);
Alan Viverette52b999f2014-03-24 18:00:26 -07002631 is.close();
2632 }
2633 } catch (Exception e) {
2634 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2635 final NotFoundException rnf = new NotFoundException(
2636 "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
2637 rnf.initCause(e);
2638 throw rnf;
2639 }
2640 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2641
2642 return dr;
2643 }
2644
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002645 @Nullable
2646 ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 throws NotFoundException {
2648 if (TRACE_FOR_PRELOAD) {
2649 // Log only framework resources
2650 if ((id >>> 24) == 0x1) {
2651 final String name = getResourceName(id);
2652 if (name != null) android.util.Log.d("PreloadColorStateList", name);
2653 }
2654 }
2655
Romain Guy5d911c32012-04-12 16:25:17 -07002656 final long key = (((long) value.assetCookie) << 32) | value.data;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657
2658 ColorStateList csl;
2659
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002660 // Handle inline color definitions.
2661 if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
2662 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002663 final android.content.res.ConstantState<ColorStateList> factory =
2664 sPreloadedColorStateLists.get(key);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002665 if (factory != null) {
2666 return factory.newInstance();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002667 }
2668
2669 csl = ColorStateList.valueOf(value.data);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002672 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2673 "color")) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002674 sPreloadedColorStateLists.put(key, csl.getConstantState());
Dianne Hackborndde331c2012-08-03 14:01:57 -07002675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676 }
2677
2678 return csl;
2679 }
2680
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002681 final ConfigurationBoundResourceCache<ColorStateList> cache = mColorStateListCache;
Alan Viverettee54d2452015-05-06 10:41:43 -07002682 csl = cache.getInstance(key, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 if (csl != null) {
2684 return csl;
2685 }
2686
Alan Viverettee0f95f32015-04-01 13:10:18 -07002687 final android.content.res.ConstantState<ColorStateList> factory =
2688 sPreloadedColorStateLists.get(key);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002689 if (factory != null) {
2690 csl = factory.newInstance(this, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 }
2692
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002693 if (csl == null) {
2694 csl = loadColorStateListForCookie(value, id, theme);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695 }
2696
2697 if (csl != null) {
2698 if (mPreloading) {
Dianne Hackbornf1ae2692013-04-19 14:09:37 -07002699 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
2700 "color")) {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002701 sPreloadedColorStateLists.put(key, csl.getConstantState());
Dianne Hackborndde331c2012-08-03 14:01:57 -07002702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 } else {
Alan Viverettee0f95f32015-04-01 13:10:18 -07002704 cache.put(key, theme, csl.getConstantState());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 }
2706 }
2707
2708 return csl;
2709 }
2710
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002711 private ColorStateList loadColorStateListForCookie(TypedValue value, int id, Theme theme) {
2712 if (value.string == null) {
Alan Viverette6bbb47b2015-01-05 18:12:44 -08002713 throw new UnsupportedOperationException(
2714 "Can't convert to color state list: type=0x" + value.type);
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002715 }
2716
2717 final String file = value.string.toString();
2718
2719 if (TRACE_FOR_MISS_PRELOAD) {
2720 // Log only framework resources
2721 if ((id >>> 24) == 0x1) {
2722 final String name = getResourceName(id);
2723 if (name != null) {
2724 Log.d(TAG, "Loading framework color state list #" + Integer.toHexString(id)
2725 + ": " + name + " at " + file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 }
2727 }
2728 }
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002729
2730 if (DEBUG_LOAD) {
2731 Log.v(TAG, "Loading color state list for cookie " + value.assetCookie + ": " + file);
2732 }
2733
2734 final ColorStateList csl;
2735
2736 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
2737 if (file.endsWith(".xml")) {
2738 try {
2739 final XmlResourceParser rp = loadXmlResourceParser(
2740 file, id, value.assetCookie, "colorstatelist");
2741 csl = ColorStateList.createFromXml(this, rp, theme);
2742 rp.close();
2743 } catch (Exception e) {
2744 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2745 final NotFoundException rnf = new NotFoundException(
2746 "File " + file + " from color state list resource ID #0x"
2747 + Integer.toHexString(id));
2748 rnf.initCause(e);
2749 throw rnf;
2750 }
2751 } else {
2752 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2753 throw new NotFoundException(
2754 "File " + file + " from drawable resource ID #0x"
2755 + Integer.toHexString(id) + ": .xml extension required");
2756 }
2757 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
2758
2759 return csl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002760 }
2761
Alan Viverette10979612016-01-06 15:27:35 -05002762 /**
2763 * Loads an XML parser for the specified file.
2764 *
2765 * @param id the resource identifier for the file
2766 * @param type the type of resource (used for logging)
2767 * @return a parser for the specified XML file
2768 * @throws NotFoundException if the file could not be loaded
2769 */
2770 @NonNull
2771 XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002772 throws NotFoundException {
Alan Viverette4d07bc92015-11-16 10:19:12 -05002773 final TypedValue value = obtainTempTypedValue(id);
2774 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 if (value.type == TypedValue.TYPE_STRING) {
2776 return loadXmlResourceParser(value.string.toString(), id,
2777 value.assetCookie, type);
2778 }
Alan Viverette4d07bc92015-11-16 10:19:12 -05002779 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
2780 + " type #0x" + Integer.toHexString(value.type) + " is not valid");
2781 } finally {
2782 releaseTempTypedValue(value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 }
2784 }
Alan Viverette10979612016-01-06 15:27:35 -05002785
2786 /**
2787 * Loads an XML parser for the specified file.
2788 *
2789 * @param file the path for the XML file to parse
2790 * @param id the resource identifier for the file
2791 * @param assetCookie the asset cookie for the file
2792 * @param type the type of resource (used for logging)
2793 * @return a parser for the specified XML file
2794 * @throws NotFoundException if the file could not be loaded
2795 */
2796 @NonNull
2797 XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
2798 int assetCookie, @NonNull String type) throws NotFoundException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002799 if (id != 0) {
2800 try {
Alan Viverette10979612016-01-06 15:27:35 -05002801 final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
2802 final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
2803 synchronized (cachedXmlBlockFiles) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 // First see if this block is in our cache.
Alan Viverette10979612016-01-06 15:27:35 -05002805 final int num = cachedXmlBlockFiles.length;
2806 for (int i = 0; i < num; i++) {
2807 if (cachedXmlBlockFiles[i] != null
2808 && cachedXmlBlockFiles[i].equals(file)) {
2809 return cachedXmlBlocks[i].newParser();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002810 }
2811 }
2812
2813 // Not in the cache, create a new block and put it at
2814 // the next slot in the cache.
Alan Viverette10979612016-01-06 15:27:35 -05002815 final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816 if (block != null) {
Alan Viverette10979612016-01-06 15:27:35 -05002817 final int pos = (mLastCachedXmlBlockIndex + 1) % num;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818 mLastCachedXmlBlockIndex = pos;
Alan Viverette10979612016-01-06 15:27:35 -05002819 final XmlBlock oldBlock = cachedXmlBlocks[pos];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820 if (oldBlock != null) {
2821 oldBlock.close();
2822 }
Alan Viverette10979612016-01-06 15:27:35 -05002823 cachedXmlBlockFiles[pos] = file;
2824 cachedXmlBlocks[pos] = block;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002825 return block.newParser();
2826 }
2827 }
2828 } catch (Exception e) {
Alan Viverette10979612016-01-06 15:27:35 -05002829 final NotFoundException rnf = new NotFoundException("File " + file
2830 + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 rnf.initCause(e);
2832 throw rnf;
2833 }
2834 }
2835
Alan Viverette10979612016-01-06 15:27:35 -05002836 throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002837 + Integer.toHexString(id));
2838 }
2839
Alan Viverette45c4bbb2015-01-05 14:59:19 -08002840 /**
2841 * Obtains styled attributes from the theme, if available, or unstyled
2842 * resources if the theme is null.
2843 *
2844 * @hide
2845 */
2846 public static TypedArray obtainAttributes(
2847 Resources res, Theme theme, AttributeSet set, int[] attrs) {
2848 if (theme == null) {
2849 return res.obtainAttributes(set, attrs);
2850 }
2851 return theme.obtainStyledAttributes(set, attrs, 0, 0);
2852 }
2853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002854 private Resources() {
2855 mAssets = AssetManager.getSystem();
Alan Viverette02fc5fe2015-08-27 13:16:09 -04002856 mClassLoader = ClassLoader.getSystemClassLoader();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 // NOTE: Intentionally leaving this uninitialized (all values set
2858 // to zero), so that anyone who tries to do something that requires
2859 // metrics will get a very wrong value.
2860 mConfiguration.setToDefaults();
2861 mMetrics.setToDefaults();
2862 updateConfiguration(null, null);
2863 mAssets.ensureStringBlocks();
2864 }
2865}