ResourcesImpl.java revision 991357fe25b3addabf85b871df3f4098fc4b833b
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;
38fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace;
39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet;
40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics;
41fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LocaleList;
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;
47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream;
49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays;
50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale;
51fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
52fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/**
53082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches
54082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it.
55082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
56082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change
57082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying
58082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created.
59082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide
61fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl {
63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static final String TAG = "Resources";
64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
65fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_LOAD = false;
66fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_CONFIG = false;
67fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_PRELOAD = false;
68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_MISS_PRELOAD = false;
69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
70ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigJavaToNative(
71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int ID_OTHER = 0x01000004;
74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final Object sSync = new Object();
76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static boolean sPreloaded;
78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean mPreloading;
79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
80fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Information about preloaded resources.  Note that they are not
81fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // protected by a lock, because while preloading in zygote we are all
82fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // single-threaded, and after that these are immutable.
83fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
84fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
85fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            = new LongSparseArray<>();
86fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloadedComplexColors = new LongSparseArray<>();
88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Lock object used to protect access to caches and configuration. */
90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Object mAccessLock = new Object();
91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // These are protected by mAccessLock.
93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mTmpConfig = new Configuration();
94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mDrawableCache = new DrawableCache();
95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mColorDrawableCache = new DrawableCache();
96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Size of the cyclical cache used to map XML files to blocks. */
104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int XML_BLOCK_CACHE_SIZE = 4;
105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Cyclical cache used for recently-accessed XML files.
107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private int mLastCachedXmlBlockIndex = -1;
108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final AssetManager mAssets;
114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final DisplayMetrics mMetrics = new DisplayMetrics();
115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules mPluralRule;
117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mConfiguration = new Configuration();
119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static {
122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables = new LongSparseArray[2];
123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[0] = new LongSparseArray<>();
124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[1] = new LongSparseArray<>();
125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo.
129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assets Previously created AssetManager.
131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param metrics Current display metrics to consider when
132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *                selecting/computing resource values.
133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param config Desired device configuration to consider when
134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *               selecting/computing resource values (optional).
135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param compatInfo this resource's compatibility info. Must not be null.
136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
138082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            CompatibilityInfo compatInfo) {
139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets = assets;
140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mMetrics.setToDefaults();
141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        updateConfiguration(config, metrics, compatInfo);
142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets.ensureStringBlocks();
143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
145082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public AssetManager getAssets() {
146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets;
147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    DisplayMetrics getDisplayMetrics() {
150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mMetrics;
153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration getConfiguration() {
156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mConfiguration;
157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration[] getSizeConfigurations() {
160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getSizeConfigurations();
161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CompatibilityInfo getCompatibilityInfo() {
164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mCompatibilityInfo;
165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules getPluralRule() {
168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule == null) {
170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mPluralRule;
173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
184fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
186082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean resolveRefs) throws NotFoundException {
187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(String name, TypedValue outValue, boolean resolveRefs)
195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int id = getIdentifier(name, "string", null);
197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            getValue(id, outValue, resolveRefs);
199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("String resource name " + name);
202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    int getIdentifier(String name, String defType, String defPackage) {
205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (name == null) {
206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NullPointerException("name is null");
207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return Integer.parseInt(name);
210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Ignore
212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getResourceIdentifier(name, defType, defPackage);
214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceName(@AnyRes int resid) throws NotFoundException {
218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceName(resid);
219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourcePackageName(resid);
227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceTypeName(resid);
235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceEntryName(resid);
243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        PluralRules rule = getPluralRule();
251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        CharSequence res = mAssets.getResourceBagText(id,
252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                attrForQuantityCode(rule.select(quantity)));
253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        res = mAssets.getResourceBagText(id, ID_OTHER);
257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " quantity=" + quantity
262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " item=" + rule.select(quantity));
263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static int attrForQuantityCode(String quantityCode) {
266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        switch (quantityCode) {
267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ZERO: return 0x01000005;
268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ONE:  return 0x01000006;
269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_TWO:  return 0x01000007;
270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_FEW:  return 0x01000008;
271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_MANY: return 0x01000009;
272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            default:                       return ID_OTHER;
273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, tempValue, true);
280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + "resource ID #0x" + Integer.toHexString(id), e);
285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, value, true);
291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.ACCESS_STREAMING);
294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    " from drawable resource ID #0x" + Integer.toHexString(id));
297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAnimatorCache;
304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mStateListAnimatorCache;
308fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
309fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
310082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
311082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                                    CompatibilityInfo compat) {
312991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesImpl#updateConfiguration");
313991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        try {
314991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (mAccessLock) {
315991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (false) {
316991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": old config is "
317991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + mConfiguration + " old compat is " + mCompatibilityInfo);
318991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": new config is "
319991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + config + " new compat is " + compat);
320991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
321991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (compat != null) {
322991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mCompatibilityInfo = compat;
323991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
324991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (metrics != null) {
325991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.setTo(metrics);
326991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
327991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // NOTE: We should re-arrange this code to create a Display
328991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the CompatibilityInfo that is used everywhere we deal
329991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // with the display in relation to this app, rather than
330991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // doing the conversion here.  This impl should be okay because
331991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // we make sure to return a compatible display in the places
332991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // where there are public APIs to retrieve the display...  but
333991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // it would be cleaner and more maintainble to just be
334991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // consistently dealing with a compatible display everywhere in
335991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                // the framework.
336991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
337991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
338991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final @Config int configChanges = calcConfigChanges(config);
339991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
340991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                LocaleList locales = mConfiguration.getLocales();
341991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (locales.isEmpty()) {
342991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    locales = LocaleList.getAdjustedDefault();
343991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mConfiguration.setLocales(locales);
344991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
345991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
346991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.densityDpi = mConfiguration.densityDpi;
347991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mMetrics.density =
348991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
349991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
350991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
351991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
352991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int width, height;
353991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mMetrics.widthPixels >= mMetrics.heightPixels) {
354991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.widthPixels;
355991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.heightPixels;
356991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
357991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
358991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    width = mMetrics.heightPixels;
359991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    //noinspection SuspiciousNameCombination
360991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    height = mMetrics.widthPixels;
361991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
362991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
363991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                final int keyboardHidden;
364991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
365991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        && mConfiguration.hardKeyboardHidden
366991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        == Configuration.HARDKEYBOARDHIDDEN_YES) {
367991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
368991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                } else {
369991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    keyboardHidden = mConfiguration.keyboardHidden;
370991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
371991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
372991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
373991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        adjustLanguageTag(locales.get(0).toLanguageTag()),
374991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.orientation,
375991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.touchscreen,
376991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.densityDpi, mConfiguration.keyboard,
377991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        keyboardHidden, mConfiguration.navigation, width, height,
378991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.smallestScreenWidthDp,
379991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
380991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        mConfiguration.screenLayout, mConfiguration.uiMode,
381991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                        Build.VERSION.RESOURCES_SDK_INT);
382991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
383991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (DEBUG_CONFIG) {
384991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    Slog.i(TAG, "**** Updating config of " + this + ": final config is "
385991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                            + mConfiguration + " final compat is " + mCompatibilityInfo);
386991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
387991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
388991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mDrawableCache.onConfigurationChange(configChanges);
389991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mColorDrawableCache.onConfigurationChange(configChanges);
390991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mComplexColorCache.onConfigurationChange(configChanges);
391991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mAnimatorCache.onConfigurationChange(configChanges);
392991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                mStateListAnimatorCache.onConfigurationChange(configChanges);
393991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski
394991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                flushLayoutCache();
395fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
396991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            synchronized (sSync) {
397991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                if (mPluralRule != null) {
398991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                    mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
399991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski                }
400fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
401991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski        } finally {
402991357fe25b3addabf85b871df3f4098fc4b833bAdam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
403fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
404fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
405fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
406fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
407ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * Applies the new configuration, returning a bitmask of the changes
408ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * between the old and new configurations.
409ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     *
410ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @param config the new configuration
411ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette     * @return bitmask of config changes
412fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
413ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    public @Config int calcConfigChanges(@Nullable Configuration config) {
414ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (config == null) {
415ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            // If there is no configuration, assume all flags have changed.
416ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            return 0xFFFFFFFF;
417ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
418fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
419ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mTmpConfig.setTo(config);
420ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        int density = config.densityDpi;
421ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
422ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            density = mMetrics.noncompatDensityDpi;
423ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        }
424fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
425ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
426ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette
427ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        if (mTmpConfig.getLocales().isEmpty()) {
428ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            mTmpConfig.setLocales(LocaleList.getDefault());
429fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
430ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        return mConfiguration.updateFrom(mTmpConfig);
431fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
432fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
433fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
434fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
435fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
436fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
437fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * All released versions of android prior to "L" used the deprecated language
438fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tags, so we will need to support them for backwards compatibility.
439fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
440fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Note that this conversion needs to take place *after* the call to
441fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code toLanguageTag} because that will convert all the deprecated codes to
442fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * the new ones, even if they're set manually.
443fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
444fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static String adjustLanguageTag(String languageTag) {
445fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final int separator = languageTag.indexOf('-');
446fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String language;
447fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String remainder;
448fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (separator == -1) {
450fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag;
451fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = "";
452fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
453fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag.substring(0, separator);
454fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = languageTag.substring(separator);
455fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
456fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
457fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return Locale.adjustLanguageCode(language) + remainder;
458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
459fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
460fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Call this to remove all cached loaded layout resources from the
462fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Resources object.  Only intended for use with performance testing
463fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tools.
464fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
465fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public void flushLayoutCache() {
466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mCachedXmlBlocks) {
467fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockCookies, 0);
468fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockFiles, null);
469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
470fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock oldBlock = cachedXmlBlocks[i];
473fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (oldBlock != null) {
474fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    oldBlock.close();
475fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
476fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
477fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(cachedXmlBlocks, null);
478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
479fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
480fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
481fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
483082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean useCache) throws NotFoundException {
484fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
485fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (TRACE_FOR_PRELOAD) {
486fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Log only framework resources
487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if ((id >>> 24) == 0x1) {
488fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String name = getResourceName(id);
489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (name != null) {
490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        Log.d("PreloadDrawable", name);
491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean isColorDrawable;
496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final DrawableCache caches;
497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final long key;
498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = true;
501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mColorDrawableCache;
502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = value.data;
503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = false;
505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mDrawableCache;
506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = (((long) value.assetCookie) << 32) | value.data;
507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // First, check whether we have a cached version of this drawable
510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // that was inflated against the specified theme. Skip the cache if
511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we're currently preloading or we're not using the cache.
512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (!mPreloading && useCache) {
513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (cachedDrawable != null) {
515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    return cachedDrawable;
516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Next, check preloaded drawables. Preloaded drawables may contain
520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // unresolved theme attributes.
521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final Drawable.ConstantState cs;
522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedColorDrawables.get(key);
524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Drawable dr;
529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (cs != null) {
530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = cs.newDrawable(wrapper);
531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else if (isColorDrawable) {
532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = new ColorDrawable(value.data);
533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = loadDrawableForCookie(wrapper, value, id, null);
535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Determine if the drawable has unresolved theme attributes. If it
538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // does, we'll need to apply a theme and store it in a theme-specific
539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache.
540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (canApplyTheme && theme != null) {
542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = dr.mutate();
543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.applyTheme(theme);
544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.clearMutated();
545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // If we were able to obtain a drawable, store it in the appropriate
548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache: preload, not themed, null theme, or theme-specific. Don't
549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // pollute the cache with drawables loaded from a foreign density.
550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (dr != null && useCache) {
551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.setChangingConfigurations(value.changingConfigurations);
552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return dr;
556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String name;
558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = getResourceName(id);
560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e2) {
561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = "(missing name)";
562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
563fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // The target drawable might fail to load for any number of
565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // reasons, but we always want to include the resource name.
566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Since the client already expects this method to throw a
567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NotFoundException, just throw one of those.
568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException nfe = new NotFoundException("Drawable " + name
569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " with resource ID #0x" + Integer.toHexString(id), e);
570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            nfe.setStackTrace(new StackTraceElement[0]);
571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw nfe;
572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
576082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable.ConstantState cs = dr.getConstantState();
578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (cs == null) {
579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int changingConfigs = cs.getChangingConfigurations();
584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedColorDrawables.put(key, cs);
587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(
590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // If this resource does not vary based on layout direction,
593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // we can put it in all of the preload maps.
594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[0].put(key, cs);
595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[1].put(key, cs);
596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } else {
597fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // Otherwise, only in the layout dir we loaded it for.
598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mAccessLock) {
604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches.put(key, theme, cs, usesTheme);
605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
609ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette    private boolean verifyPreloadConfig(@Config int changingConfigurations,
610ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette            @Config int allowVarying, @AnyRes int resourceId, @Nullable String name) {
611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // We allow preloading of resources even if they vary by font scale (which
612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // doesn't impact resource selection) or density (which we handle specially by
613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // simply turning off all preloading), as well as any other configs specified
614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // by the caller.
615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // This should never happen in production, so we should log a
624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // warning even if we're not debugging.
625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloaded " + name + " resource #0x"
626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ") that varies with configuration!!");
628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return false;
629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
634fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
635fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloading " + name + " resource #0x"
638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ")");
640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return true;
642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads a drawable from XML or resources stream.
646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
648082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable dr;
672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (file.endsWith(".xml")) {
676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser rp = loadXmlResourceParser(
677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "drawable");
678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromXml(wrapper, rp, theme);
679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rp.close();
680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final InputStream is = mAssets.openNonAsset(
682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                is.close();
685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException rnf = new NotFoundException(
689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
691fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return dr;
696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Given the value and id, we can get the XML filename as in value.data, based on that, we
700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * first try to load CSL from the cache. If not found, try to get from the constant state.
701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Last, parse the XML and generate the CSL.
702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
704082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            TypedValue value, int id) {
705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return complexColor;
710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = factory.newInstance(wrapper, theme);
717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor == null) {
719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
7230b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
7240b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette
725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPreloading) {
7260b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
7270b9295d06750dc6da032a2b2092e2c500c65393fAlan Viverette                        0, value.resourceId, "color")) {
728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cache.put(key, theme, complexColor.getConstantState());
732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
739082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("loadComplexColor", name);
745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor;
759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from complex color resource ID #0x"
765fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
780082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme)
781fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
782fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("PreloadColorStateList", name);
787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null && complexColor instanceof ColorStateList) {
800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) complexColor;
801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException(
804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                "Can't find ColorStateList from drawable resource ID #0x"
805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + Integer.toHexString(id));
806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ColorStateList csl;
811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) factory.newInstance();
815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        csl = ColorStateList.valueOf(value.data);
818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "color")) {
822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.put(key, csl.getConstantState());
823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
825fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return csl;
827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
833fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * and selector tag.
835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
838fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
840082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new UnsupportedOperationException(
843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "Can't convert to ComplexColor: type=0x" + value.type);
844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = null;
864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser parser = loadXmlResourceParser(
869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "ComplexColor");
870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final AttributeSet attrs = Xml.asAttributeSet(parser);
872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                int type;
873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                while ((type = parser.next()) != XmlPullParser.START_TAG
874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        && type != XmlPullParser.END_DOCUMENT) {
875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Seek parser to start tag.
876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
877fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (type != XmlPullParser.START_TAG) {
878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new XmlPullParserException("No start tag found");
879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = parser.getName();
882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name.equals("gradient")) {
883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                } else if (name.equals("selector")) {
885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                parser.close();
888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from ComplexColor resource ID #0x"
892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
898fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
903fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
904fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads an XML parser for the specified file.
909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param file the path for the XML file to parse
911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param id the resource identifier for the file
912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assetCookie the asset cookie for the file
913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param type the type of resource (used for logging)
914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a parser for the specified XML file
915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @throws NotFoundException if the file could not be loaded
916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
918082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
919082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            @NonNull String type)
920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (mCachedXmlBlocks) {
924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // First see if this block is in our cache.
928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int num = cachedXmlBlockFiles.length;
929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    for (int i = 0; i < num; i++) {
930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                && cachedXmlBlockFiles[i].equals(file)) {
932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            return cachedXmlBlocks[i].newParser();
933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Not in the cache, create a new block and put it at
937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // the next slot in the cache.
938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (block != null) {
940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        mLastCachedXmlBlockIndex = pos;
942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (oldBlock != null) {
944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            oldBlock.close();
945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockCookies[pos] = assetCookie;
947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockFiles[pos] = file;
948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlocks[pos] = block;
949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        return block.newParser();
950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException("File " + file
954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(id));
962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Start preloading of resource data using this Resources object.  Only
966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * for use by the zygote process for loading common system resources.
967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@hide}
968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public final void startPreloading() {
970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (sPreloaded) {
972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw new IllegalStateException("Resources already preloaded");
973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloaded = true;
975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = true;
976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            updateConfiguration(null, null, null);
978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Called by zygote when it is done preloading resources, to change back
983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * to normal Resources operation.
984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
985fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void finishPreloading() {
986fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
987fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = false;
988fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
989fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
990fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
991fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
992fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
993fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return sPreloadedDrawables[0];
994fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ThemeImpl newThemeImpl() {
997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return new ThemeImpl();
998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1000082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    /**
1001082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
1002082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     */
1003082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
1004082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        ThemeImpl impl = new ThemeImpl();
1005082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.mKey.setTo(key);
1006082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.rebase();
1007082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        return impl;
1008082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    }
1009082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski
1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public class ThemeImpl {
1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Unique key for the series of styles applied to this theme.
1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @SuppressWarnings("hiding")
1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final AssetManager mAssets;
1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final long mTheme;
1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Resource identifier for the theme.
1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private int mThemeResId = 0;
1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ ThemeImpl() {
1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets = ResourcesImpl.this.mAssets;
1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTheme = mAssets.createTheme();
1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @Override
1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        protected void finalize() throws Throwable {
1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            super.finalize();
1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.releaseTheme(mTheme);
1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ Resources.ThemeKey getKey() {
1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mKey;
1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ long getNativeTheme() {
1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mTheme;
1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ int getAppliedStyleResId() {
1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mThemeResId;
1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void applyStyle(int resId, boolean force) {
1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyThemeStyle(mTheme, resId, force);
1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mThemeResId = resId;
1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mKey.append(resId, force);
1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1055fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1056fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1057fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void setTo(ThemeImpl other) {
1058fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (other.mKey) {
1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.copyTheme(mTheme, other.mTheme);
1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mThemeResId = other.mThemeResId;
1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mKey.setTo(other.getKey());
1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
1070082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                AttributeSet set,
1071082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleableRes int[] attrs,
1072082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @AttrRes int defStyleAttr,
1073082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleRes int defStyleRes) {
1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // XXX note that for now we only work with compiled XML files.
1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // To support generic XML files we will need to manually parse
1080fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // out the attributes from the XML file (applying type information
1081fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // contained in the resources and such).
1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        parser != null ? parser.mParseState : 0,
1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        attrs, array.mData, array.mIndices);
1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = parser;
1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
1095082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] values,
1096082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] attrs) {
1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (values == null || len != values.length) {
1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new IllegalArgumentException(
1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            "Base attribute values must the same length as attrs");
1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = null;
1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int[] getAllAttributes() {
1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.getStyleAttributes(getAppliedStyleResId());
1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1122ac85f90466dd60d2af8ffc3942d503a0de606726Alan Viverette        @Config int getChangingConfigurations() {
1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int nativeChangingConfig =
1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        AssetManager.getThemeChangingConfigurations(mTheme);
1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        public void dump(int priority, String tag, String prefix) {
1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String[] getTheme() {
1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int N = mKey.mCount;
1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String[] themes = new String[N * 2];
1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[j];
1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean forced = mKey.mForce[j];
1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    try {
1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = getResourceName(resId);
1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } catch (NotFoundException e) {
1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = Integer.toHexString(i);
1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    themes[i + 1] = forced ? "forced" : "not forced";
1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return themes;
1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Rebases the theme against the parent Resource object's current
1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * configuration by re-applying the styles passed to
1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * {@link #applyStyle(int, boolean)}.
1158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void rebase() {
1160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.clearTheme(mTheme);
1162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Reapply the same styles in the same order.
1164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0; i < mKey.mCount; i++) {
1165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[i];
1166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean force = mKey.mForce[i];
1167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.applyThemeStyle(mTheme, resId, force);
1168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski}
1173