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