ResourcesImpl.java revision 0b9295d06750dc6da032a2b2092e2c500c65393f
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; 38fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace; 39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet; 40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics; 41fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LocaleList; 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; 47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream; 49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays; 50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale; 51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 52fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/** 53082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches 54082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it. 55082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 56082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change 57082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying 58082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created. 59082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide 61fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl { 63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static final String TAG = "Resources"; 64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 65fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_LOAD = false; 66fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_CONFIG = false; 67fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean TRACE_FOR_PRELOAD = false; 68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean TRACE_FOR_MISS_PRELOAD = false; 69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 70ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigJavaToNative( 71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_LAYOUT_DIRECTION); 72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int ID_OTHER = 0x01000004; 74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final Object sSync = new Object(); 76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static boolean sPreloaded; 78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private boolean mPreloading; 79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 80fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Information about preloaded resources. Note that they are not 81fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // protected by a lock, because while preloading in zygote we are all 82fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // single-threaded, and after that these are immutable. 83fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables; 84fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables 85fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski = new LongSparseArray<>(); 86fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>> 87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors = new LongSparseArray<>(); 88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Lock object used to protect access to caches and configuration. */ 90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Object mAccessLock = new Object(); 91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // These are protected by mAccessLock. 93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mTmpConfig = new Configuration(); 94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mDrawableCache = new DrawableCache(); 95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mColorDrawableCache = new DrawableCache(); 96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache = 97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = 99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = 101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Size of the cyclical cache used to map XML files to blocks. */ 104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int XML_BLOCK_CACHE_SIZE = 4; 105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Cyclical cache used for recently-accessed XML files. 107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mLastCachedXmlBlockIndex = -1; 108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE]; 109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE]; 110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE]; 111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AssetManager mAssets; 114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final DisplayMetrics mMetrics = new DisplayMetrics(); 115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules mPluralRule; 117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mConfiguration = new Configuration(); 119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; 120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static { 122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables = new LongSparseArray[2]; 123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0] = new LongSparseArray<>(); 124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1] = new LongSparseArray<>(); 125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Creates a new ResourcesImpl object with CompatibilityInfo. 129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assets Previously created AssetManager. 131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param metrics Current display metrics to consider when 132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values. 133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param config Desired device configuration to consider when 134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values (optional). 135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param compatInfo this resource's compatibility info. Must not be null. 136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config, 138082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski CompatibilityInfo compatInfo) { 139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = assets; 140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.setToDefaults(); 141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski updateConfiguration(config, metrics, compatInfo); 142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.ensureStringBlocks(); 143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 145082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public AssetManager getAssets() { 146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets; 147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski DisplayMetrics getDisplayMetrics() { 150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels 151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "x" + mMetrics.heightPixels + " " + mMetrics.density); 152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mMetrics; 153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration getConfiguration() { 156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mConfiguration; 157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration[] getSizeConfigurations() { 160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getSizeConfigurations(); 161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CompatibilityInfo getCompatibilityInfo() { 164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mCompatibilityInfo; 165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules getPluralRule() { 168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPluralRule == null) { 170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mPluralRule; 173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs) 177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs); 179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValueForDensity(@AnyRes int id, int density, TypedValue outValue, 186082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean resolveRefs) throws NotFoundException { 187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs); 188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(String name, TypedValue outValue, boolean resolveRefs) 195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int id = getIdentifier(name, "string", null); 197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, outValue, resolveRefs); 199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("String resource name " + name); 202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int getIdentifier(String name, String defType, String defPackage) { 205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name == null) { 206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NullPointerException("name is null"); 207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Integer.parseInt(name); 210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Ignore 212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getResourceIdentifier(name, defType, defPackage); 214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceName(@AnyRes int resid) throws NotFoundException { 218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceName(resid); 219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourcePackageName(@AnyRes int resid) throws NotFoundException { 226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourcePackageName(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 getResourceTypeName(@AnyRes int resid) throws NotFoundException { 234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceTypeName(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 getResourceEntryName(@AnyRes int resid) throws NotFoundException { 242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceEntryName(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 CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { 250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski PluralRules rule = getPluralRule(); 251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence res = mAssets.getResourceBagText(id, 252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrForQuantityCode(rule.select(quantity))); 253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski res = mAssets.getResourceBagText(id, ID_OTHER); 257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id) 261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " quantity=" + quantity 262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " item=" + rule.select(quantity)); 263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static int attrForQuantityCode(String quantityCode) { 266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski switch (quantityCode) { 267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ZERO: return 0x01000005; 268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ONE: return 0x01000006; 269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_TWO: return 0x01000007; 270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_FEW: return 0x01000008; 271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_MANY: return 0x01000009; 272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski default: return ID_OTHER; 273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue) 278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, tempValue, true); 280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString()); 282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + tempValue.string.toString() + " from drawable " 284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "resource ID #0x" + Integer.toHexString(id), e); 285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException { 290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, value, true); 291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAsset(value.assetCookie, value.string.toString(), 293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.ACCESS_STREAMING); 294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski NotFoundException rnf = new NotFoundException("File " + value.string.toString() + 296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski " from drawable resource ID #0x" + Integer.toHexString(id)); 297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<Animator> getAnimatorCache() { 303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAnimatorCache; 304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { 307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mStateListAnimatorCache; 308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 310082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public void updateConfiguration(Configuration config, DisplayMetrics metrics, 311082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski CompatibilityInfo compat) { 312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mAccessLock) { 313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (false) { 314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": old config is " 315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + mConfiguration + " old compat is " + mCompatibilityInfo); 316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": new config is " 317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + config + " new compat is " + compat); 318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (compat != null) { 320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mCompatibilityInfo = compat; 321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (metrics != null) { 323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.setTo(metrics); 324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // NOTE: We should re-arrange this code to create a Display 326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // with the CompatibilityInfo that is used everywhere we deal 327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // with the display in relation to this app, rather than 328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // doing the conversion here. This impl should be okay because 329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we make sure to return a compatible display in the places 330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // where there are public APIs to retrieve the display... but 331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // it would be cleaner and more maintainble to just be 332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // consistently dealing with a compatible display everywhere in 333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // the framework. 334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mCompatibilityInfo.applyToDisplayMetrics(mMetrics); 335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 336ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette final @Config int configChanges = calcConfigChanges(config); 337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski LocaleList locales = mConfiguration.getLocales(); 339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (locales.isEmpty()) { 340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski locales = LocaleList.getAdjustedDefault(); 341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.setLocales(locales); 342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { 344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.densityDpi = mConfiguration.densityDpi; 345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 346fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 347fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; 348fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 349fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int width, height; 350fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mMetrics.widthPixels >= mMetrics.heightPixels) { 351fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski width = mMetrics.widthPixels; 352fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski height = mMetrics.heightPixels; 353fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 354fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski //noinspection SuspiciousNameCombination 355fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski width = mMetrics.heightPixels; 356fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski //noinspection SuspiciousNameCombination 357fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski height = mMetrics.widthPixels; 358fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 359fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 360fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int keyboardHidden; 361fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO 362fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { 363fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; 364fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 365fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski keyboardHidden = mConfiguration.keyboardHidden; 366fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 367fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 368fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, 369fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski adjustLanguageTag(locales.get(0).toLanguageTag()), 370fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.orientation, 371fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.touchscreen, 372fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.densityDpi, mConfiguration.keyboard, 373fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski keyboardHidden, mConfiguration.navigation, width, height, 374fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.smallestScreenWidthDp, 375fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.screenWidthDp, mConfiguration.screenHeightDp, 376fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.screenLayout, mConfiguration.uiMode, 377fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Build.VERSION.RESOURCES_SDK_INT); 378fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 379fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_CONFIG) { 380fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": final config is " 381fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + mConfiguration + " final compat is " + mCompatibilityInfo); 382fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 383fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 384fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mDrawableCache.onConfigurationChange(configChanges); 385fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mColorDrawableCache.onConfigurationChange(configChanges); 386fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mComplexColorCache.onConfigurationChange(configChanges); 387fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAnimatorCache.onConfigurationChange(configChanges); 388fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mStateListAnimatorCache.onConfigurationChange(configChanges); 389fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 390fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski flushLayoutCache(); 391fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 392fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 393fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPluralRule != null) { 394fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 395fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 396fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 397fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 398fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 399fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 400ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * Applies the new configuration, returning a bitmask of the changes 401ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * between the old and new configurations. 402ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * 403ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @param config the new configuration 404ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @return bitmask of config changes 405fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 406ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette public @Config int calcConfigChanges(@Nullable Configuration config) { 407ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (config == null) { 408ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette // If there is no configuration, assume all flags have changed. 409ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return 0xFFFFFFFF; 410ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 411fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 412ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setTo(config); 413ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette int density = config.densityDpi; 414ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (density == Configuration.DENSITY_DPI_UNDEFINED) { 415ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette density = mMetrics.noncompatDensityDpi; 416ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 417fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 418ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mCompatibilityInfo.applyToConfiguration(density, mTmpConfig); 419ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette 420ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (mTmpConfig.getLocales().isEmpty()) { 421ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setLocales(LocaleList.getDefault()); 422fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 423ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return mConfiguration.updateFrom(mTmpConfig); 424fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 425fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 426fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 427fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated) 428fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively. 429fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 430fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * All released versions of android prior to "L" used the deprecated language 431fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tags, so we will need to support them for backwards compatibility. 432fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 433fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Note that this conversion needs to take place *after* the call to 434fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code toLanguageTag} because that will convert all the deprecated codes to 435fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the new ones, even if they're set manually. 436fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 437fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static String adjustLanguageTag(String languageTag) { 438fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int separator = languageTag.indexOf('-'); 439fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String language; 440fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String remainder; 441fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 442fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (separator == -1) { 443fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag; 444fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = ""; 445fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 446fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag.substring(0, separator); 447fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = languageTag.substring(separator); 448fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 450fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Locale.adjustLanguageCode(language) + remainder; 451fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 452fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 453fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 454fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Call this to remove all cached loaded layout resources from the 455fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resources object. Only intended for use with performance testing 456fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tools. 457fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void flushLayoutCache() { 459fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 460fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockCookies, 0); 461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockFiles, null); 462fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 463fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 464fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) { 465fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[i]; 466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 467fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 468fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(cachedXmlBlocks, null); 471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 473fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 474fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 475fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, 476082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean useCache) throws NotFoundException { 477fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 479fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 480fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 481fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 483fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d("PreloadDrawable", name); 484fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 485fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 486fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 488fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean isColorDrawable; 489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final DrawableCache caches; 490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key; 491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = true; 494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mColorDrawableCache; 495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = value.data; 496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = false; 498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mDrawableCache; 499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = (((long) value.assetCookie) << 32) | value.data; 500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First, check whether we have a cached version of this drawable 503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // that was inflated against the specified theme. Skip the cache if 504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we're currently preloading or we're not using the cache. 505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (!mPreloading && useCache) { 506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme); 507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedDrawable != null) { 508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedDrawable; 509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Next, check preloaded drawables. Preloaded drawables may contain 513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // unresolved theme attributes. 514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs; 515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedColorDrawables.get(key); 517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); 519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable dr; 522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs != null) { 523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = cs.newDrawable(wrapper); 524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (isColorDrawable) { 525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = new ColorDrawable(value.data); 526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = loadDrawableForCookie(wrapper, value, id, null); 528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Determine if the drawable has unresolved theme attributes. If it 531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // does, we'll need to apply a theme and store it in a theme-specific 532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache. 533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean canApplyTheme = dr != null && dr.canApplyTheme(); 534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (canApplyTheme && theme != null) { 535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = dr.mutate(); 536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.applyTheme(theme); 537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.clearMutated(); 538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If we were able to obtain a drawable, store it in the appropriate 541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache: preload, not themed, null theme, or theme-specific. Don't 542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // pollute the cache with drawables loaded from a foreign density. 543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (dr != null && useCache) { 544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.setChangingConfigurations(value.changingConfigurations); 545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); 546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String name; 551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = getResourceName(id); 553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e2) { 554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = "(missing name)"; 555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // The target drawable might fail to load for any number of 558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // reasons, but we always want to include the resource name. 559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Since the client already expects this method to throw a 560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // NotFoundException, just throw one of those. 561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException nfe = new NotFoundException("Drawable " + name 562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " with resource ID #0x" + Integer.toHexString(id), e); 563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski nfe.setStackTrace(new StackTraceElement[0]); 564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw nfe; 565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches, 569082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme, boolean usesTheme, long key, Drawable dr) { 570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs = dr.getConstantState(); 571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs == null) { 572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int changingConfigs = cs.getChangingConfigurations(); 577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) { 579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedColorDrawables.put(key, cs); 580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig( 583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) { 584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) { 585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If this resource does not vary based on layout direction, 586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we can put it in all of the preload maps. 587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0].put(key, cs); 588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1].put(key, cs); 589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Otherwise, only in the layout dir we loaded it for. 591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs); 592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mAccessLock) { 597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches.put(key, theme, cs, usesTheme); 598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 602ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private boolean verifyPreloadConfig(@Config int changingConfigurations, 603ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) { 604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // We allow preloading of resources even if they vary by font scale (which 605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // doesn't impact resource selection) or density (which we handle specially by 606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // simply turning off all preloading), as well as any other configs specified 607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // by the caller. 608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE | 609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) { 610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // This should never happen in production, so we should log a 617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // warning even if we're not debugging. 618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloaded " + name + " resource #0x" 619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ") that varies with configuration!!"); 621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return false; 622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloading " + name + " resource #0x" 631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ")"); 633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 634fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return true; 635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads a drawable from XML or resources stream. 639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id, 641082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" 644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value); 645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id) 655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file); 662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable dr; 665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser rp = loadXmlResourceParser( 670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "drawable"); 671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromXml(wrapper, rp, theme); 672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rp.close(); 673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final InputStream is = mAssets.openNonAsset( 675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski value.assetCookie, file, AssetManager.ACCESS_STREAMING); 676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = Drawable.createFromResourceStream(wrapper, value, is, file, null); 677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski is.close(); 678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); 683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Given the value and id, we can get the XML filename as in value.data, based on that, we 693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * first try to load CSL from the cache. If not found, try to get from the constant state. 694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Last, parse the XML and generate the CSL. 695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme, 697082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski TypedValue value, int id) { 698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache; 700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = cache.getInstance(key, wrapper, theme); 701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = factory.newInstance(wrapper, theme); 710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor == null) { 712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorForCookie(wrapper, value, id, theme); 713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 7160b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette complexColor.setBaseChangingConfigurations(value.changingConfigurations); 7170b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 7190b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette if (verifyPreloadConfig(complexColor.getChangingConfigurations(), 7200b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 0, value.resourceId, "color")) { 721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, complexColor.getConstantState()); 722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cache.put(key, theme, complexColor.getConstantState()); 725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id, 732082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("loadComplexColor", name); 738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor; 752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorFromName(wrapper, theme, value, id); 755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from complex color resource ID #0x" 758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, 773082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) 774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("PreloadColorStateList", name); 780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 781fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 782fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id); 792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null && complexColor instanceof ColorStateList) { 793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) complexColor; 794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't find ColorStateList from drawable resource ID #0x" 798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) { 803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList csl; 804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) factory.newInstance(); 808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski csl = ColorStateList.valueOf(value.data); 811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId, 814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "color")) { 815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, csl.getConstantState()); 816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return csl; 820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Load a ComplexColor based on the XML file content. The result can be a GradientColor or 824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * ColorStateList. Note that pure color will be wrapped into a ColorStateList. 825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * We deferred the parser creation to this function b/c we need to differentiate b/t gradient 827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * and selector tag. 828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content. 830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id, 833082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new UnsupportedOperationException( 836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't convert to ComplexColor: type=0x" + value.type); 837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 838fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id) 847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file); 854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = null; 857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser parser = loadXmlResourceParser( 862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "ComplexColor"); 863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AttributeSet attrs = Xml.asAttributeSet(parser); 865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int type; 866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski while ((type = parser.next()) != XmlPullParser.START_TAG 867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && type != XmlPullParser.END_DOCUMENT) { 868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Seek parser to start tag. 869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (type != XmlPullParser.START_TAG) { 871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new XmlPullParserException("No start tag found"); 872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = parser.getName(); 875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name.equals("gradient")) { 876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme); 877fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (name.equals("selector")) { 878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme); 879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser.close(); 881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from ComplexColor resource ID #0x" 885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 898fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads an XML parser for the specified file. 902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param file the path for the XML file to parse 904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param id the resource identifier for the file 905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assetCookie the asset cookie for the file 906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param type the type of resource (used for logging) 907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a parser for the specified XML file 908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @throws NotFoundException if the file could not be loaded 909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 911082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie, 912082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull String type) 913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies; 918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; 919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First see if this block is in our cache. 921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int num = cachedXmlBlockFiles.length; 922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < num; i++) { 923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null 924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && cachedXmlBlockFiles[i].equals(file)) { 925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedXmlBlocks[i].newParser(); 926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Not in the cache, create a new block and put it at 930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // the next slot in the cache. 931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); 932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (block != null) { 933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int pos = (mLastCachedXmlBlockIndex + 1) % num; 934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mLastCachedXmlBlockIndex = pos; 935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[pos]; 936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockCookies[pos] = assetCookie; 940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockFiles[pos] = file; 941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlocks[pos] = block; 942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return block.newParser(); 943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException("File " + file 947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); 948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" 954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Start preloading of resource data using this Resources object. Only 959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * for use by the zygote process for loading common system resources. 960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@hide} 961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public final void startPreloading() { 963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (sPreloaded) { 965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalStateException("Resources already preloaded"); 966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloaded = true; 968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = true; 969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE; 970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski updateConfiguration(null, null, null); 971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Called by zygote when it is done preloading resources, to change back 976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * to normal Resources operation. 977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void finishPreloading() { 979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = false; 981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski flushLayoutCache(); 982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() { 986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return sPreloadedDrawables[0]; 987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ThemeImpl newThemeImpl() { 990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return new ThemeImpl(); 991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 993082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski /** 994082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey. 995082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski */ 996082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl newThemeImpl(Resources.ThemeKey key) { 997082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl impl = new ThemeImpl(); 998082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.mKey.setTo(key); 999082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.rebase(); 1000082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski return impl; 1001082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski } 1002082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski 1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public class ThemeImpl { 1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unique key for the series of styles applied to this theme. 1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Resources.ThemeKey mKey = new Resources.ThemeKey(); 1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @SuppressWarnings("hiding") 1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final AssetManager mAssets; 1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final long mTheme; 1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resource identifier for the theme. 1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mThemeResId = 0; 1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ ThemeImpl() { 1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = ResourcesImpl.this.mAssets; 1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mTheme = mAssets.createTheme(); 1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Override 1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski protected void finalize() throws Throwable { 1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski super.finalize(); 1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.releaseTheme(mTheme); 1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ Resources.ThemeKey getKey() { 1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mKey; 1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ long getNativeTheme() { 1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mTheme; 1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ int getAppliedStyleResId() { 1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mThemeResId; 1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void applyStyle(int resId, boolean force) { 1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = resId; 1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.append(resId, force); 1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void setTo(ThemeImpl other) { 1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (other.mKey) { 1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.copyTheme(mTheme, other.mTheme); 1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = other.mThemeResId; 1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.setTo(other.getKey()); 1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper, 1063082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski AttributeSet set, 1064082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleableRes int[] attrs, 1065082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @AttrRes int defStyleAttr, 1066082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleRes int defStyleRes) { 1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // XXX note that for now we only work with compiled XML files. 1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // To support generic XML files we will need to manually parse 1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // out the attributes from the XML file (applying type information 1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // contained in the resources and such). 1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock.Parser parser = (XmlBlock.Parser) set; 1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, 1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser != null ? parser.mParseState : 0, 1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrs, array.mData, array.mIndices); 1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = parser; 1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray resolveAttributes(@NonNull Resources.Theme wrapper, 1088082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] values, 1089082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] attrs) { 1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (values == null || len != values.length) { 1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalArgumentException( 1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Base attribute values must the same length as attrs"); 1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); 1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = null; 1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); 1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int[] getAllAttributes() { 1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getStyleAttributes(getAppliedStyleResId()); 1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1115ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int getChangingConfigurations() { 1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int nativeChangingConfig = 1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.getThemeChangingConfigurations(mTheme); 1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); 1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void dump(int priority, String tag, String prefix) { 1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.dumpTheme(mTheme, priority, tag, prefix); 1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String[] getTheme() { 1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int N = mKey.mCount; 1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] themes = new String[N * 2]; 1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { 1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[j]; 1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean forced = mKey.mForce[j]; 1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = getResourceName(resId); 1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = Integer.toHexString(i); 1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i + 1] = forced ? "forced" : "not forced"; 1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return themes; 1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Rebases the theme against the parent Resource object's current 1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * configuration by re-applying the styles passed to 1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@link #applyStyle(int, boolean)}. 1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void rebase() { 1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.clearTheme(mTheme); 1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Reapply the same styles in the same order. 1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < mKey.mCount; i++) { 1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[i]; 1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean force = mKey.mForce[i]; 1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.applyThemeStyle(mTheme, resId, force); 1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski} 1166