ResourcesImpl.java revision 4ece3d6bb18a609afcd0e82f0340b7d36ba24eea
1fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/*
2fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Copyright (C) 2016 The Android Open Source Project
3fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
4fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * use this file except in compliance with the License. You may obtain a copy of
6fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License at
7fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
8fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0
9fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
10fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * License for the specific language governing permissions and limitations under
14fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License.
15fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
16fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipackage android.content.res;
17fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
18ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport org.xmlpull.v1.XmlPullParser;
19ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport org.xmlpull.v1.XmlPullParserException;
20ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette
21fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.Animator;
22fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.StateListAnimator;
23fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AnyRes;
24fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AttrRes;
25fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.NonNull;
26fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.Nullable;
27fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.PluralsRes;
28fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.RawRes;
29fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleRes;
30fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleableRes;
31fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.pm.ActivityInfo;
32ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viveretteimport android.content.pm.ActivityInfo.Config;
33fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException;
34fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable;
35fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable;
36fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules;
37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build;
3823cbe85610f780134cc77dd4a54732a22ed6e86eYohei Yukawaimport android.os.LocaleList;
39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace;
40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet;
41fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics;
42fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log;
43fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray;
44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog;
45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue;
46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml;
474ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.Display;
484ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinskiimport android.view.DisplayAdjustments;
49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream;
51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays;
52fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale;
53fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
54fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/**
55082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches
56082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it.
57082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
58082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change
59082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying
60082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created.
61082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide
63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl {
65fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static final String TAG = "Resources";
66fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
67fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_LOAD = false;
68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_CONFIG = false;
69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_PRELOAD = false;
70fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_MISS_PRELOAD = false;
71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
72ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigJavaToNative(
73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int ID_OTHER = 0x01000004;
76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final Object sSync = new Object();
78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static boolean sPreloaded;
80fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean mPreloading;
81fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
82fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Information about preloaded resources.  Note that they are not
83fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // protected by a lock, because while preloading in zygote we are all
84fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // single-threaded, and after that these are immutable.
85fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
86fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            = new LongSparseArray<>();
88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloadedComplexColors = new LongSparseArray<>();
90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Lock object used to protect access to caches and configuration. */
92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Object mAccessLock = new Object();
93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // These are protected by mAccessLock.
95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mTmpConfig = new Configuration();
96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mDrawableCache = new DrawableCache();
97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mColorDrawableCache = new DrawableCache();
98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Size of the cyclical cache used to map XML files to blocks. */
106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int XML_BLOCK_CACHE_SIZE = 4;
107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Cyclical cache used for recently-accessed XML files.
109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private int mLastCachedXmlBlockIndex = -1;
110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final AssetManager mAssets;
1164ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    private final DisplayMetrics mMetrics = new DisplayMetrics();
1174ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules mPluralRule;
120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mConfiguration = new Configuration();
122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static {
125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables = new LongSparseArray[2];
126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[0] = new LongSparseArray<>();
127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[1] = new LongSparseArray<>();
128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo.
132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assets Previously created AssetManager.
134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param metrics Current display metrics to consider when
135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *                selecting/computing resource values.
136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param config Desired device configuration to consider when
137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *               selecting/computing resource values (optional).
138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param compatInfo this resource's compatibility info. Must not be null.
139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1404ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
1414ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski            @Nullable Configuration config, @NonNull CompatibilityInfo compatInfo) {
1424ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        this(assets, metrics, config, compatInfo, null);
1434ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    }
1444ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski
1454ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    /**
1464ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo and assigns a static overrideConfig
1474ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * that is reported with getDisplayAdjustments(). This is used for updating the Display
1484ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * when a new ResourcesImpl is created due to multi-window configuration changes.
1494ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     *
1504ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * @param assets Previously created AssetManager.
1514ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * @param metrics Current display metrics to consider when selecting/computing resource values.
1524ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * @param fullConfig Desired device configuration to consider when selecting/computing
1534ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * resource values.
1544ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * @param compatInfo this resource's compatibility info. Must not be null.
1554ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * @param overrideConfig the overrides specific to this ResourcesImpl object. They must already
1564ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * be applied to the fullConfig and are mainly maintained in order to return a valid
1574ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     * DisplayAdjustments object during configuration changes.
1584ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski     */
1594ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public ResourcesImpl(@NonNull AssetManager assets, @Nullable DisplayMetrics metrics,
1604ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski            @Nullable Configuration fullConfig, @NonNull CompatibilityInfo compatInfo,
1614ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski            @Nullable Configuration overrideConfig) {
162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets = assets;
163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mMetrics.setToDefaults();
1644ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        mDisplayAdjustments.setCompatibilityInfo(compatInfo);
1654ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        if (overrideConfig != null) {
1664ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski            mDisplayAdjustments.setConfiguration(overrideConfig);
1674ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        }
1684ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        updateConfiguration(fullConfig, metrics, compatInfo);
169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets.ensureStringBlocks();
170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1724ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    public DisplayAdjustments getDisplayAdjustments() {
1734ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski        return mDisplayAdjustments;
1744ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski    }
1754ece3d6bb18a609afcd0e82f0340b7d36ba24eeaAdam Lesinski
176082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public AssetManager getAssets() {
177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets;
178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    DisplayMetrics getDisplayMetrics() {
181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mMetrics;
184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration getConfiguration() {
187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mConfiguration;
188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration[] getSizeConfigurations() {
191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getSizeConfigurations();
192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CompatibilityInfo getCompatibilityInfo() {
195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mCompatibilityInfo;
196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules getPluralRule() {
199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule == null) {
201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mPluralRule;
204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, 0, 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 getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
217082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean resolveRefs) throws NotFoundException {
218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(String name, TypedValue outValue, boolean resolveRefs)
226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int id = getIdentifier(name, "string", null);
228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            getValue(id, outValue, resolveRefs);
230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("String resource name " + name);
233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    int getIdentifier(String name, String defType, String defPackage) {
236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (name == null) {
237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NullPointerException("name is null");
238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return Integer.parseInt(name);
241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Ignore
243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getResourceIdentifier(name, defType, defPackage);
245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceName(@AnyRes int resid) throws NotFoundException {
249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceName(resid);
250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourcePackageName(resid);
258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceTypeName(resid);
266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceEntryName(resid);
274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        PluralRules rule = getPluralRule();
282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        CharSequence res = mAssets.getResourceBagText(id,
283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                attrForQuantityCode(rule.select(quantity)));
284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        res = mAssets.getResourceBagText(id, ID_OTHER);
288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " quantity=" + quantity
293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " item=" + rule.select(quantity));
294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static int attrForQuantityCode(String quantityCode) {
297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        switch (quantityCode) {
298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ZERO: return 0x01000005;
299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ONE:  return 0x01000006;
300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_TWO:  return 0x01000007;
301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_FEW:  return 0x01000008;
302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_MANY: return 0x01000009;
303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            default:                       return ID_OTHER;
304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, tempValue, true);
311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + "resource ID #0x" + Integer.toHexString(id), e);
316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, value, true);
322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.ACCESS_STREAMING);
325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
326f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            // Note: value.string might be null
327f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate            NotFoundException rnf = new NotFoundException("File "
328f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + (value.string == null ? "(null)" : value.string.toString())
329f135b271bfaa5a23f3af5a15ce59fd4ffb44a6beChristopher Tate                    + " from drawable resource ID #0x" + Integer.toHexString(id));
330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAnimatorCache;
337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mStateListAnimatorCache;
341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
343082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
344082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                                    CompatibilityInfo compat) {
345991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
346991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        try {
347991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (mAccessLock) {
348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (false) {
349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": old config is "
350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + mConfiguration + " old compat is " + mCompatibilityInfo);
351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": new config is "
352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + config + " new compat is " + compat);
353991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
354991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (compat != null) {
355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mCompatibilityInfo = compat;
356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (metrics != null) {
358991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.setTo(metrics);
359991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // NOTE: We should re-arrange this code to create a Display
361991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the CompatibilityInfo that is used everywhere we deal
362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the display in relation to this app, rather than
363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // doing the conversion here.  This impl should be okay because
364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // we make sure to return a compatible display in the places
365991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // where there are public APIs to retrieve the display...  but
366b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // it would be cleaner and more maintainable to just be
367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // consistently dealing with a compatible display everywhere in
368991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // the framework.
369991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
370991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
371991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final @Config int configChanges = calcConfigChanges(config);
372991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
373b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                // If even after the update there are no Locales set, grab the default locales.
374991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                LocaleList locales = mConfiguration.getLocales();
375991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (locales.isEmpty()) {
376b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    locales = LocaleList.getDefault();
377991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mConfiguration.setLocales(locales);
378991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
379b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
380b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
381b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    if (locales.size() > 1) {
382b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // The LocaleList has changed. We must query the AssetManager's available
383b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        // Locales and figure out the best matching Locale in the new LocaleList.
384b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        String[] availableLocales = mAssets.getNonSystemLocales();
385b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
386b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            // No app defined locales, so grab the system locales.
387b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            availableLocales = mAssets.getLocales();
388b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
389b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                availableLocales = null;
390b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
391b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
392b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
393b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        if (availableLocales != null) {
394b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
395b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                    availableLocales);
396b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            if (bestLocale != null && bestLocale != locales.get(0)) {
397b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                                mConfiguration.setLocales(new LocaleList(bestLocale, locales));
398b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                            }
399b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        }
400b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                    }
401b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                }
402b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski
403991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
404991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.densityDpi = mConfiguration.densityDpi;
405991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.density =
406991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
407991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
408991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
409991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
410991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int width, height;
411991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mMetrics.widthPixels >= mMetrics.heightPixels) {
412991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.widthPixels;
413991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.heightPixels;
414991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
415991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
416991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.heightPixels;
417991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
418991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.widthPixels;
419991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
420991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
421991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int keyboardHidden;
422991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
423991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        && mConfiguration.hardKeyboardHidden
424991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        == Configuration.HARDKEYBOARDHIDDEN_YES) {
425991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
426991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
427991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = mConfiguration.keyboardHidden;
428991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
429991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
430991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
431b61e405397200f78b1c652143cba7c751df05a00Adam Lesinski                        adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
432991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.orientation,
433991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.touchscreen,
434991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.densityDpi, mConfiguration.keyboard,
435991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        keyboardHidden, mConfiguration.navigation, width, height,
436991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.smallestScreenWidthDp,
437991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
438991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenLayout, mConfiguration.uiMode,
439991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        Build.VERSION.RESOURCES_SDK_INT);
440991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
441991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (DEBUG_CONFIG) {
442991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": final config is "
443991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + mConfiguration + " final compat is " + mCompatibilityInfo);
444991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
445991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
446991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mDrawableCache.onConfigurationChange(configChanges);
447991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mColorDrawableCache.onConfigurationChange(configChanges);
448991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mComplexColorCache.onConfigurationChange(configChanges);
449991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAnimatorCache.onConfigurationChange(configChanges);
450991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mStateListAnimatorCache.onConfigurationChange(configChanges);
451991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
452991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                flushLayoutCache();
453fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
454991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (sSync) {
455991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mPluralRule != null) {
456991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
457991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
459991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        } finally {
460991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
462fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
463fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
464fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
465ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * Applies the new configuration, returning a bitmask of the changes
466ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * between the old and new configurations.
467ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     *
468ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @param config the new configuration
469ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @return bitmask of config changes
470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
471ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    public @Config int calcConfigChanges(@Nullable Configuration config) {
472ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (config == null) {
473ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            // If there is no configuration, assume all flags have changed.
474ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            return 0xFFFFFFFF;
475ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
476fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
477ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mTmpConfig.setTo(config);
478ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        int density = config.densityDpi;
479ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
480ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            density = mMetrics.noncompatDensityDpi;
481ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
483ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
484ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette
485ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (mTmpConfig.getLocales().isEmpty()) {
486ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            mTmpConfig.setLocales(LocaleList.getDefault());
487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
488ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        return mConfiguration.updateFrom(mTmpConfig);
489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * All released versions of android prior to "L" used the deprecated language
496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tags, so we will need to support them for backwards compatibility.
497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Note that this conversion needs to take place *after* the call to
499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code toLanguageTag} because that will convert all the deprecated codes to
500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * the new ones, even if they're set manually.
501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static String adjustLanguageTag(String languageTag) {
503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final int separator = languageTag.indexOf('-');
504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String language;
505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String remainder;
506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (separator == -1) {
508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag;
509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = "";
510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag.substring(0, separator);
512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = languageTag.substring(separator);
513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return Locale.adjustLanguageCode(language) + remainder;
516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Call this to remove all cached loaded layout resources from the
520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Resources object.  Only intended for use with performance testing
521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tools.
522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public void flushLayoutCache() {
524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mCachedXmlBlocks) {
525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockCookies, 0);
526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockFiles, null);
527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock oldBlock = cachedXmlBlocks[i];
531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (oldBlock != null) {
532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    oldBlock.close();
533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(cachedXmlBlocks, null);
536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
541082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean useCache) throws NotFoundException {
542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (TRACE_FOR_PRELOAD) {
544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Log only framework resources
545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if ((id >>> 24) == 0x1) {
546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String name = getResourceName(id);
547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (name != null) {
548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        Log.d("PreloadDrawable", name);
549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean isColorDrawable;
554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final DrawableCache caches;
555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final long key;
556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = true;
559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mColorDrawableCache;
560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = value.data;
561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = false;
563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mDrawableCache;
564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = (((long) value.assetCookie) << 32) | value.data;
565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // First, check whether we have a cached version of this drawable
568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // that was inflated against the specified theme. Skip the cache if
569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we're currently preloading or we're not using the cache.
570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (!mPreloading && useCache) {
571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (cachedDrawable != null) {
573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    return cachedDrawable;
574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Next, check preloaded drawables. Preloaded drawables may contain
578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // unresolved theme attributes.
579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final Drawable.ConstantState cs;
580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedColorDrawables.get(key);
582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Drawable dr;
587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (cs != null) {
588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = cs.newDrawable(wrapper);
589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else if (isColorDrawable) {
590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = new ColorDrawable(value.data);
591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = loadDrawableForCookie(wrapper, value, id, null);
593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Determine if the drawable has unresolved theme attributes. If it
596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // does, we'll need to apply a theme and store it in a theme-specific
597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache.
598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (canApplyTheme && theme != null) {
600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = dr.mutate();
601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.applyTheme(theme);
602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.clearMutated();
603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // If we were able to obtain a drawable, store it in the appropriate
606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache: preload, not themed, null theme, or theme-specific. Don't
607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // pollute the cache with drawables loaded from a foreign density.
608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (dr != null && useCache) {
609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.setChangingConfigurations(value.changingConfigurations);
610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return dr;
614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String name;
616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = getResourceName(id);
618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e2) {
619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = "(missing name)";
620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // The target drawable might fail to load for any number of
623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // reasons, but we always want to include the resource name.
624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Since the client already expects this method to throw a
625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NotFoundException, just throw one of those.
626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException nfe = new NotFoundException("Drawable " + name
627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " with resource ID #0x" + Integer.toHexString(id), e);
628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            nfe.setStackTrace(new StackTraceElement[0]);
629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw nfe;
630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
634082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable.ConstantState cs = dr.getConstantState();
636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (cs == null) {
637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int changingConfigs = cs.getChangingConfigurations();
642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedColorDrawables.put(key, cs);
645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(
648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // If this resource does not vary based on layout direction,
651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // we can put it in all of the preload maps.
652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[0].put(key, cs);
653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[1].put(key, cs);
654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } else {
655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // Otherwise, only in the layout dir we loaded it for.
656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mAccessLock) {
662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches.put(key, theme, cs, usesTheme);
663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
667ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private boolean verifyPreloadConfig(@Config int changingConfigurations,
668ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) {
669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // We allow preloading of resources even if they vary by font scale (which
670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // doesn't impact resource selection) or density (which we handle specially by
671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // simply turning off all preloading), as well as any other configs specified
672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // by the caller.
673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // This should never happen in production, so we should log a
682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // warning even if we're not debugging.
683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloaded " + name + " resource #0x"
684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ") that varies with configuration!!");
686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return false;
687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloading " + name + " resource #0x"
696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ")");
698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return true;
700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads a drawable from XML or resources stream.
704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
706082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
724fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable dr;
730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (file.endsWith(".xml")) {
734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser rp = loadXmlResourceParser(
735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "drawable");
736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromXml(wrapper, rp, theme);
737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rp.close();
738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final InputStream is = mAssets.openNonAsset(
740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                is.close();
743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException rnf = new NotFoundException(
747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return dr;
754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Given the value and id, we can get the XML filename as in value.data, based on that, we
758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * first try to load CSL from the cache. If not found, try to get from the constant state.
759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Last, parse the XML and generate the CSL.
760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
762082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            TypedValue value, int id) {
763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return complexColor;
768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = factory.newInstance(wrapper, theme);
775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor == null) {
777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
7810b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
7820b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette
783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPreloading) {
7840b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
7850b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                        0, value.resourceId, "color")) {
786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cache.put(key, theme, complexColor.getConstantState());
790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
797082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("loadComplexColor", name);
803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor;
817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from complex color resource ID #0x"
823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
833fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
838082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme)
839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("PreloadColorStateList", name);
845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null && complexColor instanceof ColorStateList) {
858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) complexColor;
859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException(
862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                "Can't find ColorStateList from drawable resource ID #0x"
863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + Integer.toHexString(id));
864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ColorStateList csl;
869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) factory.newInstance();
873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        csl = ColorStateList.valueOf(value.data);
876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
877fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "color")) {
880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.put(key, csl.getConstantState());
881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return csl;
885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * and selector tag.
893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
898082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new UnsupportedOperationException(
901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "Can't convert to ComplexColor: type=0x" + value.type);
902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = null;
922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser parser = loadXmlResourceParser(
927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "ComplexColor");
928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final AttributeSet attrs = Xml.asAttributeSet(parser);
930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                int type;
931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                while ((type = parser.next()) != XmlPullParser.START_TAG
932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        && type != XmlPullParser.END_DOCUMENT) {
933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Seek parser to start tag.
934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (type != XmlPullParser.START_TAG) {
936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new XmlPullParserException("No start tag found");
937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = parser.getName();
940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name.equals("gradient")) {
941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                } else if (name.equals("selector")) {
943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                parser.close();
946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from ComplexColor resource ID #0x"
950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads an XML parser for the specified file.
967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param file the path for the XML file to parse
969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param id the resource identifier for the file
970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assetCookie the asset cookie for the file
971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param type the type of resource (used for logging)
972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a parser for the specified XML file
973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @throws NotFoundException if the file could not be loaded
974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
976082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
977082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            @NonNull String type)
978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (mCachedXmlBlocks) {
982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // First see if this block is in our cache.
986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int num = cachedXmlBlockFiles.length;
987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    for (int i = 0; i < num; i++) {
988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                && cachedXmlBlockFiles[i].equals(file)) {
990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            return cachedXmlBlocks[i].newParser();
991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Not in the cache, create a new block and put it at
995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // the next slot in the cache.
996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (block != null) {
998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        mLastCachedXmlBlockIndex = pos;
1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (oldBlock != null) {
1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            oldBlock.close();
1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockCookies[pos] = assetCookie;
1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockFiles[pos] = file;
1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlocks[pos] = block;
1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        return block.newParser();
1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException("File " + file
1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(id));
1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Start preloading of resource data using this Resources object.  Only
1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * for use by the zygote process for loading common system resources.
1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@hide}
1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public final void startPreloading() {
1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (sPreloaded) {
1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw new IllegalStateException("Resources already preloaded");
1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloaded = true;
1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = true;
1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            updateConfiguration(null, null, null);
1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Called by zygote when it is done preloading resources, to change back
1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * to normal Resources operation.
1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void finishPreloading() {
1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = false;
1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return sPreloadedDrawables[0];
1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ThemeImpl newThemeImpl() {
1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return new ThemeImpl();
1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1058082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    /**
1059082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
1060082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     */
1061082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
1062082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        ThemeImpl impl = new ThemeImpl();
1063082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.mKey.setTo(key);
1064082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.rebase();
1065082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        return impl;
1066082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    }
1067082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski
1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public class ThemeImpl {
1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Unique key for the series of styles applied to this theme.
1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @SuppressWarnings("hiding")
1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final AssetManager mAssets;
1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final long mTheme;
1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Resource identifier for the theme.
1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private int mThemeResId = 0;
1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ ThemeImpl() {
1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets = ResourcesImpl.this.mAssets;
1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTheme = mAssets.createTheme();
1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @Override
1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        protected void finalize() throws Throwable {
1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            super.finalize();
1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.releaseTheme(mTheme);
1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ Resources.ThemeKey getKey() {
1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mKey;
1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ long getNativeTheme() {
1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mTheme;
1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ int getAppliedStyleResId() {
1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mThemeResId;
1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void applyStyle(int resId, boolean force) {
1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyThemeStyle(mTheme, resId, force);
1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mThemeResId = resId;
1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mKey.append(resId, force);
1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void setTo(ThemeImpl other) {
1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (other.mKey) {
1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.copyTheme(mTheme, other.mTheme);
1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mThemeResId = other.mThemeResId;
1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mKey.setTo(other.getKey());
1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
1128082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                AttributeSet set,
1129082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleableRes int[] attrs,
1130082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @AttrRes int defStyleAttr,
1131082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleRes int defStyleRes) {
1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // XXX note that for now we only work with compiled XML files.
1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // To support generic XML files we will need to manually parse
1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // out the attributes from the XML file (applying type information
1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // contained in the resources and such).
1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        parser != null ? parser.mParseState : 0,
1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        attrs, array.mData, array.mIndices);
1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = parser;
1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
1153082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] values,
1154082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] attrs) {
1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (values == null || len != values.length) {
1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new IllegalArgumentException(
1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            "Base attribute values must the same length as attrs");
1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = null;
1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int[] getAllAttributes() {
1177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.getStyleAttributes(getAppliedStyleResId());
1178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1180ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        @Config int getChangingConfigurations() {
1181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int nativeChangingConfig =
1183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        AssetManager.getThemeChangingConfigurations(mTheme);
1184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        public void dump(int priority, String tag, String prefix) {
1189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String[] getTheme() {
1195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int N = mKey.mCount;
1197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String[] themes = new String[N * 2];
1198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[j];
1200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean forced = mKey.mForce[j];
1201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    try {
1202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = getResourceName(resId);
1203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } catch (NotFoundException e) {
1204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = Integer.toHexString(i);
1205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    themes[i + 1] = forced ? "forced" : "not forced";
1207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return themes;
1209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Rebases the theme against the parent Resource object's current
1214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * configuration by re-applying the styles passed to
1215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * {@link #applyStyle(int, boolean)}.
1216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void rebase() {
1218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.clearTheme(mTheme);
1220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Reapply the same styles in the same order.
1222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0; i < mKey.mCount; i++) {
1223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[i];
1224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean force = mKey.mForce[i];
1225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.applyThemeStyle(mTheme, resId, force);
1226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski}
1231