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 18fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.Animator; 19fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.StateListAnimator; 20fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AnyRes; 21fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AttrRes; 22fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.NonNull; 23fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.Nullable; 24fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.PluralsRes; 25fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.RawRes; 26fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleRes; 27fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleableRes; 28fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.pm.ActivityInfo; 29ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.content.pm.ActivityInfo.Config; 30513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins IIIimport android.content.res.AssetManager.AssetInputStream; 319ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viveretteimport android.content.res.Configuration.NativeConfig; 32fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException; 331480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.graphics.Bitmap; 34513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins IIIimport android.graphics.ImageDecoder; 3518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport android.graphics.Typeface; 36fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable; 37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable; 38ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghuiimport android.graphics.drawable.DrawableContainer; 39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules; 40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build; 4123cbe85610f780134cc77dd4a54732a22ed6e86eYohei Yukawaimport android.os.LocaleList; 421480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemClock; 431480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemProperties; 44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace; 45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet; 46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics; 47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log; 48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray; 49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog; 50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue; 51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml; 524ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.DisplayAdjustments; 53fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 5499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyalimport com.android.internal.util.GrowingArrayUtils; 5599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 561480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParser; 571480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParserException; 581480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 5918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport java.io.IOException; 60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream; 61fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays; 62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale; 63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/** 65082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches 66082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it. 67082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 68082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change 69082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying 70082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created. 71082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * 72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide 73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl { 75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static final String TAG = "Resources"; 76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_LOAD = false; 78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final boolean DEBUG_CONFIG = false; 79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 801480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki static final String TAG_PRELOAD = TAG + ".preload"; 811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki private static final boolean TRACE_FOR_PRELOAD = false; // Do we still need it? 831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki private static final boolean TRACE_FOR_MISS_PRELOAD = false; // Do we still need it? 841480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 851480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki public static final boolean TRACE_FOR_DETAILED_PRELOAD = 861480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki SystemProperties.getBoolean("debug.trace_resource_preload", false); 871480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 881480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki /** Used only when TRACE_FOR_DETAILED_PRELOAD is true. */ 891480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki private static int sPreloadTracingNumLoadedDrawables; 901480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki private long mPreloadTracingPreloadStartTime; 91aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki private long mPreloadTracingStartBitmapSize; 92aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki private long mPreloadTracingStartBitmapCount; 93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int ID_OTHER = 0x01000004; 95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final Object sSync = new Object(); 97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static boolean sPreloaded; 99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private boolean mPreloading; 100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Information about preloaded resources. Note that they are not 102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // protected by a lock, because while preloading in zygote we are all 103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // single-threaded, and after that these are immutable. 104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables; 105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables 106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski = new LongSparseArray<>(); 107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>> 108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors = new LongSparseArray<>(); 109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Lock object used to protect access to caches and configuration. */ 111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Object mAccessLock = new Object(); 112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // These are protected by mAccessLock. 114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mTmpConfig = new Configuration(); 115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mDrawableCache = new DrawableCache(); 116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final DrawableCache mColorDrawableCache = new DrawableCache(); 117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache = 118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = 120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = 122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski new ConfigurationBoundResourceCache<>(); 123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 12499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // A stack of all the resourceIds already referenced when parsing a resource. This is used to 12599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // detect circular references in the xml. 12699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // Using a ThreadLocal variable ensures that we have different stacks for multiple parallel 12799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // calls to ResourcesImpl 12899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal private final ThreadLocal<LookupStack> mLookupStack = 12999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal ThreadLocal.withInitial(() -> new LookupStack()); 13099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** Size of the cyclical cache used to map XML files to blocks. */ 132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static final int XML_BLOCK_CACHE_SIZE = 4; 133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Cyclical cache used for recently-accessed XML files. 135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mLastCachedXmlBlockIndex = -1; 136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE]; 137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE]; 138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE]; 139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AssetManager mAssets; 1424ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski private final DisplayMetrics mMetrics = new DisplayMetrics(); 1438e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski private final DisplayAdjustments mDisplayAdjustments; 144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules mPluralRule; 146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Configuration mConfiguration = new Configuration(); 148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski static { 150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables = new LongSparseArray[2]; 151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0] = new LongSparseArray<>(); 152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1] = new LongSparseArray<>(); 153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Creates a new ResourcesImpl object with CompatibilityInfo. 157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assets Previously created AssetManager. 159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param metrics Current display metrics to consider when 160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values. 161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param config Desired device configuration to consider when 162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * selecting/computing resource values (optional). 1638e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski * @param displayAdjustments this resource's Display override and compatibility info. 1648e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski * Must not be null. 165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1664ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics, 1678e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) { 168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = assets; 169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mMetrics.setToDefaults(); 1708e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments = displayAdjustments; 171bad43fcae487a19865c174483c11829379817c8aAdam Lesinski mConfiguration.setToDefaults(); 1728e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo()); 173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1754ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski public DisplayAdjustments getDisplayAdjustments() { 1764ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski return mDisplayAdjustments; 1774ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski } 1784ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski 179082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public AssetManager getAssets() { 180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets; 181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski DisplayMetrics getDisplayMetrics() { 184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels 185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "x" + mMetrics.heightPixels + " " + mMetrics.density); 186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mMetrics; 187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration getConfiguration() { 190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mConfiguration; 191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Configuration[] getSizeConfigurations() { 194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getSizeConfigurations(); 195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CompatibilityInfo getCompatibilityInfo() { 1988e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski return mDisplayAdjustments.getCompatibilityInfo(); 199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private PluralRules getPluralRule() { 202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPluralRule == null) { 204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mPluralRule; 207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs) 211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs); 213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValueForDensity(@AnyRes int id, int density, TypedValue outValue, 220082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski boolean resolveRefs) throws NotFoundException { 221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs); 222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (found) { 223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)); 226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void getValue(String name, TypedValue outValue, boolean resolveRefs) 229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int id = getIdentifier(name, "string", null); 231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, outValue, resolveRefs); 233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("String resource name " + name); 236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int getIdentifier(String name, String defType, String defPackage) { 239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name == null) { 240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NullPointerException("name is null"); 241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Integer.parseInt(name); 244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Ignore 246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getResourceIdentifier(name, defType, defPackage); 248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceName(@AnyRes int resid) throws NotFoundException { 252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceName(resid); 253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourcePackageName(@AnyRes int resid) throws NotFoundException { 260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourcePackageName(resid); 261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceTypeName(@AnyRes int resid) throws NotFoundException { 268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceTypeName(resid); 269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String getResourceEntryName(@AnyRes int resid) throws NotFoundException { 276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String str = mAssets.getResourceEntryName(resid); 277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (str != null) return str; 278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Unable to find resource ID #0x" 279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resid)); 280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { 284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski PluralRules rule = getPluralRule(); 285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski CharSequence res = mAssets.getResourceBagText(id, 286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski attrForQuantityCode(rule.select(quantity))); 287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski res = mAssets.getResourceBagText(id, ID_OTHER); 291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (res != null) { 292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return res; 293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id) 295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " quantity=" + quantity 296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " item=" + rule.select(quantity)); 297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static int attrForQuantityCode(String quantityCode) { 300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski switch (quantityCode) { 301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ZERO: return 0x01000005; 302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_ONE: return 0x01000006; 303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_TWO: return 0x01000007; 304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_FEW: return 0x01000008; 305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski case PluralRules.KEYWORD_MANY: return 0x01000009; 306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski default: return ID_OTHER; 307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue) 312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, tempValue, true); 314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString()); 316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + tempValue.string.toString() + " from drawable " 318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + "resource ID #0x" + Integer.toHexString(id), e); 319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException { 324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski getValue(id, value, true); 325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.openNonAsset(value.assetCookie, value.string.toString(), 327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski AssetManager.ACCESS_STREAMING); 328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 329f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate // Note: value.string might be null 330f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate NotFoundException rnf = new NotFoundException("File " 331f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + (value.string == null ? "(null)" : value.string.toString()) 332f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate + " from drawable resource ID #0x" + Integer.toHexString(id)); 333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<Animator> getAnimatorCache() { 339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAnimatorCache; 340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { 343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mStateListAnimatorCache; 344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 346082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski public void updateConfiguration(Configuration config, DisplayMetrics metrics, 347082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski CompatibilityInfo compat) { 348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration"); 349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski try { 350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (mAccessLock) { 351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (false) { 352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": old config is " 3538e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mConfiguration + " old compat is " 3548e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mDisplayAdjustments.getCompatibilityInfo()); 355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": new config is " 356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski + config + " new compat is " + compat); 357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 358991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (compat != null) { 3598e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.setCompatibilityInfo(compat); 360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 361991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (metrics != null) { 362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.setTo(metrics); 363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // NOTE: We should re-arrange this code to create a Display 365991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the CompatibilityInfo that is used everywhere we deal 366991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // with the display in relation to this app, rather than 367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // doing the conversion here. This impl should be okay because 368991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // we make sure to return a compatible display in the places 369991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // where there are public APIs to retrieve the display... but 370b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // it would be cleaner and more maintainable to just be 371991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // consistently dealing with a compatible display everywhere in 372991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski // the framework. 3738e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.getCompatibilityInfo().applyToDisplayMetrics(mMetrics); 374991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 375991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final @Config int configChanges = calcConfigChanges(config); 376991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 377b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // If even after the update there are no Locales set, grab the default locales. 378991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski LocaleList locales = mConfiguration.getLocales(); 379991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (locales.isEmpty()) { 380b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski locales = LocaleList.getDefault(); 381991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.setLocales(locales); 382991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 383b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 384b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) { 385b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (locales.size() > 1) { 386b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // The LocaleList has changed. We must query the AssetManager's available 387b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // Locales and figure out the best matching Locale in the new LocaleList. 388b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski String[] availableLocales = mAssets.getNonSystemLocales(); 389b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 390b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski // No app defined locales, so grab the system locales. 391b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = mAssets.getLocales(); 392b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (LocaleList.isPseudoLocalesOnly(availableLocales)) { 393b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales = null; 394b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 395b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 396b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 397b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (availableLocales != null) { 398b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski final Locale bestLocale = locales.getFirstMatchWithEnglishSupported( 399b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski availableLocales); 400b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski if (bestLocale != null && bestLocale != locales.get(0)) { 401b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski mConfiguration.setLocales(new LocaleList(bestLocale, locales)); 402b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 403b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 404b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 405b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski } 406b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski 407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) { 408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.densityDpi = mConfiguration.densityDpi; 409991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mMetrics.density = 410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 411991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 412bad43fcae487a19865c174483c11829379817c8aAdam Lesinski 413bad43fcae487a19865c174483c11829379817c8aAdam Lesinski // Protect against an unset fontScale. 414bad43fcae487a19865c174483c11829379817c8aAdam Lesinski mMetrics.scaledDensity = mMetrics.density * 415bad43fcae487a19865c174483c11829379817c8aAdam Lesinski (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f); 416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int width, height; 418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mMetrics.widthPixels >= mMetrics.heightPixels) { 419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.widthPixels; 420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.heightPixels; 421991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 422991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski width = mMetrics.heightPixels; 424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski //noinspection SuspiciousNameCombination 425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski height = mMetrics.widthPixels; 426991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski final int keyboardHidden; 429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO 430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski && mConfiguration.hardKeyboardHidden 431991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski == Configuration.HARDKEYBOARDHIDDEN_YES) { 432991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT; 433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } else { 434991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden = mConfiguration.keyboardHidden; 435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 437991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, 438b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()), 439991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.orientation, 440991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.touchscreen, 441991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.densityDpi, mConfiguration.keyboard, 442991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski keyboardHidden, mConfiguration.navigation, width, height, 443991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.smallestScreenWidthDp, 444991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenWidthDp, mConfiguration.screenHeightDp, 445991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mConfiguration.screenLayout, mConfiguration.uiMode, 446408afbf06040ea29d1a9d60e9dc50d1923068de4Romain Guy mConfiguration.colorMode, Build.VERSION.RESOURCES_SDK_INT); 447991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 448991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (DEBUG_CONFIG) { 449991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Slog.i(TAG, "**** Updating config of " + this + ": final config is " 4508e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mConfiguration + " final compat is " 4518e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski + mDisplayAdjustments.getCompatibilityInfo()); 452991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 453991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 454991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mDrawableCache.onConfigurationChange(configChanges); 455991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mColorDrawableCache.onConfigurationChange(configChanges); 456991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mComplexColorCache.onConfigurationChange(configChanges); 457991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mAnimatorCache.onConfigurationChange(configChanges); 458991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mStateListAnimatorCache.onConfigurationChange(configChanges); 459991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski 460991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski flushLayoutCache(); 461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 462991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski synchronized (sSync) { 463991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski if (mPluralRule != null) { 464991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0)); 465991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } 466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 467991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski } finally { 468991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 473ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * Applies the new configuration, returning a bitmask of the changes 474ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * between the old and new configurations. 475ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * 476ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @param config the new configuration 477ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette * @return bitmask of config changes 478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 479ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette public @Config int calcConfigChanges(@Nullable Configuration config) { 480ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (config == null) { 481ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette // If there is no configuration, assume all flags have changed. 482ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return 0xFFFFFFFF; 483ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 484fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 485ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setTo(config); 486ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette int density = config.densityDpi; 487ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (density == Configuration.DENSITY_DPI_UNDEFINED) { 488ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette density = mMetrics.noncompatDensityDpi; 489ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette } 490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 4918e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski mDisplayAdjustments.getCompatibilityInfo().applyToConfiguration(density, mTmpConfig); 492ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette 493ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette if (mTmpConfig.getLocales().isEmpty()) { 494ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette mTmpConfig.setLocales(LocaleList.getDefault()); 495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 496ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette return mConfiguration.updateFrom(mTmpConfig); 497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated) 501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively. 502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * All released versions of android prior to "L" used the deprecated language 504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tags, so we will need to support them for backwards compatibility. 505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Note that this conversion needs to take place *after* the call to 507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@code toLanguageTag} because that will convert all the deprecated codes to 508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the new ones, even if they're set manually. 509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private static String adjustLanguageTag(String languageTag) { 511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int separator = languageTag.indexOf('-'); 512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String language; 513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String remainder; 514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (separator == -1) { 516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag; 517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = ""; 518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski language = languageTag.substring(0, separator); 520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski remainder = languageTag.substring(separator); 521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return Locale.adjustLanguageCode(language) + remainder; 524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Call this to remove all cached loaded layout resources from the 528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resources object. Only intended for use with performance testing 529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * tools. 530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void flushLayoutCache() { 532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockCookies, 0); 534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(mCachedXmlBlockFiles, null); 535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) { 538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[i]; 539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Arrays.fill(cachedXmlBlocks, null); 544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 5471194b0bdfed798cae594c6e80c13855ea6618f3bChris Craik @Nullable 54850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id, 54950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski int density, @Nullable Resources.Theme theme) 55050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski throws NotFoundException { 55150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // If the drawable's XML lives in our current density qualifier, 55250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // it's okay to use a scaled version from the cache. Otherwise, we 55350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // need to actually load the drawable from XML. 55450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski final boolean useCache = density == 0 || value.density == mMetrics.densityDpi; 55550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski 55650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // Pretend the requested density is actually the display density. If 55750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // the drawable returned is not the requested density, then force it 55850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // to be scaled later by dividing its density by the ratio of 55950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // requested density to actual device density. Drawables that have 56050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski // undefined density or no density don't need to be handled here. 56150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski if (density > 0 && value.density > 0 && value.density != TypedValue.DENSITY_NONE) { 56250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski if (value.density == density) { 56350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski value.density = mMetrics.densityDpi; 56450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski } else { 56550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski value.density = (value.density * mMetrics.densityDpi) / density; 56650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski } 56750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski } 56850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski 569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d("PreloadDrawable", name); 576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean isColorDrawable; 581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final DrawableCache caches; 582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key; 583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = true; 586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mColorDrawableCache; 587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = value.data; 588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski isColorDrawable = false; 590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches = mDrawableCache; 591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski key = (((long) value.assetCookie) << 32) | value.data; 592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First, check whether we have a cached version of this drawable 595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // that was inflated against the specified theme. Skip the cache if 596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we're currently preloading or we're not using the cache. 597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (!mPreloading && useCache) { 598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme); 599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedDrawable != null) { 60058857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette cachedDrawable.setChangingConfigurations(value.changingConfigurations); 601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedDrawable; 602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Next, check preloaded drawables. Preloaded drawables may contain 606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // unresolved theme attributes. 607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs; 608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedColorDrawables.get(key); 610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); 612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Drawable dr; 615ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui boolean needsNewDrawableAfterCache = false; 616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs != null) { 6171480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (TRACE_FOR_DETAILED_PRELOAD) { 6181480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki // Log only framework resources 6191480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (((id >>> 24) == 0x1) && (android.os.Process.myUid() != 0)) { 6201480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final String name = getResourceName(id); 6211480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (name != null) { 6221480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki Log.d(TAG_PRELOAD, "Hit preloaded FW drawable #" 6231480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + Integer.toHexString(id) + " " + name); 6241480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 6251480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 6261480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = cs.newDrawable(wrapper); 628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (isColorDrawable) { 629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = new ColorDrawable(value.data); 630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 631ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik dr = loadDrawableForCookie(wrapper, value, id, density); 632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 633ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui // DrawableContainer' constant state has drawables instances. In order to leave the 634ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui // constant state intact in the cache, we need to create a new DrawableContainer after 635ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui // added to cache. 636ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui if (dr instanceof DrawableContainer) { 637ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui needsNewDrawableAfterCache = true; 638ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui } 639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Determine if the drawable has unresolved theme attributes. If it 641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // does, we'll need to apply a theme and store it in a theme-specific 642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache. 643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean canApplyTheme = dr != null && dr.canApplyTheme(); 644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (canApplyTheme && theme != null) { 645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr = dr.mutate(); 646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.applyTheme(theme); 647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.clearMutated(); 648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If we were able to obtain a drawable, store it in the appropriate 651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // cache: preload, not themed, null theme, or theme-specific. Don't 652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // pollute the cache with drawables loaded from a foreign density. 65358857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette if (dr != null) { 654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski dr.setChangingConfigurations(value.changingConfigurations); 65558857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette if (useCache) { 65658857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); 657ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui if (needsNewDrawableAfterCache) { 658ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui Drawable.ConstantState state = dr.getConstantState(); 659ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui if (state != null) { 660ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui dr = state.newDrawable(wrapper); 661ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui } 662ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui } 66358857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette } 664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String name; 669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = getResourceName(id); 671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e2) { 672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski name = "(missing name)"; 673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // The target drawable might fail to load for any number of 676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // reasons, but we always want to include the resource name. 677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Since the client already expects this method to throw a 678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // NotFoundException, just throw one of those. 679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException nfe = new NotFoundException("Drawable " + name 680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " with resource ID #0x" + Integer.toHexString(id), e); 681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski nfe.setStackTrace(new StackTraceElement[0]); 682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw nfe; 683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches, 687082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme, boolean usesTheme, long key, Drawable dr) { 688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable.ConstantState cs = dr.getConstantState(); 689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cs == null) { 690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return; 691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int changingConfigs = cs.getChangingConfigurations(); 695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (isColorDrawable) { 696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) { 697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedColorDrawables.put(key, cs); 698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig( 701a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette changingConfigs, ActivityInfo.CONFIG_LAYOUT_DIRECTION, value.resourceId, "drawable")) { 702a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette if ((changingConfigs & ActivityInfo.CONFIG_LAYOUT_DIRECTION) == 0) { 703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // If this resource does not vary based on layout direction, 704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // we can put it in all of the preload maps. 705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[0].put(key, cs); 706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[1].put(key, cs); 707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Otherwise, only in the layout dir we loaded it for. 709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs); 710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mAccessLock) { 715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski caches.put(key, theme, cs, usesTheme); 716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 720ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette private boolean verifyPreloadConfig(@Config int changingConfigurations, 721ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) { 722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // We allow preloading of resources even if they vary by font scale (which 723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // doesn't impact resource selection) or density (which we handle specially by 724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // simply turning off all preloading), as well as any other configs specified 725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // by the caller. 726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE | 727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) { 728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // This should never happen in production, so we should log a 735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // warning even if we're not debugging. 736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloaded " + name + " resource #0x" 737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ") that varies with configuration!!"); 739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return false; 740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String resName; 743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = getResourceName(resourceId); 745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski resName = "?"; 747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.w(TAG, "Preloading " + name + " resource #0x" 749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(resourceId) 750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " (" + resName + ")"); 751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return true; 753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 756513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III * Loads a Drawable from an encoded image stream, or null. 757513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III * 758513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III * This call will handle closing ais. 759513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III */ 7601194b0bdfed798cae594c6e80c13855ea6618f3bChris Craik @Nullable 761513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III private Drawable decodeImageDrawable(@NonNull AssetInputStream ais, 762513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III @NonNull Resources wrapper, @NonNull TypedValue value) { 763513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais, 764513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III wrapper, value); 765513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III try { 766513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> { 767513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE); 768513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III }); 769513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III } catch (IOException ioe) { 770513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III // This is okay. This may be something that ImageDecoder does not 771513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III // support, like SVG. 772513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III return null; 773513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III } 774513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III } 775513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III 776513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III /** 777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads a drawable from XML or resources stream. 7781194b0bdfed798cae594c6e80c13855ea6618f3bChris Craik * 7791194b0bdfed798cae594c6e80c13855ea6618f3bChris Craik * @return Drawable, or null if Drawable cannot be decoded. 780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 7811194b0bdfed798cae594c6e80c13855ea6618f3bChris Craik @Nullable 78250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value, 783ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik int id, int density) { 784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" 786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value); 787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id) 797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 802ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik // For preload tracing. 8031480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki long startTime = 0; 8041480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki int startBitmapCount = 0; 8051480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki long startBitmapSize = 0; 806ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik int startDrawableCount = 0; 8071480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (TRACE_FOR_DETAILED_PRELOAD) { 8081480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki startTime = System.nanoTime(); 8091480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps; 8101480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize; 811ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik startDrawableCount = sPreloadTracingNumLoadedDrawables; 8121480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 8131480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file); 816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 818ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik 819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final Drawable dr; 820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 82299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal LookupStack stack = mLookupStack.get(); 823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 82499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // Perform a linear search to check if we have already referenced this resource before. 82599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal if (stack.contains(id)) { 82699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal throw new Exception("Recursive reference in drawable"); 827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 82899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal stack.push(id); 82999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal try { 83099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal if (file.endsWith(".xml")) { 83199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal final XmlResourceParser rp = loadXmlResourceParser( 83299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal file, id, value.assetCookie, "drawable"); 833ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null); 83499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal rp.close(); 83599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } else { 83699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal final InputStream is = mAssets.openNonAsset( 83799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal value.assetCookie, file, AssetManager.ACCESS_STREAMING); 838513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III AssetInputStream ais = (AssetInputStream) is; 839513031d15b78579e39d59b71ab5a1b0afabc5544Leon Scroggins III dr = decodeImageDrawable(ais, wrapper, value); 84099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 84199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } finally { 84299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal stack.pop(); 84399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 844aff04c35ae4dd98bf1a0ea363e5708bd40cf2ad9Hyunyoung Song } catch (Exception | StackOverflowError e) { 845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id)); 848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 8531480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (TRACE_FOR_DETAILED_PRELOAD) { 8541480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (((id >>> 24) == 0x1)) { 8551480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final String name = getResourceName(id); 8561480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (name != null) { 8571480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final long time = System.nanoTime() - startTime; 8581480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final int loadedBitmapCount = 8591480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki Bitmap.sPreloadTracingNumInstantiatedBitmaps - startBitmapCount; 8601480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final long loadedBitmapSize = 8611480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize; 8621480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final int loadedDrawables = 863ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik sPreloadTracingNumLoadedDrawables - startDrawableCount; 8641480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 8651480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki sPreloadTracingNumLoadedDrawables++; 8661480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 8671480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final boolean isRoot = (android.os.Process.myUid() == 0); 8681480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 8691480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki Log.d(TAG_PRELOAD, 8701480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki (isRoot ? "Preloaded FW drawable #" 8711480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki : "Loaded non-preloaded FW drawable #") 8721480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + Integer.toHexString(id) 8731480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " " + name 8741480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " " + file 8751480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " " + dr.getClass().getCanonicalName() 8761480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " #nested_drawables= " + loadedDrawables 8771480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " #bitmaps= " + loadedBitmapCount 8781480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " total_bitmap_size= " + loadedBitmapSize 8791480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki + " in[us] " + (time / 1000)); 8801480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 8811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 8821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 8831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return dr; 885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 88818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri * Loads a font from XML or resources stream. 88918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri */ 89018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri @Nullable 891ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri public Typeface loadFont(Resources wrapper, TypedValue value, int id) { 89218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri if (value.string == null) { 89318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" 89418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri + Integer.toHexString(id) + ") is not a Font: " + value); 89518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } 89618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri 89718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri final String file = value.string.toString(); 8982ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka if (!file.startsWith("res/")) { 8992ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka return null; 9002ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka } 9012ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka 902b12397e57e79c5dd9e8b2cb3839f5cd30b5d515fClara Bayarri Typeface cached = Typeface.findFromCache(mAssets, file); 903ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri if (cached != null) { 904ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri return cached; 905ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri } 90618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri 90718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri if (DEBUG_LOAD) { 90818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file); 90918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } 91018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri 91118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 91218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri try { 913ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri if (file.endsWith("xml")) { 914ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri final XmlResourceParser rp = loadXmlResourceParser( 915ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri file, id, value.assetCookie, "font"); 916ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka final FontResourcesParser.FamilyResourceEntry familyEntry = 917ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka FontResourcesParser.parse(rp, wrapper); 918ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka if (familyEntry == null) { 919ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka return null; 920ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka } 921ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka return Typeface.createFromResources(familyEntry, mAssets, file); 92218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } 923ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri return Typeface.createFromResources(mAssets, file, value.assetCookie); 924ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri } catch (XmlPullParserException e) { 925ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri Log.e(TAG, "Failed to parse xml resource " + file, e); 926ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri } catch (IOException e) { 927ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri Log.e(TAG, "Failed to read xml resource " + file, e); 92818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } finally { 92918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 93018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } 93118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri return null; 93218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri } 93318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri 93418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri /** 935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Given the value and id, we can get the XML filename as in value.data, based on that, we 936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * first try to load CSL from the cache. If not found, try to get from the constant state. 937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Last, parse the XML and generate the CSL. 938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 9392e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik @Nullable 940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme, 941082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski TypedValue value, int id) { 942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache; 944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = cache.getInstance(key, wrapper, theme); 945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null) { 946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = factory.newInstance(wrapper, theme); 954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor == null) { 956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorForCookie(wrapper, value, id, theme); 957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 9592e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik if (complexColor != null) { 9602e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik complexColor.setBaseChangingConfigurations(value.changingConfigurations); 9610b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette 9622e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik if (mPreloading) { 9632e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik if (verifyPreloadConfig(complexColor.getChangingConfigurations(), 9642e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik 0, value.resourceId, "color")) { 9652e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik sPreloadedComplexColors.put(key, complexColor.getConstantState()); 9662e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik } 9672e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik } else { 9682e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik cache.put(key, theme, complexColor.getConstantState()); 969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Nullable 975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id, 976082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("loadComplexColor", name); 982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor; 996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = loadComplexColorFromName(wrapper, theme, value, id); 999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from complex color resource ID #0x" 1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1015ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik @NonNull 1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, 1017082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) 1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_PRELOAD) { 1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) android.util.Log.d("PreloadColorStateList", name); 1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final long key = (((long) value.assetCookie) << 32) | value.data; 1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Handle inline color definitions. 1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT 1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { 1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return getColorStateListFromInt(value, key); 1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id); 1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (complexColor != null && complexColor instanceof ColorStateList) { 1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) complexColor; 1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't find ColorStateList from drawable resource ID #0x" 1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) { 1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ColorStateList csl; 1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final android.content.res.ConstantState<ComplexColor> factory = 1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.get(key); 1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (factory != null) { 1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return (ColorStateList) factory.newInstance(); 1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski csl = ColorStateList.valueOf(value.data); 1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId, 1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "color")) { 1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloadedComplexColors.put(key, csl.getConstantState()); 1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return csl; 1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Load a ComplexColor based on the XML file content. The result can be a GradientColor or 1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * ColorStateList. Note that pure color will be wrapped into a ColorStateList. 1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * We deferred the parser creation to this function b/c we need to differentiate b/t gradient 1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * and selector tag. 1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 10732e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content, or 10742e41d49d0023cbbb762c3254ef37295d6fb03d14Chris Craik * {@code null} if the XML file is neither. 1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1076ceb269362175e90899e8bdcad4319b91ee13abb6Chris Craik @NonNull 1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id, 1078082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski Resources.Theme theme) { 1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (value.string == null) { 1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new UnsupportedOperationException( 1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Can't convert to ComplexColor: type=0x" + value.type); 1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String file = value.string.toString(); 1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (TRACE_FOR_MISS_PRELOAD) { 1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Log only framework resources 1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if ((id >>> 24) == 0x1) { 1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = getResourceName(id); 1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name != null) { 1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id) 1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + ": " + name + " at " + file); 1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (DEBUG_LOAD) { 1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file); 1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ComplexColor complexColor = null; 1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); 1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (file.endsWith(".xml")) { 1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlResourceParser parser = loadXmlResourceParser( 1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski file, id, value.assetCookie, "ComplexColor"); 1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final AttributeSet attrs = Xml.asAttributeSet(parser); 1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int type; 1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski while ((type = parser.next()) != XmlPullParser.START_TAG 1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && type != XmlPullParser.END_DOCUMENT) { 1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Seek parser to start tag. 1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (type != XmlPullParser.START_TAG) { 1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new XmlPullParserException("No start tag found"); 1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String name = parser.getName(); 1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (name.equals("gradient")) { 1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme); 1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else if (name.equals("selector")) { 1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme); 1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski parser.close(); 1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException( 1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from ComplexColor resource ID #0x" 1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } else { 1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException( 1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "File " + file + " from drawable resource ID #0x" 1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id) + ": .xml extension required"); 1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return complexColor; 1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Loads an XML parser for the specified file. 1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * 1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param file the path for the XML file to parse 1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param id the resource identifier for the file 1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param assetCookie the asset cookie for the file 1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @param type the type of resource (used for logging) 1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @return a parser for the specified XML file 1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @throws NotFoundException if the file could not be loaded 1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1156082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie, 1157082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull String type) 1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throws NotFoundException { 1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (id != 0) { 1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mCachedXmlBlocks) { 1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies; 1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; 1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; 1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // First see if this block is in our cache. 1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int num = cachedXmlBlockFiles.length; 1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < num; i++) { 1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null 1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski && cachedXmlBlockFiles[i].equals(file)) { 1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return cachedXmlBlocks[i].newParser(); 1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Not in the cache, create a new block and put it at 1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // the next slot in the cache. 1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); 1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (block != null) { 1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int pos = (mLastCachedXmlBlockIndex + 1) % num; 1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mLastCachedXmlBlockIndex = pos; 1180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock oldBlock = cachedXmlBlocks[pos]; 1181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (oldBlock != null) { 1182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski oldBlock.close(); 1183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockCookies[pos] = assetCookie; 1185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlockFiles[pos] = file; 1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski cachedXmlBlocks[pos] = block; 1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return block.newParser(); 1188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (Exception e) { 1191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final NotFoundException rnf = new NotFoundException("File " + file 1192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); 1193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski rnf.initCause(e); 1194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw rnf; 1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" 1199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski + Integer.toHexString(id)); 1200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Start preloading of resource data using this Resources object. Only 1204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * for use by the zygote process for loading common system resources. 1205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@hide} 1206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public final void startPreloading() { 1208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (sSync) { 1209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (sPreloaded) { 1210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalStateException("Resources already preloaded"); 1211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski sPreloaded = true; 1213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = true; 1214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE; 1215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski updateConfiguration(null, null, null); 12161480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 12171480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (TRACE_FOR_DETAILED_PRELOAD) { 12181480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki mPreloadTracingPreloadStartTime = SystemClock.uptimeMillis(); 1219aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki mPreloadTracingStartBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize; 1220aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki mPreloadTracingStartBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps; 12211480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki Log.d(TAG_PRELOAD, "Preload starting"); 12221480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 1223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Called by zygote when it is done preloading resources, to change back 1228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * to normal Resources operation. 1229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void finishPreloading() { 1231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (mPreloading) { 12321480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki if (TRACE_FOR_DETAILED_PRELOAD) { 12331480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki final long time = SystemClock.uptimeMillis() - mPreloadTracingPreloadStartTime; 1234aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki final long size = 1235aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki Bitmap.sPreloadTracingTotalBitmapsSize - mPreloadTracingStartBitmapSize; 1236aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki final long count = Bitmap.sPreloadTracingNumInstantiatedBitmaps 1237aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki - mPreloadTracingStartBitmapCount; 1238aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki Log.d(TAG_PRELOAD, "Preload finished, " 1239aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki + count + " bitmaps of " + size + " bytes in " + time + " ms"); 12401480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki } 12411480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki 1242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mPreloading = false; 1243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski flushLayoutCache(); 1244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() { 1248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return sPreloadedDrawables[0]; 1249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski ThemeImpl newThemeImpl() { 1252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return new ThemeImpl(); 1253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1255082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski /** 1256082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey. 1257082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski */ 1258082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl newThemeImpl(Resources.ThemeKey key) { 1259082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski ThemeImpl impl = new ThemeImpl(); 1260082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.mKey.setTo(key); 1261082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski impl.rebase(); 1262082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski return impl; 1263082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski } 1264082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski 1265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public class ThemeImpl { 1266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unique key for the series of styles applied to this theme. 1268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final Resources.ThemeKey mKey = new Resources.ThemeKey(); 1270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @SuppressWarnings("hiding") 1272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final AssetManager mAssets; 1273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private final long mTheme; 1274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Resource identifier for the theme. 1277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski private int mThemeResId = 0; 1279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ ThemeImpl() { 1281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets = ResourcesImpl.this.mAssets; 1282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mTheme = mAssets.createTheme(); 1283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @Override 1286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski protected void finalize() throws Throwable { 1287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski super.finalize(); 1288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mAssets.releaseTheme(mTheme); 1289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ Resources.ThemeKey getKey() { 1292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mKey; 1293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ long getNativeTheme() { 1296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mTheme; 1297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /*package*/ int getAppliedStyleResId() { 1300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mThemeResId; 1301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void applyStyle(int resId, boolean force) { 1304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1305bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski mAssets.applyStyleToTheme(mTheme, resId, force); 1306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = resId; 1307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.append(resId, force); 1308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void setTo(ThemeImpl other) { 1312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (other.mKey) { 1314bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski AssetManager.nativeThemeCopy(mTheme, other.mTheme); 1315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mThemeResId = other.mThemeResId; 1317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski mKey.setTo(other.getKey()); 1318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper, 1324082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski AttributeSet set, 1325082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleableRes int[] attrs, 1326082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @AttrRes int defStyleAttr, 1327082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @StyleRes int defStyleRes) { 1328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // XXX note that for now we only work with compiled XML files. 1333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // To support generic XML files we will need to manually parse 1334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // out the attributes from the XML file (applying type information 1335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // contained in the resources and such). 1336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final XmlBlock.Parser parser = (XmlBlock.Parser) set; 1337bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs, 1338bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski array.mDataAddress, array.mIndicesAddress); 1339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = parser; 1341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski @NonNull 1346fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski TypedArray resolveAttributes(@NonNull Resources.Theme wrapper, 1347082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] values, 1348082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski @NonNull int[] attrs) { 1349fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1350fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int len = attrs.length; 1351fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski if (values == null || len != values.length) { 1352fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski throw new IllegalArgumentException( 1353fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski "Base attribute values must the same length as attrs"); 1354fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1355fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1356fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final TypedArray array = TypedArray.obtain(wrapper.getResources(), len); 1357bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices); 1358fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mTheme = wrapper; 1359fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski array.mXml = null; 1360fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return array; 1361fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1362fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1363fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1364fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 1365fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1366fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs); 1367fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1368fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1369fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1370fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski int[] getAllAttributes() { 1371fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return mAssets.getStyleAttributes(getAppliedStyleResId()); 1372fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1373fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1374ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette @Config int getChangingConfigurations() { 1375fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 13769ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viverette final @NativeConfig int nativeChangingConfig = 1377bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski AssetManager.nativeThemeGetChangingConfigurations(mTheme); 1378fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig); 1379fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1380fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1381fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1382fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski public void dump(int priority, String tag, String prefix) { 1383fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1384bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski mAssets.dumpTheme(mTheme, priority, tag, prefix); 1385fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1386fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1387fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1388fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski String[] getTheme() { 1389fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1390fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int N = mKey.mCount; 1391fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final String[] themes = new String[N * 2]; 1392fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) { 1393fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[j]; 1394fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean forced = mKey.mForce[j]; 1395fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski try { 1396fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = getResourceName(resId); 1397fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } catch (NotFoundException e) { 1398fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i] = Integer.toHexString(i); 1399fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1400fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski themes[i + 1] = forced ? "forced" : "not forced"; 1401fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1402fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski return themes; 1403fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1404fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1405fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1406fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski /** 1407fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Rebases the theme against the parent Resource object's current 1408fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * configuration by re-applying the styles passed to 1409fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * {@link #applyStyle(int, boolean)}. 1410fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */ 1411fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski void rebase() { 1412fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski synchronized (mKey) { 1413bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski AssetManager.nativeThemeClear(mTheme); 1414fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski 1415fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski // Reapply the same styles in the same order. 1416fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski for (int i = 0; i < mKey.mCount; i++) { 1417fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final int resId = mKey.mResId[i]; 1418fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski final boolean force = mKey.mForce[i]; 1419bebfcc46a249a70af04bc18490a897888a142fb8Adam Lesinski mAssets.applyStyleToTheme(mTheme, resId, force); 1420fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1421fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1422fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 1423fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski } 142499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 142599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal private static class LookupStack { 142699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 142799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal // Pick a reasonable default size for the array, it is grown as needed. 142899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal private int[] mIds = new int[4]; 142999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal private int mSize = 0; 143099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 143199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal public void push(int id) { 143299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal mIds = GrowingArrayUtils.append(mIds, mSize, id); 143399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal mSize++; 143499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 143599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 143699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal public boolean contains(int id) { 143799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal for (int i = 0; i < mSize; i++) { 143899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal if (mIds[i] == id) { 143999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal return true; 144099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 144199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 144299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal return false; 144399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 144499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal 144599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal public void pop() { 144699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal mSize--; 144799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 144899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal } 1449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski} 1450