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(); 1178e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski private final DisplayAdjustments mDisplayAdjustments; 118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules mPluralRule; 120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mConfiguration = new Configuration(); 122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static { 124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables = new LongSparseArray[2]; 125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0] = new LongSparseArray<>(); 126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1] = new LongSparseArray<>(); 127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Creates a new ResourcesImpl object with CompatibilityInfo. 131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assets Previously created AssetManager. 133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param metrics Current display metrics to consider when 134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values. 135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param config Desired device configuration to consider when 136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values (optional). 1378e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski * @param displayAdjustments this resource's Display override and compatibility info. 1388e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski * Must not be null. 139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1404ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, 1418e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) { 142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = assets; 143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.setToDefaults(); 1448e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments = displayAdjustments; 1458e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo()); 146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.ensureStringBlocks(); 147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1494ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public DisplayAdjustments getDisplayAdjustments() { 1504ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski return mDisplayAdjustments; 1514ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski } 1524ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski 153082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public AssetManager getAssets() { 154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets; 155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski DisplayMetrics getDisplayMetrics() { 158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels 159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "x" + mMetrics.heightPixels + " " + mMetrics.density); 160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mMetrics; 161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration getConfiguration() { 164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mConfiguration; 165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration[] getSizeConfigurations() { 168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getSizeConfigurations(); 169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CompatibilityInfo getCompatibilityInfo() { 1728e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski return mDisplayAdjustments.getCompatibilityInfo(); 173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules getPluralRule() { 176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPluralRule == null) { 178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mPluralRule; 181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs) 185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs); 187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValueForDensity(@AnyRes int id, int density, TypedValue outValue, 194082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean resolveRefs) throws NotFoundException { 195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs); 196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(String name, TypedValue outValue, boolean resolveRefs) 203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int id = getIdentifier(name, "string", null); 205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, outValue, resolveRefs); 207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("String resource name " + name); 210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int getIdentifier(String name, String defType, String defPackage) { 213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name == null) { 214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NullPointerException("name is null"); 215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Integer.parseInt(name); 218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Ignore 220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getResourceIdentifier(name, defType, defPackage); 222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceName(@AnyRes int resid) throws NotFoundException { 226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceName(resid); 227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourcePackageName(@AnyRes int resid) throws NotFoundException { 234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourcePackageName(resid); 235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceTypeName(@AnyRes int resid) throws NotFoundException { 242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceTypeName(resid); 243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceEntryName(@AnyRes int resid) throws NotFoundException { 250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceEntryName(resid); 251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { 258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski PluralRules rule = getPluralRule(); 259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence res = mAssets.getResourceBagText(id, 260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrForQuantityCode(rule.select(quantity))); 261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski res = mAssets.getResourceBagText(id, ID_OTHER); 265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id) 269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " quantity=" + quantity 270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " item=" + rule.select(quantity)); 271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static int attrForQuantityCode(String quantityCode) { 274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski switch (quantityCode) { 275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ZERO: return 0x01000005; 276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ONE: return 0x01000006; 277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_TWO: return 0x01000007; 278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_FEW: return 0x01000008; 279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_MANY: return 0x01000009; 280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski default: return ID_OTHER; 281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue) 286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, tempValue, true); 288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString()); 290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + tempValue.string.toString() + " from drawable " 292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "resource ID #0x" + Integer.toHexString(id), e); 293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException { 298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, value, true); 299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAsset(value.assetCookie, value.string.toString(), 301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.ACCESS_STREAMING); 302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 303f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate // Note: value.string might be null 304f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate NotFoundException rnf = new NotFoundException("File " 305f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + (value.string == null ? "(null)" : value.string.toString()) 306f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + " from drawable resource ID #0x" + Integer.toHexString(id)); 307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<Animator> getAnimatorCache() { 313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAnimatorCache; 314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { 317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mStateListAnimatorCache; 318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 320082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public void updateConfiguration(Configuration config, DisplayMetrics metrics, 321082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski CompatibilityInfo compat) { 322991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration"); 323991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski try { 324991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (mAccessLock) { 325991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (false) { 326991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": old config is " 3278e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mConfiguration + " old compat is " 3288e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mDisplayAdjustments.getCompatibilityInfo()); 329991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": new config is " 330991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski + config + " new compat is " + compat); 331991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 332991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (compat != null) { 3338e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.setCompatibilityInfo(compat); 334991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 335991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (metrics != null) { 336991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.setTo(metrics); 337991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 338991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // NOTE: We should re-arrange this code to create a Display 339991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the CompatibilityInfo that is used everywhere we deal 340991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the display in relation to this app, rather than 341991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // doing the conversion here. This impl should be okay because 342991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // we make sure to return a compatible display in the places 343991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // where there are public APIs to retrieve the display... but 344b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // it would be cleaner and more maintainable to just be 345991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // consistently dealing with a compatible display everywhere in 346991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // the framework. 3478e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.getCompatibilityInfo().applyToDisplayMetrics(mMetrics); 348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final @Config int configChanges = calcConfigChanges(config); 350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 351b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // If even after the update there are no Locales set, grab the default locales. 352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski LocaleList locales = mConfiguration.getLocales(); 353991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (locales.isEmpty()) { 354b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski locales = LocaleList.getDefault(); 355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.setLocales(locales); 356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 357b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 358b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) { 359b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (locales.size() > 1) { 360b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // The LocaleList has changed. We must query the AssetManager's available 361b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // Locales and figure out the best matching Locale in the new LocaleList. 362b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski String[] availableLocales = mAssets.getNonSystemLocales(); 363b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 364b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // No app defined locales, so grab the system locales. 365b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = mAssets.getLocales(); 366b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 367b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = null; 368b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 369b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 370b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 371b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (availableLocales != null) { 372b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski final Locale bestLocale = locales.getFirstMatchWithEnglishSupported( 373b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales); 374b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (bestLocale != null && bestLocale != locales.get(0)) { 375b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski mConfiguration.setLocales(new LocaleList(bestLocale, locales)); 376b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 377b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 378b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 379b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 380b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 381991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { 382991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.densityDpi = mConfiguration.densityDpi; 383991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.density = 384991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 385991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 386991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; 387991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 388991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int width, height; 389991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mMetrics.widthPixels >= mMetrics.heightPixels) { 390991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.widthPixels; 391991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.heightPixels; 392991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 393991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 394991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.heightPixels; 395991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 396991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.widthPixels; 397991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 398991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 399991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int keyboardHidden; 400991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO 401991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski && mConfiguration.hardKeyboardHidden 402991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski == Configuration.HARDKEYBOARDHIDDEN_YES) { 403991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; 404991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 405991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = mConfiguration.keyboardHidden; 406991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, 409b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()), 410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.orientation, 411991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.touchscreen, 412991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi, mConfiguration.keyboard, 413991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden, mConfiguration.navigation, width, height, 414991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.smallestScreenWidthDp, 415991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenWidthDp, mConfiguration.screenHeightDp, 416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenLayout, mConfiguration.uiMode, 417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Build.VERSION.RESOURCES_SDK_INT); 418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (DEBUG_CONFIG) { 420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": final config is " 4218e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mConfiguration + " final compat is " 4228e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mDisplayAdjustments.getCompatibilityInfo()); 423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mDrawableCache.onConfigurationChange(configChanges); 426991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mColorDrawableCache.onConfigurationChange(configChanges); 427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mComplexColorCache.onConfigurationChange(configChanges); 428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAnimatorCache.onConfigurationChange(configChanges); 429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mStateListAnimatorCache.onConfigurationChange(configChanges); 430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 431991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski flushLayoutCache(); 432fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (sSync) { 434991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mPluralRule != null) { 435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 437fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 438991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } finally { 439991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 440fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 441fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 442fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 443fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 444ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * Applies the new configuration, returning a bitmask of the changes 445ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * between the old and new configurations. 446ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * 447ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @param config the new configuration 448ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @return bitmask of config changes 449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 450ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette public @Config int calcConfigChanges(@Nullable Configuration config) { 451ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (config == null) { 452ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette // If there is no configuration, assume all flags have changed. 453ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return 0xFFFFFFFF; 454ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 455fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 456ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setTo(config); 457ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette int density = config.densityDpi; 458ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (density == Configuration.DENSITY_DPI_UNDEFINED) { 459ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette density = mMetrics.noncompatDensityDpi; 460ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 4628e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.getCompatibilityInfo().applyToConfiguration(density, mTmpConfig); 463ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette 464ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (mTmpConfig.getLocales().isEmpty()) { 465ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setLocales(LocaleList.getDefault()); 466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 467ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return mConfiguration.updateFrom(mTmpConfig); 468fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated) 472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively. 473fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 474fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * All released versions of android prior to "L" used the deprecated language 475fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tags, so we will need to support them for backwards compatibility. 476fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 477fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Note that this conversion needs to take place *after* the call to 478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code toLanguageTag} because that will convert all the deprecated codes to 479fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the new ones, even if they're set manually. 480fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 481fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static String adjustLanguageTag(String languageTag) { 482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int separator = languageTag.indexOf('-'); 483fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String language; 484fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String remainder; 485fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 486fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (separator == -1) { 487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag; 488fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = ""; 489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag.substring(0, separator); 491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = languageTag.substring(separator); 492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Locale.adjustLanguageCode(language) + remainder; 495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Call this to remove all cached loaded layout resources from the 499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resources object. Only intended for use with performance testing 500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tools. 501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void flushLayoutCache() { 503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockCookies, 0); 505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockFiles, null); 506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) { 509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[i]; 510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(cachedXmlBlocks, null); 515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, 520082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean useCache) throws NotFoundException { 521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d("PreloadDrawable", name); 528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean isColorDrawable; 533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final DrawableCache caches; 534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key; 535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = true; 538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mColorDrawableCache; 539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = value.data; 540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = false; 542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mDrawableCache; 543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = (((long) value.assetCookie) << 32) | value.data; 544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First, check whether we have a cached version of this drawable 547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // that was inflated against the specified theme. Skip the cache if 548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we're currently preloading or we're not using the cache. 549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (!mPreloading && useCache) { 550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme); 551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedDrawable != null) { 552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedDrawable; 553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Next, check preloaded drawables. Preloaded drawables may contain 557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // unresolved theme attributes. 558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs; 559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedColorDrawables.get(key); 561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); 563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable dr; 566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs != null) { 567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = cs.newDrawable(wrapper); 568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (isColorDrawable) { 569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = new ColorDrawable(value.data); 570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = loadDrawableForCookie(wrapper, value, id, null); 572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Determine if the drawable has unresolved theme attributes. If it 575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // does, we'll need to apply a theme and store it in a theme-specific 576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache. 577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean canApplyTheme = dr != null && dr.canApplyTheme(); 578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (canApplyTheme && theme != null) { 579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = dr.mutate(); 580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.applyTheme(theme); 581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.clearMutated(); 582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If we were able to obtain a drawable, store it in the appropriate 585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache: preload, not themed, null theme, or theme-specific. Don't 586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // pollute the cache with drawables loaded from a foreign density. 587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (dr != null && useCache) { 588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.setChangingConfigurations(value.changingConfigurations); 589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); 590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String name; 595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = getResourceName(id); 597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e2) { 598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = "(missing name)"; 599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // The target drawable might fail to load for any number of 602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // reasons, but we always want to include the resource name. 603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Since the client already expects this method to throw a 604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // NotFoundException, just throw one of those. 605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException nfe = new NotFoundException("Drawable " + name 606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " with resource ID #0x" + Integer.toHexString(id), e); 607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski nfe.setStackTrace(new StackTraceElement[0]); 608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw nfe; 609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches, 613082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme, boolean usesTheme, long key, Drawable dr) { 614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs = dr.getConstantState(); 615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs == null) { 616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int changingConfigs = cs.getChangingConfigurations(); 621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) { 623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedColorDrawables.put(key, cs); 624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig( 627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) { 628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) { 629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If this resource does not vary based on layout direction, 630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we can put it in all of the preload maps. 631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0].put(key, cs); 632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1].put(key, cs); 633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 634fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Otherwise, only in the layout dir we loaded it for. 635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs); 636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mAccessLock) { 641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches.put(key, theme, cs, usesTheme); 642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 646ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private boolean verifyPreloadConfig(@Config int changingConfigurations, 647ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) { 648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // We allow preloading of resources even if they vary by font scale (which 649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // doesn't impact resource selection) or density (which we handle specially by 650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // simply turning off all preloading), as well as any other configs specified 651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // by the caller. 652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE | 653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) { 654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // This should never happen in production, so we should log a 661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // warning even if we're not debugging. 662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloaded " + name + " resource #0x" 663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ") that varies with configuration!!"); 665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return false; 666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloading " + name + " resource #0x" 675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ")"); 677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return true; 679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads a drawable from XML or resources stream. 683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id, 685082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" 688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value); 689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id) 699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file); 706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable dr; 709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser rp = loadXmlResourceParser( 714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "drawable"); 715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromXml(wrapper, rp, theme); 716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rp.close(); 717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final InputStream is = mAssets.openNonAsset( 719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski value.assetCookie, file, AssetManager.ACCESS_STREAMING); 720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromResourceStream(wrapper, value, is, file, null); 721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski is.close(); 722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); 727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Given the value and id, we can get the XML filename as in value.data, based on that, we 737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * first try to load CSL from the cache. If not found, try to get from the constant state. 738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Last, parse the XML and generate the CSL. 739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme, 741082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski TypedValue value, int id) { 742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache; 744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = cache.getInstance(key, wrapper, theme); 745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = factory.newInstance(wrapper, theme); 754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor == null) { 756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorForCookie(wrapper, value, id, theme); 757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 7600b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette complexColor.setBaseChangingConfigurations(value.changingConfigurations); 7610b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 7630b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette if (verifyPreloadConfig(complexColor.getChangingConfigurations(), 7640b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 0, value.resourceId, "color")) { 765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, complexColor.getConstantState()); 766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cache.put(key, theme, complexColor.getConstantState()); 769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id, 776082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 781fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("loadComplexColor", name); 782fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor; 796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorFromName(wrapper, theme, value, id); 799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from complex color resource ID #0x" 802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, 817082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) 818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("PreloadColorStateList", name); 824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 833fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id); 836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null && complexColor instanceof ColorStateList) { 837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) complexColor; 838fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't find ColorStateList from drawable resource ID #0x" 842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) { 847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList csl; 848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) factory.newInstance(); 852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski csl = ColorStateList.valueOf(value.data); 855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId, 858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "color")) { 859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, csl.getConstantState()); 860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return csl; 864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Load a ComplexColor based on the XML file content. The result can be a GradientColor or 868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * ColorStateList. Note that pure color will be wrapped into a ColorStateList. 869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * We deferred the parser creation to this function b/c we need to differentiate b/t gradient 871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * and selector tag. 872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content. 874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id, 877082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new UnsupportedOperationException( 880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't convert to ComplexColor: type=0x" + value.type); 881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id) 891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file); 898fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = null; 901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser parser = loadXmlResourceParser( 906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "ComplexColor"); 907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AttributeSet attrs = Xml.asAttributeSet(parser); 909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int type; 910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski while ((type = parser.next()) != XmlPullParser.START_TAG 911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && type != XmlPullParser.END_DOCUMENT) { 912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Seek parser to start tag. 913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (type != XmlPullParser.START_TAG) { 915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new XmlPullParserException("No start tag found"); 916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = parser.getName(); 919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name.equals("gradient")) { 920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme); 921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (name.equals("selector")) { 922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme); 923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser.close(); 925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from ComplexColor resource ID #0x" 929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads an XML parser for the specified file. 946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param file the path for the XML file to parse 948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param id the resource identifier for the file 949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assetCookie the asset cookie for the file 950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param type the type of resource (used for logging) 951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a parser for the specified XML file 952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @throws NotFoundException if the file could not be loaded 953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 955082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie, 956082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull String type) 957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies; 962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; 963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First see if this block is in our cache. 965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int num = cachedXmlBlockFiles.length; 966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < num; i++) { 967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null 968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && cachedXmlBlockFiles[i].equals(file)) { 969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedXmlBlocks[i].newParser(); 970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Not in the cache, create a new block and put it at 974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // the next slot in the cache. 975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); 976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (block != null) { 977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int pos = (mLastCachedXmlBlockIndex + 1) % num; 978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mLastCachedXmlBlockIndex = pos; 979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[pos]; 980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockCookies[pos] = assetCookie; 984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockFiles[pos] = file; 985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlocks[pos] = block; 986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return block.newParser(); 987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException("File " + file 991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); 992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" 998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Start preloading of resource data using this Resources object. Only 1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * for use by the zygote process for loading common system resources. 1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@hide} 1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public final void startPreloading() { 1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (sPreloaded) { 1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalStateException("Resources already preloaded"); 1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloaded = true; 1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = true; 1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE; 1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski updateConfiguration(null, null, null); 1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Called by zygote when it is done preloading resources, to change back 1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * to normal Resources operation. 1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void finishPreloading() { 1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = false; 1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski flushLayoutCache(); 1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() { 1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return sPreloadedDrawables[0]; 1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ThemeImpl newThemeImpl() { 1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return new ThemeImpl(); 1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1037082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski /** 1038082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey. 1039082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski */ 1040082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl newThemeImpl(Resources.ThemeKey key) { 1041082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl impl = new ThemeImpl(); 1042082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.mKey.setTo(key); 1043082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.rebase(); 1044082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski return impl; 1045082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski } 1046082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski 1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public class ThemeImpl { 1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unique key for the series of styles applied to this theme. 1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Resources.ThemeKey mKey = new Resources.ThemeKey(); 1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @SuppressWarnings("hiding") 1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final AssetManager mAssets; 1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final long mTheme; 1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resource identifier for the theme. 1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mThemeResId = 0; 1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ ThemeImpl() { 1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = ResourcesImpl.this.mAssets; 1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mTheme = mAssets.createTheme(); 1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Override 1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski protected void finalize() throws Throwable { 1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski super.finalize(); 1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.releaseTheme(mTheme); 1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ Resources.ThemeKey getKey() { 1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mKey; 1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ long getNativeTheme() { 1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mTheme; 1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ int getAppliedStyleResId() { 1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mThemeResId; 1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void applyStyle(int resId, boolean force) { 1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = resId; 1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.append(resId, force); 1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void setTo(ThemeImpl other) { 1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (other.mKey) { 1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.copyTheme(mTheme, other.mTheme); 1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = other.mThemeResId; 1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.setTo(other.getKey()); 1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper, 1107082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski AttributeSet set, 1108082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleableRes int[] attrs, 1109082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @AttrRes int defStyleAttr, 1110082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleRes int defStyleRes) { 1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // XXX note that for now we only work with compiled XML files. 1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // To support generic XML files we will need to manually parse 1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // out the attributes from the XML file (applying type information 1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // contained in the resources and such). 1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock.Parser parser = (XmlBlock.Parser) set; 1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, 1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser != null ? parser.mParseState : 0, 1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrs, array.mData, array.mIndices); 1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = parser; 1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray resolveAttributes(@NonNull Resources.Theme wrapper, 1132082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] values, 1133082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] attrs) { 1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (values == null || len != values.length) { 1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalArgumentException( 1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Base attribute values must the same length as attrs"); 1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); 1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = null; 1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); 1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int[] getAllAttributes() { 1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getStyleAttributes(getAppliedStyleResId()); 1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1159ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int getChangingConfigurations() { 1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int nativeChangingConfig = 1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.getThemeChangingConfigurations(mTheme); 1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); 1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void dump(int priority, String tag, String prefix) { 1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.dumpTheme(mTheme, priority, tag, prefix); 1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String[] getTheme() { 1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int N = mKey.mCount; 1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] themes = new String[N * 2]; 1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { 1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[j]; 1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean forced = mKey.mForce[j]; 1180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = getResourceName(resId); 1182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 1183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = Integer.toHexString(i); 1184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i + 1] = forced ? "forced" : "not forced"; 1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return themes; 1188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Rebases the theme against the parent Resource object's current 1193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * configuration by re-applying the styles passed to 1194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@link #applyStyle(int, boolean)}. 1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void rebase() { 1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.clearTheme(mTheme); 1199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Reapply the same styles in the same order. 1201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < mKey.mCount; i++) { 1202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[i]; 1203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean force = mKey.mForce[i]; 1204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski} 1210