ResourcesImpl.java revision 99b25d2817a1058e56c5384a43040e0f3f291ce1
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;
309ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viveretteimport android.content.res.Configuration.NativeConfig;
31fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException;
321480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.graphics.Bitmap;
3318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport android.graphics.Typeface;
34fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable;
35fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable;
36ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghuiimport android.graphics.drawable.DrawableContainer;
37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules;
38fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build;
3923cbe85610f780134cc77dd4a54732a22ed6e86eYohei Yukawaimport android.os.LocaleList;
401480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemClock;
411480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemProperties;
42fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace;
43fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet;
44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics;
45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log;
46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray;
47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog;
48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue;
49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml;
504ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.DisplayAdjustments;
51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
5299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyalimport com.android.internal.util.GrowingArrayUtils;
5399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
541480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParser;
551480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParserException;
561480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
5718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport java.io.IOException;
58fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream;
59fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays;
60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale;
61fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/**
63082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches
64082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it.
65082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
66082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change
67082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying
68082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created.
69082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
70fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide
71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl {
73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static final String TAG = "Resources";
74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_LOAD = false;
76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_CONFIG = false;
77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
781480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    static final String TAG_PRELOAD = TAG + ".preload";
791480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
801480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static final boolean TRACE_FOR_PRELOAD = false; // Do we still need it?
811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static final boolean TRACE_FOR_MISS_PRELOAD = false; // Do we still need it?
821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    public static final boolean TRACE_FOR_DETAILED_PRELOAD =
841480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            SystemProperties.getBoolean("debug.trace_resource_preload", false);
851480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
861480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    /** Used only when TRACE_FOR_DETAILED_PRELOAD is true. */
871480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static int sPreloadTracingNumLoadedDrawables;
881480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private long mPreloadTracingPreloadStartTime;
89aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki    private long mPreloadTracingStartBitmapSize;
90aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki    private long mPreloadTracingStartBitmapCount;
91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int ID_OTHER = 0x01000004;
93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final Object sSync = new Object();
95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static boolean sPreloaded;
97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean mPreloading;
98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Information about preloaded resources.  Note that they are not
100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // protected by a lock, because while preloading in zygote we are all
101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // single-threaded, and after that these are immutable.
102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            = new LongSparseArray<>();
105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloadedComplexColors = new LongSparseArray<>();
107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Lock object used to protect access to caches and configuration. */
109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Object mAccessLock = new Object();
110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // These are protected by mAccessLock.
112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mTmpConfig = new Configuration();
113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mDrawableCache = new DrawableCache();
114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mColorDrawableCache = new DrawableCache();
115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
12299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    // A stack of all the resourceIds already referenced when parsing a resource. This is used to
12399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    // detect circular references in the xml.
12499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    // Using a ThreadLocal variable ensures that we have different stacks for multiple parallel
12599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    // calls to ResourcesImpl
12699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    private final ThreadLocal<LookupStack> mLookupStack =
12799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            ThreadLocal.withInitial(() -> new LookupStack());
12899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Size of the cyclical cache used to map XML files to blocks. */
130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int XML_BLOCK_CACHE_SIZE = 4;
131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Cyclical cache used for recently-accessed XML files.
133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private int mLastCachedXmlBlockIndex = -1;
134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final AssetManager mAssets;
1404ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    private final DisplayMetrics mMetrics = new DisplayMetrics();
1418e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski    private final DisplayAdjustments mDisplayAdjustments;
142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules mPluralRule;
144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mConfiguration = new Configuration();
146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static {
148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables = new LongSparseArray[2];
149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[0] = new LongSparseArray<>();
150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[1] = new LongSparseArray<>();
151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo.
155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assets Previously created AssetManager.
157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param metrics Current display metrics to consider when
158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *                selecting/computing resource values.
159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param config Desired device configuration to consider when
160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *               selecting/computing resource values (optional).
1618e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski     * @param displayAdjustments this resource's Display override and compatibility info.
1628e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski     *                           Must not be null.
163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1644ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
1658e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski            @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) {
166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets = assets;
167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mMetrics.setToDefaults();
1688e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        mDisplayAdjustments = displayAdjustments;
169bad43fcae487a19865c174483c11829379817c8aAdam Lesinski        mConfiguration.setToDefaults();
1708e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets.ensureStringBlocks();
172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1744ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public DisplayAdjustments getDisplayAdjustments() {
1754ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        return mDisplayAdjustments;
1764ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    }
1774ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski
178082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public AssetManager getAssets() {
179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets;
180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    DisplayMetrics getDisplayMetrics() {
183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mMetrics;
186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration getConfiguration() {
189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mConfiguration;
190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration[] getSizeConfigurations() {
193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getSizeConfigurations();
194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CompatibilityInfo getCompatibilityInfo() {
1978e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        return mDisplayAdjustments.getCompatibilityInfo();
198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules getPluralRule() {
201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule == null) {
203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mPluralRule;
206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
219082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean resolveRefs) throws NotFoundException {
220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(String name, TypedValue outValue, boolean resolveRefs)
228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int id = getIdentifier(name, "string", null);
230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            getValue(id, outValue, resolveRefs);
232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("String resource name " + name);
235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    int getIdentifier(String name, String defType, String defPackage) {
238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (name == null) {
239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NullPointerException("name is null");
240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return Integer.parseInt(name);
243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Ignore
245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getResourceIdentifier(name, defType, defPackage);
247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceName(@AnyRes int resid) throws NotFoundException {
251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceName(resid);
252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourcePackageName(resid);
260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceTypeName(resid);
268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceEntryName(resid);
276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        PluralRules rule = getPluralRule();
284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        CharSequence res = mAssets.getResourceBagText(id,
285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                attrForQuantityCode(rule.select(quantity)));
286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        res = mAssets.getResourceBagText(id, ID_OTHER);
290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " quantity=" + quantity
295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " item=" + rule.select(quantity));
296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static int attrForQuantityCode(String quantityCode) {
299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        switch (quantityCode) {
300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ZERO: return 0x01000005;
301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ONE:  return 0x01000006;
302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_TWO:  return 0x01000007;
303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_FEW:  return 0x01000008;
304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_MANY: return 0x01000009;
305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            default:                       return ID_OTHER;
306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, tempValue, true);
313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + "resource ID #0x" + Integer.toHexString(id), e);
318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, value, true);
324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.ACCESS_STREAMING);
327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
328f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            // Note: value.string might be null
329f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            NotFoundException rnf = new NotFoundException("File "
330f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + (value.string == null ? "(null)" : value.string.toString())
331f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + " from drawable resource ID #0x" + Integer.toHexString(id));
332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAnimatorCache;
339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mStateListAnimatorCache;
343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
345082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
346082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                                    CompatibilityInfo compat) {
347991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        try {
349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (mAccessLock) {
350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (false) {
351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": old config is "
3528e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mConfiguration + " old compat is "
3538e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mDisplayAdjustments.getCompatibilityInfo());
354991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": new config is "
355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + config + " new compat is " + compat);
356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (compat != null) {
3588e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                    mDisplayAdjustments.setCompatibilityInfo(compat);
359991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (metrics != null) {
361991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.setTo(metrics);
362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // NOTE: We should re-arrange this code to create a Display
364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the CompatibilityInfo that is used everywhere we deal
365991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the display in relation to this app, rather than
366991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // doing the conversion here.  This impl should be okay because
367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // we make sure to return a compatible display in the places
368991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // where there are public APIs to retrieve the display...  but
369b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // it would be cleaner and more maintainable to just be
370991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // consistently dealing with a compatible display everywhere in
371991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // the framework.
3728e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                mDisplayAdjustments.getCompatibilityInfo().applyToDisplayMetrics(mMetrics);
373991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
374991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final @Config int configChanges = calcConfigChanges(config);
375991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
376b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // If even after the update there are no Locales set, grab the default locales.
377991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                LocaleList locales = mConfiguration.getLocales();
378991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (locales.isEmpty()) {
379b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    locales = LocaleList.getDefault();
380991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mConfiguration.setLocales(locales);
381991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
382b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
383b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
384b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    if (locales.size() > 1) {
385b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // The LocaleList has changed. We must query the AssetManager's available
386b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // Locales and figure out the best matching Locale in the new LocaleList.
387b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        String[] availableLocales = mAssets.getNonSystemLocales();
388b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
389b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            // No app defined locales, so grab the system locales.
390b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            availableLocales = mAssets.getLocales();
391b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
392b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                availableLocales = null;
393b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
394b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
395b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
396b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (availableLocales != null) {
397b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
398b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                    availableLocales);
399b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (bestLocale != null && bestLocale != locales.get(0)) {
400b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                mConfiguration.setLocales(new LocaleList(bestLocale, locales));
401b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
402b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
403b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    }
404b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                }
405b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
406991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.densityDpi = mConfiguration.densityDpi;
408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.density =
409991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
411bad43fcae487a19865c174483c11829379817c8aAdam Lesinski
412bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                // Protect against an unset fontScale.
413bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                mMetrics.scaledDensity = mMetrics.density *
414bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                        (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);
415991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int width, height;
417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mMetrics.widthPixels >= mMetrics.heightPixels) {
418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.widthPixels;
419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.heightPixels;
420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
421991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
422991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.heightPixels;
423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.widthPixels;
425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
426991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int keyboardHidden;
428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        && mConfiguration.hardKeyboardHidden
430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        == Configuration.HARDKEYBOARDHIDDEN_YES) {
431991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
432991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = mConfiguration.keyboardHidden;
434991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
437b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
438991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.orientation,
439991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.touchscreen,
440991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.densityDpi, mConfiguration.keyboard,
441991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        keyboardHidden, mConfiguration.navigation, width, height,
442991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.smallestScreenWidthDp,
443991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
444991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenLayout, mConfiguration.uiMode,
445408afbf06040ea29d1a9d60e9dc50d1923068de4Romain Guy                        mConfiguration.colorMode, Build.VERSION.RESOURCES_SDK_INT);
446991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
447991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (DEBUG_CONFIG) {
448991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": final config is "
4498e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mConfiguration + " final compat is "
4508e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mDisplayAdjustments.getCompatibilityInfo());
451991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
452991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
453991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mDrawableCache.onConfigurationChange(configChanges);
454991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mColorDrawableCache.onConfigurationChange(configChanges);
455991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mComplexColorCache.onConfigurationChange(configChanges);
456991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAnimatorCache.onConfigurationChange(configChanges);
457991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mStateListAnimatorCache.onConfigurationChange(configChanges);
458991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
459991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                flushLayoutCache();
460fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
461991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (sSync) {
462991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mPluralRule != null) {
463991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
464991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
465fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
466991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        } finally {
467991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
468fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
472ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * Applies the new configuration, returning a bitmask of the changes
473ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * between the old and new configurations.
474ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     *
475ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @param config the new configuration
476ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @return bitmask of config changes
477fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
478ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    public @Config int calcConfigChanges(@Nullable Configuration config) {
479ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (config == null) {
480ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            // If there is no configuration, assume all flags have changed.
481ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            return 0xFFFFFFFF;
482ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
483fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
484ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mTmpConfig.setTo(config);
485ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        int density = config.densityDpi;
486ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
487ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            density = mMetrics.noncompatDensityDpi;
488ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
4908e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        mDisplayAdjustments.getCompatibilityInfo().applyToConfiguration(density, mTmpConfig);
491ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette
492ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (mTmpConfig.getLocales().isEmpty()) {
493ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            mTmpConfig.setLocales(LocaleList.getDefault());
494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
495ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        return mConfiguration.updateFrom(mTmpConfig);
496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * All released versions of android prior to "L" used the deprecated language
503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tags, so we will need to support them for backwards compatibility.
504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Note that this conversion needs to take place *after* the call to
506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code toLanguageTag} because that will convert all the deprecated codes to
507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * the new ones, even if they're set manually.
508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static String adjustLanguageTag(String languageTag) {
510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final int separator = languageTag.indexOf('-');
511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String language;
512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String remainder;
513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (separator == -1) {
515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag;
516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = "";
517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag.substring(0, separator);
519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = languageTag.substring(separator);
520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return Locale.adjustLanguageCode(language) + remainder;
523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Call this to remove all cached loaded layout resources from the
527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Resources object.  Only intended for use with performance testing
528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tools.
529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public void flushLayoutCache() {
531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mCachedXmlBlocks) {
532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockCookies, 0);
533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockFiles, null);
534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock oldBlock = cachedXmlBlocks[i];
538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (oldBlock != null) {
539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    oldBlock.close();
540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(cachedXmlBlocks, null);
543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
54750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
54850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            int density, @Nullable Resources.Theme theme)
54950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            throws NotFoundException {
55050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // If the drawable's XML lives in our current density qualifier,
55150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // it's okay to use a scaled version from the cache. Otherwise, we
55250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // need to actually load the drawable from XML.
55350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        final boolean useCache = density == 0 || value.density == mMetrics.densityDpi;
55450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski
55550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // Pretend the requested density is actually the display density. If
55650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // the drawable returned is not the requested density, then force it
55750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // to be scaled later by dividing its density by the ratio of
55850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // requested density to actual device density. Drawables that have
55950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // undefined density or no density don't need to be handled here.
56050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        if (density > 0 && value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
56150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            if (value.density == density) {
56250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                value.density = mMetrics.densityDpi;
56350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            } else {
56450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                value.density = (value.density * mMetrics.densityDpi) / density;
56550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            }
56650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        }
56750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski
568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (TRACE_FOR_PRELOAD) {
570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Log only framework resources
571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if ((id >>> 24) == 0x1) {
572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String name = getResourceName(id);
573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (name != null) {
574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        Log.d("PreloadDrawable", name);
575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean isColorDrawable;
580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final DrawableCache caches;
581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final long key;
582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = true;
585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mColorDrawableCache;
586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = value.data;
587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = false;
589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mDrawableCache;
590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = (((long) value.assetCookie) << 32) | value.data;
591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // First, check whether we have a cached version of this drawable
594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // that was inflated against the specified theme. Skip the cache if
595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we're currently preloading or we're not using the cache.
596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (!mPreloading && useCache) {
597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (cachedDrawable != null) {
59958857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    return cachedDrawable;
601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Next, check preloaded drawables. Preloaded drawables may contain
605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // unresolved theme attributes.
606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final Drawable.ConstantState cs;
607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedColorDrawables.get(key);
609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Drawable dr;
614ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            boolean needsNewDrawableAfterCache = false;
615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (cs != null) {
6161480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                if (TRACE_FOR_DETAILED_PRELOAD) {
6171480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    // Log only framework resources
6181480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    if (((id >>> 24) == 0x1) && (android.os.Process.myUid() != 0)) {
6191480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        final String name = getResourceName(id);
6201480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        if (name != null) {
6211480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Log.d(TAG_PRELOAD, "Hit preloaded FW drawable #"
6221480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                                    + Integer.toHexString(id) + " " + name);
6231480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        }
6241480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    }
6251480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                }
626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = cs.newDrawable(wrapper);
627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else if (isColorDrawable) {
628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = new ColorDrawable(value.data);
629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
63050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                dr = loadDrawableForCookie(wrapper, value, id, density, null);
631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
632ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // DrawableContainer' constant state has drawables instances. In order to leave the
633ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // constant state intact in the cache, we need to create a new DrawableContainer after
634ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // added to cache.
635ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            if (dr instanceof DrawableContainer)  {
636ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                needsNewDrawableAfterCache = true;
637ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            }
638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Determine if the drawable has unresolved theme attributes. If it
640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // does, we'll need to apply a theme and store it in a theme-specific
641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache.
642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (canApplyTheme && theme != null) {
644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = dr.mutate();
645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.applyTheme(theme);
646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.clearMutated();
647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // If we were able to obtain a drawable, store it in the appropriate
650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache: preload, not themed, null theme, or theme-specific. Don't
651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // pollute the cache with drawables loaded from a foreign density.
65258857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette            if (dr != null) {
653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.setChangingConfigurations(value.changingConfigurations);
65458857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                if (useCache) {
65558857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
656ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                    if (needsNewDrawableAfterCache) {
657ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        Drawable.ConstantState state = dr.getConstantState();
658ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        if (state != null) {
659ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                            dr = state.newDrawable(wrapper);
660ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        }
661ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                    }
66258857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                }
663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return dr;
666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String name;
668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = getResourceName(id);
670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e2) {
671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = "(missing name)";
672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // The target drawable might fail to load for any number of
675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // reasons, but we always want to include the resource name.
676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Since the client already expects this method to throw a
677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NotFoundException, just throw one of those.
678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException nfe = new NotFoundException("Drawable " + name
679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " with resource ID #0x" + Integer.toHexString(id), e);
680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            nfe.setStackTrace(new StackTraceElement[0]);
681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw nfe;
682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
686082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable.ConstantState cs = dr.getConstantState();
688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (cs == null) {
689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int changingConfigs = cs.getChangingConfigurations();
694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedColorDrawables.put(key, cs);
697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(
700a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette                        changingConfigs, ActivityInfo.CONFIG_LAYOUT_DIRECTION, value.resourceId, "drawable")) {
701a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette                    if ((changingConfigs & ActivityInfo.CONFIG_LAYOUT_DIRECTION) == 0) {
702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // If this resource does not vary based on layout direction,
703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // we can put it in all of the preload maps.
704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[0].put(key, cs);
705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[1].put(key, cs);
706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } else {
707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // Otherwise, only in the layout dir we loaded it for.
708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mAccessLock) {
714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches.put(key, theme, cs, usesTheme);
715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
719ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private boolean verifyPreloadConfig(@Config int changingConfigurations,
720ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) {
721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // We allow preloading of resources even if they vary by font scale (which
722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // doesn't impact resource selection) or density (which we handle specially by
723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // simply turning off all preloading), as well as any other configs specified
724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // by the caller.
725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // This should never happen in production, so we should log a
734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // warning even if we're not debugging.
735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloaded " + name + " resource #0x"
736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ") that varies with configuration!!");
738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return false;
739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloading " + name + " resource #0x"
748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ")");
750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return true;
752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads a drawable from XML or resources stream.
756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
75750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
75850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            int id, int density, @Nullable Resources.Theme theme) {
759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
7771480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        // For prelaod tracing.
7781480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        long startTime = 0;
7791480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        int startBitmapCount = 0;
7801480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        long startBitmapSize = 0;
7811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        int startDrwableCount = 0;
7821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        if (TRACE_FOR_DETAILED_PRELOAD) {
7831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startTime = System.nanoTime();
7841480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
7851480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
7861480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startDrwableCount = sPreloadTracingNumLoadedDrawables;
7871480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        }
7881480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable dr;
794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
79699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        LookupStack stack = mLookupStack.get();
797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
79899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            // Perform a linear search to check if we have already referenced this resource before.
79999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            if (stack.contains(id)) {
80099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                throw new Exception("Recursive reference in drawable");
801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
80299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            stack.push(id);
80399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            try {
80499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                if (file.endsWith(".xml")) {
80599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    final XmlResourceParser rp = loadXmlResourceParser(
80699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                            file, id, value.assetCookie, "drawable");
80799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
80899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    rp.close();
80999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                } else {
81099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    final InputStream is = mAssets.openNonAsset(
81199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                            value.assetCookie, file, AssetManager.ACCESS_STREAMING);
81299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
81399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    is.close();
81499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                }
81599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            } finally {
81699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                stack.pop();
81799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            }
81899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        } catch (Exception e) {
819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException rnf = new NotFoundException(
821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
8271480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        if (TRACE_FOR_DETAILED_PRELOAD) {
8281480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (((id >>> 24) == 0x1)) {
8291480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                final String name = getResourceName(id);
8301480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                if (name != null) {
8311480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final long time = System.nanoTime() - startTime;
8321480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final int loadedBitmapCount =
8331480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Bitmap.sPreloadTracingNumInstantiatedBitmaps - startBitmapCount;
8341480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final long loadedBitmapSize =
8351480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize;
8361480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final int loadedDrawables =
8371480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            sPreloadTracingNumLoadedDrawables - startDrwableCount;
8381480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8391480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    sPreloadTracingNumLoadedDrawables++;
8401480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8411480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final boolean isRoot = (android.os.Process.myUid() == 0);
8421480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8431480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    Log.d(TAG_PRELOAD,
8441480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            (isRoot ? "Preloaded FW drawable #"
8451480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                                    : "Loaded non-preloaded FW drawable #")
8461480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + Integer.toHexString(id)
8471480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + name
8481480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + file
8491480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + dr.getClass().getCanonicalName()
8501480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " #nested_drawables= " + loadedDrawables
8511480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " #bitmaps= " + loadedBitmapCount
8521480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " total_bitmap_size= " + loadedBitmapSize
8531480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " in[us] " + (time / 1000));
8541480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                }
8551480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
8561480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        }
8571480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return dr;
859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
86218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri     * Loads a font from XML or resources stream.
86318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri     */
86418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    @Nullable
865ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri    public Typeface loadFont(Resources wrapper, TypedValue value, int id) {
86618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        if (value.string == null) {
86718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
86818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri                    + Integer.toHexString(id) + ") is not a Font: " + value);
86918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
87018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
87118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        final String file = value.string.toString();
8722ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka        if (!file.startsWith("res/")) {
8732ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka            return null;
8742ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka        }
8752ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka
876b12397e57e79c5dd9e8b2cb3839f5cd30b5d515fClara Bayarri        Typeface cached = Typeface.findFromCache(mAssets, file);
877ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        if (cached != null) {
878ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            return cached;
879ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        }
88018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
88118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        if (DEBUG_LOAD) {
88218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file);
88318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
88418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
88518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
88618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        try {
887ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            if (file.endsWith("xml")) {
888ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri                final XmlResourceParser rp = loadXmlResourceParser(
889ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri                        file, id, value.assetCookie, "font");
890ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                final FontResourcesParser.FamilyResourceEntry familyEntry =
891ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                        FontResourcesParser.parse(rp, wrapper);
892ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                if (familyEntry == null) {
893ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                    return null;
894ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                }
895ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                return Typeface.createFromResources(familyEntry, mAssets, file);
89618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            }
897ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            return Typeface.createFromResources(mAssets, file, value.assetCookie);
898ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        } catch (XmlPullParserException e) {
899ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            Log.e(TAG, "Failed to parse xml resource " + file, e);
900ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        } catch (IOException e) {
901ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            Log.e(TAG, "Failed to read xml resource " + file, e);
90218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        } finally {
90318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
90418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
90518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        return null;
90618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    }
90718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
90818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    /**
909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Given the value and id, we can get the XML filename as in value.data, based on that, we
910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * first try to load CSL from the cache. If not found, try to get from the constant state.
911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Last, parse the XML and generate the CSL.
912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
914082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            TypedValue value, int id) {
915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return complexColor;
920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = factory.newInstance(wrapper, theme);
927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor == null) {
929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
9330b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
9340b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette
935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPreloading) {
9360b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
9370b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                        0, value.resourceId, "color")) {
938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cache.put(key, theme, complexColor.getConstantState());
942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
949082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("loadComplexColor", name);
955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor;
969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from complex color resource ID #0x"
975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
990082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme)
991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("PreloadColorStateList", name);
997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null && complexColor instanceof ColorStateList) {
1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) complexColor;
1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException(
1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                "Can't find ColorStateList from drawable resource ID #0x"
1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + Integer.toHexString(id));
1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ColorStateList csl;
1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) factory.newInstance();
1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        csl = ColorStateList.valueOf(value.data);
1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "color")) {
1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.put(key, csl.getConstantState());
1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return csl;
1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * and selector tag.
1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
1050082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new UnsupportedOperationException(
1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "Can't convert to ComplexColor: type=0x" + value.type);
1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = null;
1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser parser = loadXmlResourceParser(
1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "ComplexColor");
1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final AttributeSet attrs = Xml.asAttributeSet(parser);
1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                int type;
1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                while ((type = parser.next()) != XmlPullParser.START_TAG
1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        && type != XmlPullParser.END_DOCUMENT) {
1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Seek parser to start tag.
1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (type != XmlPullParser.START_TAG) {
1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new XmlPullParserException("No start tag found");
1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = parser.getName();
1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name.equals("gradient")) {
1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                } else if (name.equals("selector")) {
1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                parser.close();
1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from ComplexColor resource ID #0x"
1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads an XML parser for the specified file.
1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param file the path for the XML file to parse
1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param id the resource identifier for the file
1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assetCookie the asset cookie for the file
1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param type the type of resource (used for logging)
1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a parser for the specified XML file
1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @throws NotFoundException if the file could not be loaded
1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
1128082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
1129082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            @NonNull String type)
1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (mCachedXmlBlocks) {
1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // First see if this block is in our cache.
1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int num = cachedXmlBlockFiles.length;
1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    for (int i = 0; i < num; i++) {
1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                && cachedXmlBlockFiles[i].equals(file)) {
1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            return cachedXmlBlocks[i].newParser();
1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Not in the cache, create a new block and put it at
1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // the next slot in the cache.
1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (block != null) {
1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        mLastCachedXmlBlockIndex = pos;
1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (oldBlock != null) {
1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            oldBlock.close();
1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockCookies[pos] = assetCookie;
1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockFiles[pos] = file;
1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlocks[pos] = block;
1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        return block.newParser();
1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException("File " + file
1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(id));
1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Start preloading of resource data using this Resources object.  Only
1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * for use by the zygote process for loading common system resources.
1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@hide}
1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public final void startPreloading() {
1180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
1181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (sPreloaded) {
1182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw new IllegalStateException("Resources already preloaded");
1183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloaded = true;
1185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = true;
1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            updateConfiguration(null, null, null);
11881480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
11891480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (TRACE_FOR_DETAILED_PRELOAD) {
11901480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                mPreloadTracingPreloadStartTime = SystemClock.uptimeMillis();
1191aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                mPreloadTracingStartBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
1192aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                mPreloadTracingStartBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
11931480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                Log.d(TAG_PRELOAD, "Preload starting");
11941480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Called by zygote when it is done preloading resources, to change back
1200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * to normal Resources operation.
1201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void finishPreloading() {
1203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
12041480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (TRACE_FOR_DETAILED_PRELOAD) {
12051480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                final long time = SystemClock.uptimeMillis() - mPreloadTracingPreloadStartTime;
1206aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                final long size =
1207aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                        Bitmap.sPreloadTracingTotalBitmapsSize - mPreloadTracingStartBitmapSize;
1208aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                final long count = Bitmap.sPreloadTracingNumInstantiatedBitmaps
1209aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                        - mPreloadTracingStartBitmapCount;
1210aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                Log.d(TAG_PRELOAD, "Preload finished, "
1211aa6560c148909ae0e0be4cbc3d14562ba3eceb77Makoto Onuki                        + count + " bitmaps of " + size + " bytes in " + time + " ms");
12121480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
12131480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
1214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = false;
1215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
1216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
1220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return sPreloadedDrawables[0];
1221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ThemeImpl newThemeImpl() {
1224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return new ThemeImpl();
1225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1227082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    /**
1228082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
1229082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     */
1230082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
1231082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        ThemeImpl impl = new ThemeImpl();
1232082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.mKey.setTo(key);
1233082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.rebase();
1234082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        return impl;
1235082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    }
1236082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski
1237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public class ThemeImpl {
1238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Unique key for the series of styles applied to this theme.
1240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
1242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @SuppressWarnings("hiding")
1244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final AssetManager mAssets;
1245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final long mTheme;
1246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Resource identifier for the theme.
1249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private int mThemeResId = 0;
1251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ ThemeImpl() {
1253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets = ResourcesImpl.this.mAssets;
1254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTheme = mAssets.createTheme();
1255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @Override
1258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        protected void finalize() throws Throwable {
1259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            super.finalize();
1260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.releaseTheme(mTheme);
1261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ Resources.ThemeKey getKey() {
1264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mKey;
1265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ long getNativeTheme() {
1268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mTheme;
1269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ int getAppliedStyleResId() {
1272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mThemeResId;
1273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void applyStyle(int resId, boolean force) {
1276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyThemeStyle(mTheme, resId, force);
1278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mThemeResId = resId;
1280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mKey.append(resId, force);
1281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void setTo(ThemeImpl other) {
1285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (other.mKey) {
1287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.copyTheme(mTheme, other.mTheme);
1288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mThemeResId = other.mThemeResId;
1290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mKey.setTo(other.getKey());
1291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
1297082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                AttributeSet set,
1298082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleableRes int[] attrs,
1299082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @AttrRes int defStyleAttr,
1300082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleRes int defStyleRes) {
1301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // XXX note that for now we only work with compiled XML files.
1306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // To support generic XML files we will need to manually parse
1307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // out the attributes from the XML file (applying type information
1308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // contained in the resources and such).
1309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        parser != null ? parser.mParseState : 0,
1312f32adf447511d54c2aa0948d3c1ef44d461538acJohn Reck                        attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
1313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = parser;
1315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
1322082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] values,
1323082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] attrs) {
1324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (values == null || len != values.length) {
1327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new IllegalArgumentException(
1328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            "Base attribute values must the same length as attrs");
1329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = null;
1335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int[] getAllAttributes() {
1346fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.getStyleAttributes(getAppliedStyleResId());
1347fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1348fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1349ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        @Config int getChangingConfigurations() {
1350fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
13519ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viverette                final @NativeConfig int nativeChangingConfig =
1352fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        AssetManager.getThemeChangingConfigurations(mTheme);
1353fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1354fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1355fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1356fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1357fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        public void dump(int priority, String tag, String prefix) {
1358fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1359fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1360fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1361fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1362fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1363fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String[] getTheme() {
1364fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1365fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int N = mKey.mCount;
1366fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String[] themes = new String[N * 2];
1367fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1368fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[j];
1369fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean forced = mKey.mForce[j];
1370fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    try {
1371fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = getResourceName(resId);
1372fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } catch (NotFoundException e) {
1373fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = Integer.toHexString(i);
1374fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1375fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    themes[i + 1] = forced ? "forced" : "not forced";
1376fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1377fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return themes;
1378fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1379fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1380fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1381fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1382fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Rebases the theme against the parent Resource object's current
1383fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * configuration by re-applying the styles passed to
1384fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * {@link #applyStyle(int, boolean)}.
1385fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1386fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void rebase() {
1387fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1388fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.clearTheme(mTheme);
1389fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1390fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Reapply the same styles in the same order.
1391fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0; i < mKey.mCount; i++) {
1392fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[i];
1393fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean force = mKey.mForce[i];
1394fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.applyThemeStyle(mTheme, resId, force);
1395fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1396fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1397fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1398fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
139999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
140099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    private static class LookupStack {
140199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
140299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        // Pick a reasonable default size for the array, it is grown as needed.
140399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        private int[] mIds = new int[4];
140499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        private int mSize = 0;
140599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
140699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        public void push(int id) {
140799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            mIds = GrowingArrayUtils.append(mIds, mSize, id);
140899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            mSize++;
140999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        }
141099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
141199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        public boolean contains(int id) {
141299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            for (int i = 0; i < mSize; i++) {
141399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                if (mIds[i] == id) {
141499b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                    return true;
141599b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal                }
141699b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            }
141799b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            return false;
141899b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        }
141999b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal
142099b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        public void pop() {
142199b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal            mSize--;
142299b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal        }
142399b25d2817a1058e56c5384a43040e0f3f291ce1Sunny Goyal    }
1424fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski}
1425