ResourcesImpl.java revision 4ece3d6bb18a609afcd0e82f0340b7d36ba24eea
1fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/* 2fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Copyright (C) 2016 The Android Open Source Project 3fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 4fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * use this file except in compliance with the License. You may obtain a copy of 6fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License at 7fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 8fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 10fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * License for the specific language governing permissions and limitations under 14fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License. 15fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 16fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipackage android.content.res; 17fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 18ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport org.xmlpull.v1.XmlPullParser; 19ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport org.xmlpull.v1.XmlPullParserException; 20ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette 21fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.Animator; 22fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.StateListAnimator; 23fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AnyRes; 24fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AttrRes; 25fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.NonNull; 26fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.Nullable; 27fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.PluralsRes; 28fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.RawRes; 29fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleRes; 30fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleableRes; 31fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.pm.ActivityInfo; 32ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.content.pm.ActivityInfo.Config; 33fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException; 34fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable; 35fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable; 36fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules; 37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build; 3823cbe85610f780134cc77dd4a54732a22ed6e86eYohei Yukawaimport android.os.LocaleList; 39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace; 40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet; 41fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics; 42fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log; 43fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray; 44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog; 45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue; 46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml; 474ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.Display; 484ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.DisplayAdjustments; 49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream; 51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays; 52fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale; 53fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 54fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/** 55082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches 56082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it. 57082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 58082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change 59082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying 60082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created. 61082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide 63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl { 65fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static final String TAG = "Resources"; 66fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 67fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_LOAD = false; 68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_CONFIG = false; 69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean TRACE_FOR_PRELOAD = false; 70fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean TRACE_FOR_MISS_PRELOAD = false; 71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 72ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigJavaToNative( 73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_LAYOUT_DIRECTION); 74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int ID_OTHER = 0x01000004; 76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final Object sSync = new Object(); 78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static boolean sPreloaded; 80fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private boolean mPreloading; 81fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 82fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Information about preloaded resources. Note that they are not 83fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // protected by a lock, because while preloading in zygote we are all 84fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // single-threaded, and after that these are immutable. 85fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables; 86fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables 87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski = new LongSparseArray<>(); 88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>> 89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors = new LongSparseArray<>(); 90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Lock object used to protect access to caches and configuration. */ 92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Object mAccessLock = new Object(); 93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // These are protected by mAccessLock. 95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mTmpConfig = new Configuration(); 96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mDrawableCache = new DrawableCache(); 97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mColorDrawableCache = new DrawableCache(); 98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache = 99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = 101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = 103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Size of the cyclical cache used to map XML files to blocks. */ 106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int XML_BLOCK_CACHE_SIZE = 4; 107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Cyclical cache used for recently-accessed XML files. 109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mLastCachedXmlBlockIndex = -1; 110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE]; 111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE]; 112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE]; 113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AssetManager mAssets; 1164ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski private final DisplayMetrics mMetrics = new DisplayMetrics(); 1174ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); 118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules mPluralRule; 120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mConfiguration = new Configuration(); 122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; 123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static { 125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables = new LongSparseArray[2]; 126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0] = new LongSparseArray<>(); 127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1] = new LongSparseArray<>(); 128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Creates a new ResourcesImpl object with CompatibilityInfo. 132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assets Previously created AssetManager. 134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param metrics Current display metrics to consider when 135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values. 136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param config Desired device configuration to consider when 137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values (optional). 138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param compatInfo this resource's compatibility info. Must not be null. 139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1404ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, 1414ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski @Nullable Configuration config, @NonNull CompatibilityInfo compatInfo) { 1424ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski this(assets, metrics, config, compatInfo, null); 1434ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski } 1444ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski 1454ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski /** 1464ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * Creates a new ResourcesImpl object with CompatibilityInfo and assigns a static overrideConfig 1474ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * that is reported with getDisplayAdjustments(). This is used for updating the Display 1484ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * when a new ResourcesImpl is created due to multi-window configuration changes. 1494ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * 1504ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * @param assets Previously created AssetManager. 1514ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * @param metrics Current display metrics to consider when selecting/computing resource values. 1524ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * @param fullConfig Desired device configuration to consider when selecting/computing 1534ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * resource values. 1544ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * @param compatInfo this resource's compatibility info. Must not be null. 1554ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * @param overrideConfig the overrides specific to this ResourcesImpl object. They must already 1564ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * be applied to the fullConfig and are mainly maintained in order to return a valid 1574ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski * DisplayAdjustments object during configuration changes. 1584ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski */ 1594ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, 1604ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski @Nullable Configuration fullConfig, @NonNull CompatibilityInfo compatInfo, 1614ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski @Nullable Configuration overrideConfig) { 162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = assets; 163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.setToDefaults(); 1644ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski mDisplayAdjustments.setCompatibilityInfo(compatInfo); 1654ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski if (overrideConfig != null) { 1664ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski mDisplayAdjustments.setConfiguration(overrideConfig); 1674ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski } 1684ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski updateConfiguration(fullConfig, metrics, compatInfo); 169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.ensureStringBlocks(); 170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1724ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public DisplayAdjustments getDisplayAdjustments() { 1734ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski return mDisplayAdjustments; 1744ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski } 1754ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski 176082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public AssetManager getAssets() { 177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets; 178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski DisplayMetrics getDisplayMetrics() { 181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels 182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "x" + mMetrics.heightPixels + " " + mMetrics.density); 183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mMetrics; 184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration getConfiguration() { 187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mConfiguration; 188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration[] getSizeConfigurations() { 191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getSizeConfigurations(); 192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CompatibilityInfo getCompatibilityInfo() { 195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mCompatibilityInfo; 196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules getPluralRule() { 199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPluralRule == null) { 201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mPluralRule; 204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs) 208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs); 210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValueForDensity(@AnyRes int id, int density, TypedValue outValue, 217082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean resolveRefs) throws NotFoundException { 218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs); 219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(String name, TypedValue outValue, boolean resolveRefs) 226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int id = getIdentifier(name, "string", null); 228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, outValue, resolveRefs); 230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("String resource name " + name); 233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int getIdentifier(String name, String defType, String defPackage) { 236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name == null) { 237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NullPointerException("name is null"); 238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Integer.parseInt(name); 241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Ignore 243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getResourceIdentifier(name, defType, defPackage); 245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceName(@AnyRes int resid) throws NotFoundException { 249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceName(resid); 250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourcePackageName(@AnyRes int resid) throws NotFoundException { 257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourcePackageName(resid); 258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceTypeName(@AnyRes int resid) throws NotFoundException { 265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceTypeName(resid); 266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceEntryName(@AnyRes int resid) throws NotFoundException { 273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceEntryName(resid); 274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { 281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski PluralRules rule = getPluralRule(); 282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence res = mAssets.getResourceBagText(id, 283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrForQuantityCode(rule.select(quantity))); 284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski res = mAssets.getResourceBagText(id, ID_OTHER); 288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id) 292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " quantity=" + quantity 293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " item=" + rule.select(quantity)); 294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static int attrForQuantityCode(String quantityCode) { 297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski switch (quantityCode) { 298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ZERO: return 0x01000005; 299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ONE: return 0x01000006; 300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_TWO: return 0x01000007; 301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_FEW: return 0x01000008; 302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_MANY: return 0x01000009; 303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski default: return ID_OTHER; 304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue) 309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, tempValue, true); 311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString()); 313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + tempValue.string.toString() + " from drawable " 315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "resource ID #0x" + Integer.toHexString(id), e); 316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException { 321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, value, true); 322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAsset(value.assetCookie, value.string.toString(), 324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.ACCESS_STREAMING); 325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 326f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate // Note: value.string might be null 327f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate NotFoundException rnf = new NotFoundException("File " 328f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + (value.string == null ? "(null)" : value.string.toString()) 329f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + " from drawable resource ID #0x" + Integer.toHexString(id)); 330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<Animator> getAnimatorCache() { 336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAnimatorCache; 337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { 340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mStateListAnimatorCache; 341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 343082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public void updateConfiguration(Configuration config, DisplayMetrics metrics, 344082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski CompatibilityInfo compat) { 345991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration"); 346991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski try { 347991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (mAccessLock) { 348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (false) { 349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": old config is " 350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski + mConfiguration + " old compat is " + mCompatibilityInfo); 351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": new config is " 352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski + config + " new compat is " + compat); 353991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 354991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (compat != null) { 355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mCompatibilityInfo = compat; 356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (metrics != null) { 358991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.setTo(metrics); 359991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // NOTE: We should re-arrange this code to create a Display 361991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the CompatibilityInfo that is used everywhere we deal 362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the display in relation to this app, rather than 363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // doing the conversion here. This impl should be okay because 364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // we make sure to return a compatible display in the places 365991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // where there are public APIs to retrieve the display... but 366b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // it would be cleaner and more maintainable to just be 367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // consistently dealing with a compatible display everywhere in 368991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // the framework. 369991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mCompatibilityInfo.applyToDisplayMetrics(mMetrics); 370991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 371991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final @Config int configChanges = calcConfigChanges(config); 372991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 373b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // If even after the update there are no Locales set, grab the default locales. 374991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski LocaleList locales = mConfiguration.getLocales(); 375991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (locales.isEmpty()) { 376b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski locales = LocaleList.getDefault(); 377991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.setLocales(locales); 378991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 379b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 380b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) { 381b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (locales.size() > 1) { 382b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // The LocaleList has changed. We must query the AssetManager's available 383b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // Locales and figure out the best matching Locale in the new LocaleList. 384b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski String[] availableLocales = mAssets.getNonSystemLocales(); 385b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 386b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // No app defined locales, so grab the system locales. 387b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = mAssets.getLocales(); 388b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 389b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = null; 390b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 391b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 392b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 393b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (availableLocales != null) { 394b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski final Locale bestLocale = locales.getFirstMatchWithEnglishSupported( 395b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales); 396b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (bestLocale != null && bestLocale != locales.get(0)) { 397b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski mConfiguration.setLocales(new LocaleList(bestLocale, locales)); 398b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 399b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 400b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 401b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 402b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 403991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { 404991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.densityDpi = mConfiguration.densityDpi; 405991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.density = 406991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; 409991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int width, height; 411991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mMetrics.widthPixels >= mMetrics.heightPixels) { 412991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.widthPixels; 413991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.heightPixels; 414991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 415991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.heightPixels; 417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.widthPixels; 419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 421991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int keyboardHidden; 422991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO 423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski && mConfiguration.hardKeyboardHidden 424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski == Configuration.HARDKEYBOARDHIDDEN_YES) { 425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; 426991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = mConfiguration.keyboardHidden; 428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, 431b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()), 432991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.orientation, 433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.touchscreen, 434991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi, mConfiguration.keyboard, 435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden, mConfiguration.navigation, width, height, 436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.smallestScreenWidthDp, 437991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenWidthDp, mConfiguration.screenHeightDp, 438991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenLayout, mConfiguration.uiMode, 439991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Build.VERSION.RESOURCES_SDK_INT); 440991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 441991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (DEBUG_CONFIG) { 442991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": final config is " 443991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski + mConfiguration + " final compat is " + mCompatibilityInfo); 444991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 445991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 446991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mDrawableCache.onConfigurationChange(configChanges); 447991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mColorDrawableCache.onConfigurationChange(configChanges); 448991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mComplexColorCache.onConfigurationChange(configChanges); 449991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAnimatorCache.onConfigurationChange(configChanges); 450991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mStateListAnimatorCache.onConfigurationChange(configChanges); 451991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 452991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski flushLayoutCache(); 453fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 454991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (sSync) { 455991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mPluralRule != null) { 456991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 457991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 459991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } finally { 460991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 462fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 463fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 464fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 465ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * Applies the new configuration, returning a bitmask of the changes 466ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * between the old and new configurations. 467ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * 468ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @param config the new configuration 469ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @return bitmask of config changes 470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 471ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette public @Config int calcConfigChanges(@Nullable Configuration config) { 472ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (config == null) { 473ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette // If there is no configuration, assume all flags have changed. 474ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return 0xFFFFFFFF; 475ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 476fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 477ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setTo(config); 478ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette int density = config.densityDpi; 479ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (density == Configuration.DENSITY_DPI_UNDEFINED) { 480ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette density = mMetrics.noncompatDensityDpi; 481ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 483ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mCompatibilityInfo.applyToConfiguration(density, mTmpConfig); 484ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette 485ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (mTmpConfig.getLocales().isEmpty()) { 486ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setLocales(LocaleList.getDefault()); 487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 488ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return mConfiguration.updateFrom(mTmpConfig); 489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated) 493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively. 494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * All released versions of android prior to "L" used the deprecated language 496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tags, so we will need to support them for backwards compatibility. 497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Note that this conversion needs to take place *after* the call to 499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code toLanguageTag} because that will convert all the deprecated codes to 500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the new ones, even if they're set manually. 501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static String adjustLanguageTag(String languageTag) { 503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int separator = languageTag.indexOf('-'); 504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String language; 505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String remainder; 506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (separator == -1) { 508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag; 509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = ""; 510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag.substring(0, separator); 512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = languageTag.substring(separator); 513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Locale.adjustLanguageCode(language) + remainder; 516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Call this to remove all cached loaded layout resources from the 520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resources object. Only intended for use with performance testing 521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tools. 522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void flushLayoutCache() { 524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockCookies, 0); 526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockFiles, null); 527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) { 530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[i]; 531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(cachedXmlBlocks, null); 536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, 541082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean useCache) throws NotFoundException { 542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d("PreloadDrawable", name); 549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean isColorDrawable; 554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final DrawableCache caches; 555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key; 556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = true; 559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mColorDrawableCache; 560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = value.data; 561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = false; 563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mDrawableCache; 564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = (((long) value.assetCookie) << 32) | value.data; 565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First, check whether we have a cached version of this drawable 568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // that was inflated against the specified theme. Skip the cache if 569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we're currently preloading or we're not using the cache. 570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (!mPreloading && useCache) { 571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme); 572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedDrawable != null) { 573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedDrawable; 574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Next, check preloaded drawables. Preloaded drawables may contain 578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // unresolved theme attributes. 579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs; 580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedColorDrawables.get(key); 582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); 584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable dr; 587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs != null) { 588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = cs.newDrawable(wrapper); 589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (isColorDrawable) { 590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = new ColorDrawable(value.data); 591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = loadDrawableForCookie(wrapper, value, id, null); 593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Determine if the drawable has unresolved theme attributes. If it 596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // does, we'll need to apply a theme and store it in a theme-specific 597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache. 598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean canApplyTheme = dr != null && dr.canApplyTheme(); 599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (canApplyTheme && theme != null) { 600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = dr.mutate(); 601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.applyTheme(theme); 602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.clearMutated(); 603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If we were able to obtain a drawable, store it in the appropriate 606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache: preload, not themed, null theme, or theme-specific. Don't 607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // pollute the cache with drawables loaded from a foreign density. 608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (dr != null && useCache) { 609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.setChangingConfigurations(value.changingConfigurations); 610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); 611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String name; 616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = getResourceName(id); 618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e2) { 619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = "(missing name)"; 620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // The target drawable might fail to load for any number of 623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // reasons, but we always want to include the resource name. 624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Since the client already expects this method to throw a 625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // NotFoundException, just throw one of those. 626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException nfe = new NotFoundException("Drawable " + name 627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " with resource ID #0x" + Integer.toHexString(id), e); 628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski nfe.setStackTrace(new StackTraceElement[0]); 629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw nfe; 630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches, 634082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme, boolean usesTheme, long key, Drawable dr) { 635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs = dr.getConstantState(); 636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs == null) { 637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int changingConfigs = cs.getChangingConfigurations(); 642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) { 644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedColorDrawables.put(key, cs); 645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig( 648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) { 649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) { 650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If this resource does not vary based on layout direction, 651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we can put it in all of the preload maps. 652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0].put(key, cs); 653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1].put(key, cs); 654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Otherwise, only in the layout dir we loaded it for. 656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs); 657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mAccessLock) { 662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches.put(key, theme, cs, usesTheme); 663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 667ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private boolean verifyPreloadConfig(@Config int changingConfigurations, 668ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) { 669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // We allow preloading of resources even if they vary by font scale (which 670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // doesn't impact resource selection) or density (which we handle specially by 671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // simply turning off all preloading), as well as any other configs specified 672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // by the caller. 673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE | 674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) { 675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // This should never happen in production, so we should log a 682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // warning even if we're not debugging. 683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloaded " + name + " resource #0x" 684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ") that varies with configuration!!"); 686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return false; 687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloading " + name + " resource #0x" 696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ")"); 698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return true; 700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads a drawable from XML or resources stream. 704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id, 706082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" 709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value); 710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id) 720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file); 727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable dr; 730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser rp = loadXmlResourceParser( 735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "drawable"); 736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromXml(wrapper, rp, theme); 737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rp.close(); 738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final InputStream is = mAssets.openNonAsset( 740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski value.assetCookie, file, AssetManager.ACCESS_STREAMING); 741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromResourceStream(wrapper, value, is, file, null); 742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski is.close(); 743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); 748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Given the value and id, we can get the XML filename as in value.data, based on that, we 758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * first try to load CSL from the cache. If not found, try to get from the constant state. 759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Last, parse the XML and generate the CSL. 760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme, 762082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski TypedValue value, int id) { 763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache; 765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = cache.getInstance(key, wrapper, theme); 766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = factory.newInstance(wrapper, theme); 775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor == null) { 777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorForCookie(wrapper, value, id, theme); 778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 7810b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette complexColor.setBaseChangingConfigurations(value.changingConfigurations); 7820b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 7840b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette if (verifyPreloadConfig(complexColor.getChangingConfigurations(), 7850b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 0, value.resourceId, "color")) { 786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, complexColor.getConstantState()); 787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cache.put(key, theme, complexColor.getConstantState()); 790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id, 797082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("loadComplexColor", name); 803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor; 817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorFromName(wrapper, theme, value, id); 820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from complex color resource ID #0x" 823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 833fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, 838082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) 839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("PreloadColorStateList", name); 845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id); 857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null && complexColor instanceof ColorStateList) { 858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) complexColor; 859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't find ColorStateList from drawable resource ID #0x" 863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) { 868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList csl; 869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) factory.newInstance(); 873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski csl = ColorStateList.valueOf(value.data); 876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 877fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId, 879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "color")) { 880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, csl.getConstantState()); 881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return csl; 885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Load a ComplexColor based on the XML file content. The result can be a GradientColor or 889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * ColorStateList. Note that pure color will be wrapped into a ColorStateList. 890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * We deferred the parser creation to this function b/c we need to differentiate b/t gradient 892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * and selector tag. 893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content. 895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id, 898082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new UnsupportedOperationException( 901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't convert to ComplexColor: type=0x" + value.type); 902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id) 912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file); 919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = null; 922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser parser = loadXmlResourceParser( 927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "ComplexColor"); 928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AttributeSet attrs = Xml.asAttributeSet(parser); 930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int type; 931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski while ((type = parser.next()) != XmlPullParser.START_TAG 932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && type != XmlPullParser.END_DOCUMENT) { 933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Seek parser to start tag. 934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (type != XmlPullParser.START_TAG) { 936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new XmlPullParserException("No start tag found"); 937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = parser.getName(); 940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name.equals("gradient")) { 941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme); 942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (name.equals("selector")) { 943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme); 944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser.close(); 946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from ComplexColor resource ID #0x" 950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads an XML parser for the specified file. 967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param file the path for the XML file to parse 969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param id the resource identifier for the file 970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assetCookie the asset cookie for the file 971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param type the type of resource (used for logging) 972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a parser for the specified XML file 973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @throws NotFoundException if the file could not be loaded 974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 976082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie, 977082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull String type) 978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies; 983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; 984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First see if this block is in our cache. 986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int num = cachedXmlBlockFiles.length; 987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < num; i++) { 988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null 989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && cachedXmlBlockFiles[i].equals(file)) { 990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedXmlBlocks[i].newParser(); 991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Not in the cache, create a new block and put it at 995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // the next slot in the cache. 996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); 997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (block != null) { 998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int pos = (mLastCachedXmlBlockIndex + 1) % num; 999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mLastCachedXmlBlockIndex = pos; 1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[pos]; 1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockCookies[pos] = assetCookie; 1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockFiles[pos] = file; 1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlocks[pos] = block; 1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return block.newParser(); 1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException("File " + file 1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); 1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" 1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Start preloading of resource data using this Resources object. Only 1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * for use by the zygote process for loading common system resources. 1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@hide} 1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public final void startPreloading() { 1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (sPreloaded) { 1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalStateException("Resources already preloaded"); 1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloaded = true; 1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = true; 1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE; 1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski updateConfiguration(null, null, null); 1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Called by zygote when it is done preloading resources, to change back 1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * to normal Resources operation. 1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void finishPreloading() { 1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = false; 1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski flushLayoutCache(); 1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() { 1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return sPreloadedDrawables[0]; 1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ThemeImpl newThemeImpl() { 1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return new ThemeImpl(); 1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1058082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski /** 1059082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey. 1060082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski */ 1061082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl newThemeImpl(Resources.ThemeKey key) { 1062082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl impl = new ThemeImpl(); 1063082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.mKey.setTo(key); 1064082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.rebase(); 1065082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski return impl; 1066082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski } 1067082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski 1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public class ThemeImpl { 1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unique key for the series of styles applied to this theme. 1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Resources.ThemeKey mKey = new Resources.ThemeKey(); 1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @SuppressWarnings("hiding") 1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final AssetManager mAssets; 1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final long mTheme; 1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resource identifier for the theme. 1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mThemeResId = 0; 1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ ThemeImpl() { 1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = ResourcesImpl.this.mAssets; 1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mTheme = mAssets.createTheme(); 1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Override 1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski protected void finalize() throws Throwable { 1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski super.finalize(); 1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.releaseTheme(mTheme); 1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ Resources.ThemeKey getKey() { 1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mKey; 1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ long getNativeTheme() { 1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mTheme; 1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ int getAppliedStyleResId() { 1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mThemeResId; 1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void applyStyle(int resId, boolean force) { 1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = resId; 1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.append(resId, force); 1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void setTo(ThemeImpl other) { 1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (other.mKey) { 1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.copyTheme(mTheme, other.mTheme); 1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = other.mThemeResId; 1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.setTo(other.getKey()); 1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper, 1128082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski AttributeSet set, 1129082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleableRes int[] attrs, 1130082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @AttrRes int defStyleAttr, 1131082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleRes int defStyleRes) { 1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // XXX note that for now we only work with compiled XML files. 1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // To support generic XML files we will need to manually parse 1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // out the attributes from the XML file (applying type information 1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // contained in the resources and such). 1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock.Parser parser = (XmlBlock.Parser) set; 1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, 1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser != null ? parser.mParseState : 0, 1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrs, array.mData, array.mIndices); 1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = parser; 1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray resolveAttributes(@NonNull Resources.Theme wrapper, 1153082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] values, 1154082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] attrs) { 1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (values == null || len != values.length) { 1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalArgumentException( 1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Base attribute values must the same length as attrs"); 1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); 1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = null; 1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); 1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int[] getAllAttributes() { 1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getStyleAttributes(getAppliedStyleResId()); 1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1180ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int getChangingConfigurations() { 1181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int nativeChangingConfig = 1183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.getThemeChangingConfigurations(mTheme); 1184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); 1185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void dump(int priority, String tag, String prefix) { 1189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.dumpTheme(mTheme, priority, tag, prefix); 1191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String[] getTheme() { 1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int N = mKey.mCount; 1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] themes = new String[N * 2]; 1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { 1199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[j]; 1200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean forced = mKey.mForce[j]; 1201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = getResourceName(resId); 1203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 1204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = Integer.toHexString(i); 1205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i + 1] = forced ? "forced" : "not forced"; 1207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return themes; 1209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Rebases the theme against the parent Resource object's current 1214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * configuration by re-applying the styles passed to 1215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@link #applyStyle(int, boolean)}. 1216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void rebase() { 1218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.clearTheme(mTheme); 1220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Reapply the same styles in the same order. 1222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < mKey.mCount; i++) { 1223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[i]; 1224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean force = mKey.mForce[i]; 1225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski} 1231