ResourcesImpl.java revision 1480b67635cdc4c2c5e735741bf30393fd70d738
1fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/*
2fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Copyright (C) 2016 The Android Open Source Project
3fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
4fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * use this file except in compliance with the License. You may obtain a copy of
6fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License at
7fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
8fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0
9fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
10fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * License for the specific language governing permissions and limitations under
14fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License.
15fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
16fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipackage android.content.res;
17fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
18fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.Animator;
19fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.StateListAnimator;
20fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AnyRes;
21fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AttrRes;
22fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.NonNull;
23fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.Nullable;
24fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.PluralsRes;
25fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.RawRes;
26fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleRes;
27fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleableRes;
28fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.pm.ActivityInfo;
29ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.content.pm.ActivityInfo.Config;
309ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viveretteimport android.content.res.Configuration.NativeConfig;
31fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException;
321480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.graphics.Bitmap;
3318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport android.graphics.Typeface;
34fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable;
35fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable;
36ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghuiimport android.graphics.drawable.DrawableContainer;
37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules;
38fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build;
3923cbe85610f780134cc77dd4a54732a22ed6e86eYohei Yukawaimport android.os.LocaleList;
401480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemClock;
411480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport android.os.SystemProperties;
42fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace;
43fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet;
44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics;
45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log;
46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray;
47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog;
48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue;
49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml;
504ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.DisplayAdjustments;
51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
521480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParser;
531480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onukiimport org.xmlpull.v1.XmlPullParserException;
541480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
5518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarriimport java.io.IOException;
56fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream;
57fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays;
58fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale;
59fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/**
61082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches
62082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it.
63082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
64082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change
65082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying
66082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created.
67082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide
69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
70fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl {
71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static final String TAG = "Resources";
72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_LOAD = false;
74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_CONFIG = false;
75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
761480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    static final String TAG_PRELOAD = TAG + ".preload";
771480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
781480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static final boolean TRACE_FOR_PRELOAD = false; // Do we still need it?
791480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static final boolean TRACE_FOR_MISS_PRELOAD = false; // Do we still need it?
801480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    public static final boolean TRACE_FOR_DETAILED_PRELOAD =
821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            SystemProperties.getBoolean("debug.trace_resource_preload", false);
831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
841480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    /** Used only when TRACE_FOR_DETAILED_PRELOAD is true. */
851480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private static int sPreloadTracingNumLoadedDrawables;
861480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki    private long mPreloadTracingPreloadStartTime;
87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int ID_OTHER = 0x01000004;
89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final Object sSync = new Object();
91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static boolean sPreloaded;
93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean mPreloading;
94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Information about preloaded resources.  Note that they are not
96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // protected by a lock, because while preloading in zygote we are all
97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // single-threaded, and after that these are immutable.
98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            = new LongSparseArray<>();
101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloadedComplexColors = new LongSparseArray<>();
103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Lock object used to protect access to caches and configuration. */
105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Object mAccessLock = new Object();
106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // These are protected by mAccessLock.
108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mTmpConfig = new Configuration();
109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mDrawableCache = new DrawableCache();
110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mColorDrawableCache = new DrawableCache();
111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Size of the cyclical cache used to map XML files to blocks. */
119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int XML_BLOCK_CACHE_SIZE = 4;
120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Cyclical cache used for recently-accessed XML files.
122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private int mLastCachedXmlBlockIndex = -1;
123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final AssetManager mAssets;
1294ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    private final DisplayMetrics mMetrics = new DisplayMetrics();
1308e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski    private final DisplayAdjustments mDisplayAdjustments;
131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules mPluralRule;
133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mConfiguration = new Configuration();
135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static {
137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables = new LongSparseArray[2];
138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[0] = new LongSparseArray<>();
139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[1] = new LongSparseArray<>();
140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo.
144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assets Previously created AssetManager.
146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param metrics Current display metrics to consider when
147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *                selecting/computing resource values.
148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param config Desired device configuration to consider when
149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *               selecting/computing resource values (optional).
1508e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski     * @param displayAdjustments this resource's Display override and compatibility info.
1518e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski     *                           Must not be null.
152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1534ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
1548e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski            @Nullable Configuration config, @NonNull DisplayAdjustments displayAdjustments) {
155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets = assets;
156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mMetrics.setToDefaults();
1578e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        mDisplayAdjustments = displayAdjustments;
158bad43fcae487a19865c174483c11829379817c8aAdam Lesinski        mConfiguration.setToDefaults();
1598e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets.ensureStringBlocks();
161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1634ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public DisplayAdjustments getDisplayAdjustments() {
1644ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        return mDisplayAdjustments;
1654ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    }
1664ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski
167082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public AssetManager getAssets() {
168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets;
169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    DisplayMetrics getDisplayMetrics() {
172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mMetrics;
175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration getConfiguration() {
178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mConfiguration;
179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration[] getSizeConfigurations() {
182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getSizeConfigurations();
183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CompatibilityInfo getCompatibilityInfo() {
1868e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        return mDisplayAdjustments.getCompatibilityInfo();
187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules getPluralRule() {
190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule == null) {
192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mPluralRule;
195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
208082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean resolveRefs) throws NotFoundException {
209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(String name, TypedValue outValue, boolean resolveRefs)
217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int id = getIdentifier(name, "string", null);
219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            getValue(id, outValue, resolveRefs);
221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("String resource name " + name);
224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    int getIdentifier(String name, String defType, String defPackage) {
227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (name == null) {
228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NullPointerException("name is null");
229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return Integer.parseInt(name);
232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Ignore
234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getResourceIdentifier(name, defType, defPackage);
236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceName(@AnyRes int resid) throws NotFoundException {
240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceName(resid);
241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourcePackageName(resid);
249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceTypeName(resid);
257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceEntryName(resid);
265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        PluralRules rule = getPluralRule();
273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        CharSequence res = mAssets.getResourceBagText(id,
274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                attrForQuantityCode(rule.select(quantity)));
275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        res = mAssets.getResourceBagText(id, ID_OTHER);
279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " quantity=" + quantity
284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " item=" + rule.select(quantity));
285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static int attrForQuantityCode(String quantityCode) {
288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        switch (quantityCode) {
289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ZERO: return 0x01000005;
290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ONE:  return 0x01000006;
291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_TWO:  return 0x01000007;
292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_FEW:  return 0x01000008;
293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_MANY: return 0x01000009;
294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            default:                       return ID_OTHER;
295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, tempValue, true);
302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + "resource ID #0x" + Integer.toHexString(id), e);
307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, value, true);
313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.ACCESS_STREAMING);
316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
317f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            // Note: value.string might be null
318f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            NotFoundException rnf = new NotFoundException("File "
319f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + (value.string == null ? "(null)" : value.string.toString())
320f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + " from drawable resource ID #0x" + Integer.toHexString(id));
321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAnimatorCache;
328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mStateListAnimatorCache;
332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
334082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
335082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                                    CompatibilityInfo compat) {
336991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
337991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        try {
338991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (mAccessLock) {
339991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (false) {
340991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": old config is "
3418e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mConfiguration + " old compat is "
3428e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mDisplayAdjustments.getCompatibilityInfo());
343991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": new config is "
344991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + config + " new compat is " + compat);
345991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
346991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (compat != null) {
3478e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                    mDisplayAdjustments.setCompatibilityInfo(compat);
348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (metrics != null) {
350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.setTo(metrics);
351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // NOTE: We should re-arrange this code to create a Display
353991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the CompatibilityInfo that is used everywhere we deal
354991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the display in relation to this app, rather than
355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // doing the conversion here.  This impl should be okay because
356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // we make sure to return a compatible display in the places
357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // where there are public APIs to retrieve the display...  but
358b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // it would be cleaner and more maintainable to just be
359991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // consistently dealing with a compatible display everywhere in
360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // the framework.
3618e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                mDisplayAdjustments.getCompatibilityInfo().applyToDisplayMetrics(mMetrics);
362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final @Config int configChanges = calcConfigChanges(config);
364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
365b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // If even after the update there are no Locales set, grab the default locales.
366991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                LocaleList locales = mConfiguration.getLocales();
367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (locales.isEmpty()) {
368b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    locales = LocaleList.getDefault();
369991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mConfiguration.setLocales(locales);
370991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
371b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
372b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
373b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    if (locales.size() > 1) {
374b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // The LocaleList has changed. We must query the AssetManager's available
375b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // Locales and figure out the best matching Locale in the new LocaleList.
376b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        String[] availableLocales = mAssets.getNonSystemLocales();
377b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
378b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            // No app defined locales, so grab the system locales.
379b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            availableLocales = mAssets.getLocales();
380b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
381b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                availableLocales = null;
382b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
383b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
384b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
385b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (availableLocales != null) {
386b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
387b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                    availableLocales);
388b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (bestLocale != null && bestLocale != locales.get(0)) {
389b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                mConfiguration.setLocales(new LocaleList(bestLocale, locales));
390b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
391b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
392b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    }
393b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                }
394b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
395991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
396991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.densityDpi = mConfiguration.densityDpi;
397991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.density =
398991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
399991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
400bad43fcae487a19865c174483c11829379817c8aAdam Lesinski
401bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                // Protect against an unset fontScale.
402bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                mMetrics.scaledDensity = mMetrics.density *
403bad43fcae487a19865c174483c11829379817c8aAdam Lesinski                        (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);
404991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
405991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int width, height;
406991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mMetrics.widthPixels >= mMetrics.heightPixels) {
407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.widthPixels;
408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.heightPixels;
409991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
411991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.heightPixels;
412991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
413991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.widthPixels;
414991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
415991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int keyboardHidden;
417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        && mConfiguration.hardKeyboardHidden
419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        == Configuration.HARDKEYBOARDHIDDEN_YES) {
420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
421991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
422991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = mConfiguration.keyboardHidden;
423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
426b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.orientation,
428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.touchscreen,
429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.densityDpi, mConfiguration.keyboard,
430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        keyboardHidden, mConfiguration.navigation, width, height,
431991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.smallestScreenWidthDp,
432991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenLayout, mConfiguration.uiMode,
434408afbf06040ea29d1a9d60e9dc50d1923068de4Romain Guy                        mConfiguration.colorMode, Build.VERSION.RESOURCES_SDK_INT);
435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (DEBUG_CONFIG) {
437991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": final config is "
4388e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mConfiguration + " final compat is "
4398e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski                            + mDisplayAdjustments.getCompatibilityInfo());
440991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
441991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
442991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mDrawableCache.onConfigurationChange(configChanges);
443991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mColorDrawableCache.onConfigurationChange(configChanges);
444991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mComplexColorCache.onConfigurationChange(configChanges);
445991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAnimatorCache.onConfigurationChange(configChanges);
446991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mStateListAnimatorCache.onConfigurationChange(configChanges);
447991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
448991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                flushLayoutCache();
449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
450991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (sSync) {
451991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mPluralRule != null) {
452991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
453991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
454fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
455991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        } finally {
456991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
457fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
459fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
460fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
461ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * Applies the new configuration, returning a bitmask of the changes
462ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * between the old and new configurations.
463ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     *
464ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @param config the new configuration
465ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @return bitmask of config changes
466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
467ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    public @Config int calcConfigChanges(@Nullable Configuration config) {
468ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (config == null) {
469ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            // If there is no configuration, assume all flags have changed.
470ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            return 0xFFFFFFFF;
471ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
473ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mTmpConfig.setTo(config);
474ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        int density = config.densityDpi;
475ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
476ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            density = mMetrics.noncompatDensityDpi;
477ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
4798e8d23214a71d8813ebd3676b192924c530cb913Adam Lesinski        mDisplayAdjustments.getCompatibilityInfo().applyToConfiguration(density, mTmpConfig);
480ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette
481ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (mTmpConfig.getLocales().isEmpty()) {
482ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            mTmpConfig.setLocales(LocaleList.getDefault());
483fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
484ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        return mConfiguration.updateFrom(mTmpConfig);
485fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
486fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
488fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * All released versions of android prior to "L" used the deprecated language
492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tags, so we will need to support them for backwards compatibility.
493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Note that this conversion needs to take place *after* the call to
495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code toLanguageTag} because that will convert all the deprecated codes to
496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * the new ones, even if they're set manually.
497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static String adjustLanguageTag(String languageTag) {
499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final int separator = languageTag.indexOf('-');
500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String language;
501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String remainder;
502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (separator == -1) {
504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag;
505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = "";
506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag.substring(0, separator);
508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = languageTag.substring(separator);
509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return Locale.adjustLanguageCode(language) + remainder;
512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Call this to remove all cached loaded layout resources from the
516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Resources object.  Only intended for use with performance testing
517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tools.
518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public void flushLayoutCache() {
520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mCachedXmlBlocks) {
521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockCookies, 0);
522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockFiles, null);
523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock oldBlock = cachedXmlBlocks[i];
527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (oldBlock != null) {
528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    oldBlock.close();
529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(cachedXmlBlocks, null);
532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
53650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
53750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            int density, @Nullable Resources.Theme theme)
53850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            throws NotFoundException {
53950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // If the drawable's XML lives in our current density qualifier,
54050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // it's okay to use a scaled version from the cache. Otherwise, we
54150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // need to actually load the drawable from XML.
54250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        final boolean useCache = density == 0 || value.density == mMetrics.densityDpi;
54350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski
54450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // Pretend the requested density is actually the display density. If
54550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // the drawable returned is not the requested density, then force it
54650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // to be scaled later by dividing its density by the ratio of
54750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // requested density to actual device density. Drawables that have
54850954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        // undefined density or no density don't need to be handled here.
54950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        if (density > 0 && value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
55050954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            if (value.density == density) {
55150954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                value.density = mMetrics.densityDpi;
55250954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            } else {
55350954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                value.density = (value.density * mMetrics.densityDpi) / density;
55450954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            }
55550954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski        }
55650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski
557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (TRACE_FOR_PRELOAD) {
559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Log only framework resources
560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if ((id >>> 24) == 0x1) {
561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String name = getResourceName(id);
562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (name != null) {
563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        Log.d("PreloadDrawable", name);
564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean isColorDrawable;
569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final DrawableCache caches;
570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final long key;
571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = true;
574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mColorDrawableCache;
575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = value.data;
576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = false;
578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mDrawableCache;
579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = (((long) value.assetCookie) << 32) | value.data;
580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // First, check whether we have a cached version of this drawable
583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // that was inflated against the specified theme. Skip the cache if
584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we're currently preloading or we're not using the cache.
585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (!mPreloading && useCache) {
586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (cachedDrawable != null) {
58858857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    return cachedDrawable;
590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Next, check preloaded drawables. Preloaded drawables may contain
594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // unresolved theme attributes.
595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final Drawable.ConstantState cs;
596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedColorDrawables.get(key);
598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Drawable dr;
603ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            boolean needsNewDrawableAfterCache = false;
604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (cs != null) {
6051480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                if (TRACE_FOR_DETAILED_PRELOAD) {
6061480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    // Log only framework resources
6071480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    if (((id >>> 24) == 0x1) && (android.os.Process.myUid() != 0)) {
6081480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        final String name = getResourceName(id);
6091480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        if (name != null) {
6101480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Log.d(TAG_PRELOAD, "Hit preloaded FW drawable #"
6111480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                                    + Integer.toHexString(id) + " " + name);
6121480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                        }
6131480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    }
6141480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                }
615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = cs.newDrawable(wrapper);
616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else if (isColorDrawable) {
617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = new ColorDrawable(value.data);
618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
61950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                dr = loadDrawableForCookie(wrapper, value, id, density, null);
620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
621ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // DrawableContainer' constant state has drawables instances. In order to leave the
622ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // constant state intact in the cache, we need to create a new DrawableContainer after
623ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            // added to cache.
624ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            if (dr instanceof DrawableContainer)  {
625ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                needsNewDrawableAfterCache = true;
626ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui            }
627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Determine if the drawable has unresolved theme attributes. If it
629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // does, we'll need to apply a theme and store it in a theme-specific
630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache.
631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (canApplyTheme && theme != null) {
633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = dr.mutate();
634fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.applyTheme(theme);
635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.clearMutated();
636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // If we were able to obtain a drawable, store it in the appropriate
639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache: preload, not themed, null theme, or theme-specific. Don't
640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // pollute the cache with drawables loaded from a foreign density.
64158857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette            if (dr != null) {
642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.setChangingConfigurations(value.changingConfigurations);
64358857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                if (useCache) {
64458857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
645ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                    if (needsNewDrawableAfterCache) {
646ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        Drawable.ConstantState state = dr.getConstantState();
647ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        if (state != null) {
648ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                            dr = state.newDrawable(wrapper);
649ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                        }
650ee7e8f13ea2293e93ef9dd9f3f088186edd4864eztenghui                    }
65158857c8b2bd64272d2320f62fd860783bb671da8Alan Viverette                }
652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return dr;
655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String name;
657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = getResourceName(id);
659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e2) {
660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = "(missing name)";
661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // The target drawable might fail to load for any number of
664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // reasons, but we always want to include the resource name.
665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Since the client already expects this method to throw a
666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NotFoundException, just throw one of those.
667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException nfe = new NotFoundException("Drawable " + name
668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " with resource ID #0x" + Integer.toHexString(id), e);
669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            nfe.setStackTrace(new StackTraceElement[0]);
670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw nfe;
671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
675082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable.ConstantState cs = dr.getConstantState();
677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (cs == null) {
678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int changingConfigs = cs.getChangingConfigurations();
683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedColorDrawables.put(key, cs);
686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(
689a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette                        changingConfigs, ActivityInfo.CONFIG_LAYOUT_DIRECTION, value.resourceId, "drawable")) {
690a8a66ccf1c6c042a71817d61fc159f10c21f4844Alan Viverette                    if ((changingConfigs & ActivityInfo.CONFIG_LAYOUT_DIRECTION) == 0) {
691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // If this resource does not vary based on layout direction,
692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // we can put it in all of the preload maps.
693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[0].put(key, cs);
694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[1].put(key, cs);
695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } else {
696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // Otherwise, only in the layout dir we loaded it for.
697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mAccessLock) {
703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches.put(key, theme, cs, usesTheme);
704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
708ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private boolean verifyPreloadConfig(@Config int changingConfigurations,
709ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) {
710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // We allow preloading of resources even if they vary by font scale (which
711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // doesn't impact resource selection) or density (which we handle specially by
712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // simply turning off all preloading), as well as any other configs specified
713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // by the caller.
714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // This should never happen in production, so we should log a
723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // warning even if we're not debugging.
724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloaded " + name + " resource #0x"
725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ") that varies with configuration!!");
727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return false;
728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloading " + name + " resource #0x"
737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ")");
739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return true;
741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads a drawable from XML or resources stream.
745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
74650954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski    private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
74750954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski            int id, int density, @Nullable Resources.Theme theme) {
748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
7661480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        // For prelaod tracing.
7671480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        long startTime = 0;
7681480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        int startBitmapCount = 0;
7691480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        long startBitmapSize = 0;
7701480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        int startDrwableCount = 0;
7711480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        if (TRACE_FOR_DETAILED_PRELOAD) {
7721480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startTime = System.nanoTime();
7731480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
7741480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
7751480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            startDrwableCount = sPreloadTracingNumLoadedDrawables;
7761480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        }
7771480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
781fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
782fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable dr;
783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (file.endsWith(".xml")) {
787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser rp = loadXmlResourceParser(
788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "drawable");
78950954d2b4ea938d787ef5021d75f6bc02826607aAdam Lesinski                dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rp.close();
791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final InputStream is = mAssets.openNonAsset(
793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                is.close();
796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException rnf = new NotFoundException(
800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
8061480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        if (TRACE_FOR_DETAILED_PRELOAD) {
8071480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (((id >>> 24) == 0x1)) {
8081480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                final String name = getResourceName(id);
8091480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                if (name != null) {
8101480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final long time = System.nanoTime() - startTime;
8111480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final int loadedBitmapCount =
8121480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Bitmap.sPreloadTracingNumInstantiatedBitmaps - startBitmapCount;
8131480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final long loadedBitmapSize =
8141480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize;
8151480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final int loadedDrawables =
8161480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            sPreloadTracingNumLoadedDrawables - startDrwableCount;
8171480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8181480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    sPreloadTracingNumLoadedDrawables++;
8191480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8201480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    final boolean isRoot = (android.os.Process.myUid() == 0);
8211480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
8221480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                    Log.d(TAG_PRELOAD,
8231480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            (isRoot ? "Preloaded FW drawable #"
8241480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                                    : "Loaded non-preloaded FW drawable #")
8251480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + Integer.toHexString(id)
8261480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + name
8271480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + file
8281480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " " + dr.getClass().getCanonicalName()
8291480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " #nested_drawables= " + loadedDrawables
8301480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " #bitmaps= " + loadedBitmapCount
8311480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " total_bitmap_size= " + loadedBitmapSize
8321480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                            + " in[us] " + (time / 1000));
8331480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                }
8341480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
8351480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki        }
8361480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return dr;
838fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
84118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri     * Loads a font from XML or resources stream.
84218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri     */
84318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    @Nullable
844ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri    public Typeface loadFont(Resources wrapper, TypedValue value, int id) {
84518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        if (value.string == null) {
84618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
84718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri                    + Integer.toHexString(id) + ") is not a Font: " + value);
84818e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
84918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
85018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        final String file = value.string.toString();
8512ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka        if (!file.startsWith("res/")) {
8522ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka            return null;
8532ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka        }
8542ea169a2ecbb7e589fcef78cb1486d007a8fb867Seigo Nonaka
855b12397e57e79c5dd9e8b2cb3839f5cd30b5d515fClara Bayarri        Typeface cached = Typeface.findFromCache(mAssets, file);
856ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        if (cached != null) {
857ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            return cached;
858ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        }
85918e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
86018e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        if (DEBUG_LOAD) {
86118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file);
86218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
86318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
86418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
86518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        try {
866ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            if (file.endsWith("xml")) {
867ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri                final XmlResourceParser rp = loadXmlResourceParser(
868ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri                        file, id, value.assetCookie, "font");
869ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                final FontResourcesParser.FamilyResourceEntry familyEntry =
870ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                        FontResourcesParser.parse(rp, wrapper);
871ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                if (familyEntry == null) {
872ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                    return null;
873ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                }
874ac873c9f25d2a687c9195226b9d680f51c91fa30Seigo Nonaka                return Typeface.createFromResources(familyEntry, mAssets, file);
87518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            }
876ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            return Typeface.createFromResources(mAssets, file, value.assetCookie);
877ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        } catch (XmlPullParserException e) {
878ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            Log.e(TAG, "Failed to parse xml resource " + file, e);
879ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri        } catch (IOException e) {
880ed00bfdfae5d5cbc9e13f4e8affdece48f4c5b7fClara Bayarri            Log.e(TAG, "Failed to read xml resource " + file, e);
88118e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        } finally {
88218e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
88318e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        }
88418e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri        return null;
88518e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    }
88618e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri
88718e9f9f3778318918c44d944489cb50daaf45d1cClara Bayarri    /**
888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Given the value and id, we can get the XML filename as in value.data, based on that, we
889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * first try to load CSL from the cache. If not found, try to get from the constant state.
890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Last, parse the XML and generate the CSL.
891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
893082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            TypedValue value, int id) {
894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
898fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return complexColor;
899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = factory.newInstance(wrapper, theme);
906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor == null) {
908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
9120b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
9130b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette
914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPreloading) {
9150b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
9160b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                        0, value.resourceId, "color")) {
917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cache.put(key, theme, complexColor.getConstantState());
921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
928082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("loadComplexColor", name);
934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor;
948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from complex color resource ID #0x"
954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
969082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme)
970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("PreloadColorStateList", name);
976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null && complexColor instanceof ColorStateList) {
989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) complexColor;
990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException(
993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                "Can't find ColorStateList from drawable resource ID #0x"
994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + Integer.toHexString(id));
995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ColorStateList csl;
1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) factory.newInstance();
1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        csl = ColorStateList.valueOf(value.data);
1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "color")) {
1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.put(key, csl.getConstantState());
1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return csl;
1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * and selector tag.
1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
1029082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new UnsupportedOperationException(
1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "Can't convert to ComplexColor: type=0x" + value.type);
1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = null;
1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser parser = loadXmlResourceParser(
1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "ComplexColor");
1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final AttributeSet attrs = Xml.asAttributeSet(parser);
1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                int type;
1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                while ((type = parser.next()) != XmlPullParser.START_TAG
1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        && type != XmlPullParser.END_DOCUMENT) {
1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Seek parser to start tag.
1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (type != XmlPullParser.START_TAG) {
1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new XmlPullParserException("No start tag found");
1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = parser.getName();
1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name.equals("gradient")) {
1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                } else if (name.equals("selector")) {
1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                parser.close();
1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from ComplexColor resource ID #0x"
1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads an XML parser for the specified file.
1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param file the path for the XML file to parse
1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param id the resource identifier for the file
1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assetCookie the asset cookie for the file
1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param type the type of resource (used for logging)
1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a parser for the specified XML file
1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @throws NotFoundException if the file could not be loaded
1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
1107082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
1108082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            @NonNull String type)
1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (mCachedXmlBlocks) {
1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // First see if this block is in our cache.
1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int num = cachedXmlBlockFiles.length;
1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    for (int i = 0; i < num; i++) {
1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                && cachedXmlBlockFiles[i].equals(file)) {
1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            return cachedXmlBlocks[i].newParser();
1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Not in the cache, create a new block and put it at
1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // the next slot in the cache.
1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (block != null) {
1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        mLastCachedXmlBlockIndex = pos;
1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (oldBlock != null) {
1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            oldBlock.close();
1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockCookies[pos] = assetCookie;
1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockFiles[pos] = file;
1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlocks[pos] = block;
1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        return block.newParser();
1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException("File " + file
1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(id));
1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Start preloading of resource data using this Resources object.  Only
1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * for use by the zygote process for loading common system resources.
1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@hide}
1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public final void startPreloading() {
1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (sPreloaded) {
1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw new IllegalStateException("Resources already preloaded");
1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloaded = true;
1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = true;
1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            updateConfiguration(null, null, null);
11671480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
11681480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (TRACE_FOR_DETAILED_PRELOAD) {
11691480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                mPreloadTracingPreloadStartTime = SystemClock.uptimeMillis();
11701480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                Log.d(TAG_PRELOAD, "Preload starting");
11711480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Called by zygote when it is done preloading resources, to change back
1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * to normal Resources operation.
1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void finishPreloading() {
1180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
11811480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            if (TRACE_FOR_DETAILED_PRELOAD) {
11821480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                final long time = SystemClock.uptimeMillis() - mPreloadTracingPreloadStartTime;
11831480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki                Log.d(TAG_PRELOAD, "Preload finished in " + time + " ms");
11841480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki            }
11851480b67635cdc4c2c5e735741bf30393fd70d738Makoto Onuki
1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = false;
1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
1188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
1192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return sPreloadedDrawables[0];
1193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ThemeImpl newThemeImpl() {
1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return new ThemeImpl();
1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1199082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    /**
1200082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
1201082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     */
1202082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
1203082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        ThemeImpl impl = new ThemeImpl();
1204082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.mKey.setTo(key);
1205082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.rebase();
1206082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        return impl;
1207082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    }
1208082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski
1209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public class ThemeImpl {
1210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Unique key for the series of styles applied to this theme.
1212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
1214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @SuppressWarnings("hiding")
1216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final AssetManager mAssets;
1217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final long mTheme;
1218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Resource identifier for the theme.
1221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private int mThemeResId = 0;
1223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ ThemeImpl() {
1225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets = ResourcesImpl.this.mAssets;
1226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTheme = mAssets.createTheme();
1227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @Override
1230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        protected void finalize() throws Throwable {
1231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            super.finalize();
1232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.releaseTheme(mTheme);
1233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ Resources.ThemeKey getKey() {
1236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mKey;
1237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ long getNativeTheme() {
1240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mTheme;
1241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ int getAppliedStyleResId() {
1244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mThemeResId;
1245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void applyStyle(int resId, boolean force) {
1248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyThemeStyle(mTheme, resId, force);
1250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mThemeResId = resId;
1252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mKey.append(resId, force);
1253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void setTo(ThemeImpl other) {
1257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (other.mKey) {
1259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.copyTheme(mTheme, other.mTheme);
1260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mThemeResId = other.mThemeResId;
1262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mKey.setTo(other.getKey());
1263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
1269082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                AttributeSet set,
1270082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleableRes int[] attrs,
1271082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @AttrRes int defStyleAttr,
1272082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleRes int defStyleRes) {
1273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // XXX note that for now we only work with compiled XML files.
1278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // To support generic XML files we will need to manually parse
1279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // out the attributes from the XML file (applying type information
1280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // contained in the resources and such).
1281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        parser != null ? parser.mParseState : 0,
1284f32adf447511d54c2aa0948d3c1ef44d461538acJohn Reck                        attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
1285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = parser;
1287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
1294082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] values,
1295082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] attrs) {
1296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (values == null || len != values.length) {
1299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new IllegalArgumentException(
1300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            "Base attribute values must the same length as attrs");
1301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = null;
1307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int[] getAllAttributes() {
1318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.getStyleAttributes(getAppliedStyleResId());
1319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1321ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        @Config int getChangingConfigurations() {
1322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
13239ad386b37c4c4ebe1176caa8eeab131387fc93edAlan Viverette                final @NativeConfig int nativeChangingConfig =
1324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        AssetManager.getThemeChangingConfigurations(mTheme);
1325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        public void dump(int priority, String tag, String prefix) {
1330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String[] getTheme() {
1336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int N = mKey.mCount;
1338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String[] themes = new String[N * 2];
1339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[j];
1341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean forced = mKey.mForce[j];
1342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    try {
1343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = getResourceName(resId);
1344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } catch (NotFoundException e) {
1345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = Integer.toHexString(i);
1346fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1347fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    themes[i + 1] = forced ? "forced" : "not forced";
1348fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1349fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return themes;
1350fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1351fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1352fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1353fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1354fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Rebases the theme against the parent Resource object's current
1355fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * configuration by re-applying the styles passed to
1356fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * {@link #applyStyle(int, boolean)}.
1357fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1358fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void rebase() {
1359fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1360fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.clearTheme(mTheme);
1361fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1362fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Reapply the same styles in the same order.
1363fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0; i < mKey.mCount; i++) {
1364fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[i];
1365fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean force = mKey.mForce[i];
1366fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.applyThemeStyle(mTheme, resId, force);
1367fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1368fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1369fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1370fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1371fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski}
1372