ResourcesImpl.java revision 082614c6a57a115ee0c5975e3579bf34a178c0f8
1fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/*
2fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Copyright (C) 2016 The Android Open Source Project
3fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
4fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * use this file except in compliance with the License. You may obtain a copy of
6fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License at
7fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
8fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0
9fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski *
10fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * License for the specific language governing permissions and limitations under
14fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * the License.
15fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
16fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipackage android.content.res;
17fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
18fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.Animator;
19fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.animation.StateListAnimator;
20fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AnyRes;
21fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.AttrRes;
22fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.NonNull;
23fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.Nullable;
24fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.PluralsRes;
25fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.RawRes;
26fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleRes;
27fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.annotation.StyleableRes;
28fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.pm.ActivityInfo;
29fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.content.res.Resources.NotFoundException;
30fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.ColorDrawable;
31fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.graphics.drawable.Drawable;
32fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.icu.text.PluralRules;
33fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Build;
34fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.os.Trace;
35fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.AttributeSet;
36fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.DisplayMetrics;
37fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LocaleList;
38fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Log;
39fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.LongSparseArray;
40fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Slog;
41fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.TypedValue;
42fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport android.util.Xml;
43fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport org.xmlpull.v1.XmlPullParser;
44fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport org.xmlpull.v1.XmlPullParserException;
45fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
46fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.io.InputStream;
47fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Arrays;
48fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskiimport java.util.Locale;
49fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
50fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski/**
51082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * The implementation of Resource access. This class contains the AssetManager and all caches
52082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * associated with it.
53082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
54082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link Resources} is just a thing wrapper around this class. When a configuration change
55082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * occurs, clients can retain the same {@link Resources} reference because the underlying
56082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski * {@link ResourcesImpl} object will be updated or re-created.
57082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski *
58fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski * @hide
59fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski */
60fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinskipublic class ResourcesImpl {
61fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static final String TAG = "Resources";
62fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
63fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_LOAD = false;
64fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean DEBUG_CONFIG = false;
65fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_PRELOAD = false;
66fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final boolean TRACE_FOR_MISS_PRELOAD = false;
67fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
68fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
69fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
70fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
71fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int ID_OTHER = 0x01000004;
72fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
73fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final Object sSync = new Object();
74fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
75fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static boolean sPreloaded;
76fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean mPreloading;
77fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
78fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Information about preloaded resources.  Note that they are not
79fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // protected by a lock, because while preloading in zygote we are all
80fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // single-threaded, and after that these are immutable.
81fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
82fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
83fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            = new LongSparseArray<>();
84fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
85fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloadedComplexColors = new LongSparseArray<>();
86fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
87fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Lock object used to protect access to caches and configuration. */
88fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Object mAccessLock = new Object();
89fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
90fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // These are protected by mAccessLock.
91fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mTmpConfig = new Configuration();
92fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mDrawableCache = new DrawableCache();
93fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final DrawableCache mColorDrawableCache = new DrawableCache();
94fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
95fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
96fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
97fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
98fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
99fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            new ConfigurationBoundResourceCache<>();
100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /** Size of the cyclical cache used to map XML files to blocks. */
102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static final int XML_BLOCK_CACHE_SIZE = 4;
103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    // Cyclical cache used for recently-accessed XML files.
105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private int mLastCachedXmlBlockIndex = -1;
106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final AssetManager mAssets;
112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    final DisplayMetrics mMetrics = new DisplayMetrics();
113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules mPluralRule;
115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private final Configuration mConfiguration = new Configuration();
117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    static {
120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables = new LongSparseArray[2];
121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[0] = new LongSparseArray<>();
122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        sPreloadedDrawables[1] = new LongSparseArray<>();
123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Creates a new ResourcesImpl object with CompatibilityInfo.
127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assets Previously created AssetManager.
129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param metrics Current display metrics to consider when
130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *                selecting/computing resource values.
131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param config Desired device configuration to consider when
132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *               selecting/computing resource values (optional).
133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param compatInfo this resource's compatibility info. Must not be null.
134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
136082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            CompatibilityInfo compatInfo) {
137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets = assets;
138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mMetrics.setToDefaults();
139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        updateConfiguration(config, metrics, compatInfo);
140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        mAssets.ensureStringBlocks();
141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
143082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public AssetManager getAssets() {
144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets;
145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    DisplayMetrics getDisplayMetrics() {
148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mMetrics;
151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration getConfiguration() {
154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mConfiguration;
155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Configuration[] getSizeConfigurations() {
158fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getSizeConfigurations();
159fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
160fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
161fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CompatibilityInfo getCompatibilityInfo() {
162fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mCompatibilityInfo;
163fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
164fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
165fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private PluralRules getPluralRule() {
166fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
167fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule == null) {
168fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
169fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
170fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mPluralRule;
171fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
172fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
173fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
174fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
175fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
176fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
177fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
178fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
179fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
180fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
181fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
182fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
183fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
184082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean resolveRefs) throws NotFoundException {
185fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
186fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (found) {
187fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
188fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
189fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
190fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
191fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
192fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void getValue(String name, TypedValue outValue, boolean resolveRefs)
193fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
194fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int id = getIdentifier(name, "string", null);
195fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
196fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            getValue(id, outValue, resolveRefs);
197fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
198fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
199fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("String resource name " + name);
200fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
201fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
202fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    int getIdentifier(String name, String defType, String defPackage) {
203fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (name == null) {
204fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NullPointerException("name is null");
205fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
206fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
207fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return Integer.parseInt(name);
208fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
209fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Ignore
210fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
211fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAssets.getResourceIdentifier(name, defType, defPackage);
212fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
213fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
214fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
215fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceName(@AnyRes int resid) throws NotFoundException {
216fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceName(resid);
217fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
218fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
219fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
220fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
221fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
222fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
223fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
224fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourcePackageName(resid);
225fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
226fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
227fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
228fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
229fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
230fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
231fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
232fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceTypeName(resid);
233fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
234fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
235fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
236fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
237fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
238fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
239fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
240fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String str = mAssets.getResourceEntryName(resid);
241fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (str != null) return str;
242fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Unable to find resource ID #0x"
243fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(resid));
244fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
245fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
246fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
247fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
248fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        PluralRules rule = getPluralRule();
249fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        CharSequence res = mAssets.getResourceBagText(id,
250fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                attrForQuantityCode(rule.select(quantity)));
251fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
252fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
253fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
254fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        res = mAssets.getResourceBagText(id, ID_OTHER);
255fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (res != null) {
256fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return res;
257fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
258fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
259fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " quantity=" + quantity
260fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + " item=" + rule.select(quantity));
261fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
262fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
263fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static int attrForQuantityCode(String quantityCode) {
264fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        switch (quantityCode) {
265fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ZERO: return 0x01000005;
266fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_ONE:  return 0x01000006;
267fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_TWO:  return 0x01000007;
268fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_FEW:  return 0x01000008;
269fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            case PluralRules.KEYWORD_MANY: return 0x01000009;
270fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            default:                       return ID_OTHER;
271fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
272fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
273fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
274fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
275fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
276fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
277fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, tempValue, true);
278fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
279fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
280fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
281fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
282fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + "resource ID #0x" + Integer.toHexString(id), e);
283fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
284fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
285fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
286fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
287fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
288fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        getValue(id, value, true);
289fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
290fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
291fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.ACCESS_STREAMING);
292fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
293fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
294fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    " from drawable resource ID #0x" + Integer.toHexString(id));
295fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
296fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
297fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
298fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
299fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
300fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
301fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mAnimatorCache;
302fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
303fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
304fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
305fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return mStateListAnimatorCache;
306fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
307fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
308082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
309082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                                    CompatibilityInfo compat) {
310fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mAccessLock) {
311fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (false) {
312fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
313fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + mConfiguration + " old compat is " + mCompatibilityInfo);
314fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
315fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + config + " new compat is " + compat);
316fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
317fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (compat != null) {
318fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mCompatibilityInfo = compat;
319fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
320fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (metrics != null) {
321fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mMetrics.setTo(metrics);
322fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
323fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NOTE: We should re-arrange this code to create a Display
324fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // with the CompatibilityInfo that is used everywhere we deal
325fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // with the display in relation to this app, rather than
326fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // doing the conversion here.  This impl should be okay because
327fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we make sure to return a compatible display in the places
328fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // where there are public APIs to retrieve the display...  but
329fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // it would be cleaner and more maintainble to just be
330fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // consistently dealing with a compatible display everywhere in
331fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // the framework.
332fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
333fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
334fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int configChanges = calcConfigChanges(config);
335fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
336fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            LocaleList locales = mConfiguration.getLocales();
337fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (locales.isEmpty()) {
338fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                locales = LocaleList.getAdjustedDefault();
339fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mConfiguration.setLocales(locales);
340fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
341fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
342fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mMetrics.densityDpi = mConfiguration.densityDpi;
343fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
344fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
345fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
346fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
347fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int width, height;
348fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mMetrics.widthPixels >= mMetrics.heightPixels) {
349fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                width = mMetrics.widthPixels;
350fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                height = mMetrics.heightPixels;
351fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
352fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                //noinspection SuspiciousNameCombination
353fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                width = mMetrics.heightPixels;
354fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                //noinspection SuspiciousNameCombination
355fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                height = mMetrics.widthPixels;
356fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
357fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
358fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int keyboardHidden;
359fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
360fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
361fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
362fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
363fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                keyboardHidden = mConfiguration.keyboardHidden;
364fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
365fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
366fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
367fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    adjustLanguageTag(locales.get(0).toLanguageTag()),
368fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.orientation,
369fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.touchscreen,
370fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.densityDpi, mConfiguration.keyboard,
371fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    keyboardHidden, mConfiguration.navigation, width, height,
372fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.smallestScreenWidthDp,
373fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
374fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mConfiguration.screenLayout, mConfiguration.uiMode,
375fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Build.VERSION.RESOURCES_SDK_INT);
376fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
377fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (DEBUG_CONFIG) {
378fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Slog.i(TAG, "**** Updating config of " + this + ": final config is "
379fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + mConfiguration + " final compat is " + mCompatibilityInfo);
380fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
381fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
382fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mDrawableCache.onConfigurationChange(configChanges);
383fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mColorDrawableCache.onConfigurationChange(configChanges);
384fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mComplexColorCache.onConfigurationChange(configChanges);
385fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAnimatorCache.onConfigurationChange(configChanges);
386fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mStateListAnimatorCache.onConfigurationChange(configChanges);
387fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
388fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
389fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
390fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
391fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPluralRule != null) {
392fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
393fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
394fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
395fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
396fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
397fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
398082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Called by ConfigurationBoundResourceCacheTest.
399fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
400082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    public int calcConfigChanges(Configuration config) {
401fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int configChanges = 0xfffffff;
402fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (config != null) {
403fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTmpConfig.setTo(config);
404fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            int density = config.densityDpi;
405fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
406fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                density = mMetrics.noncompatDensityDpi;
407fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
408fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
409fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
410fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
411fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mTmpConfig.getLocales().isEmpty()) {
412fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mTmpConfig.setLocales(LocaleList.getDefault());
413fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
414fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            configChanges = mConfiguration.updateFrom(mTmpConfig);
415fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
416fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
417fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return configChanges;
418fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
419fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
420fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
421fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
422fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
423fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
424fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * All released versions of android prior to "L" used the deprecated language
425fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tags, so we will need to support them for backwards compatibility.
426fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
427fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Note that this conversion needs to take place *after* the call to
428fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@code toLanguageTag} because that will convert all the deprecated codes to
429fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * the new ones, even if they're set manually.
430fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
431fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private static String adjustLanguageTag(String languageTag) {
432fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final int separator = languageTag.indexOf('-');
433fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String language;
434fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String remainder;
435fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
436fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (separator == -1) {
437fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag;
438fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = "";
439fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
440fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            language = languageTag.substring(0, separator);
441fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            remainder = languageTag.substring(separator);
442fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
443fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
444fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return Locale.adjustLanguageCode(language) + remainder;
445fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
446fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
447fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
448fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Call this to remove all cached loaded layout resources from the
449fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Resources object.  Only intended for use with performance testing
450fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * tools.
451fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
452fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public void flushLayoutCache() {
453fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (mCachedXmlBlocks) {
454fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockCookies, 0);
455fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(mCachedXmlBlockFiles, null);
456fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
457fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
458fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
459fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock oldBlock = cachedXmlBlocks[i];
460fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (oldBlock != null) {
461fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    oldBlock.close();
462fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
463fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
464fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Arrays.fill(cachedXmlBlocks, null);
465fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
466fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
467fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
468fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
469fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
470082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            boolean useCache) throws NotFoundException {
471fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
472fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (TRACE_FOR_PRELOAD) {
473fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Log only framework resources
474fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if ((id >>> 24) == 0x1) {
475fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String name = getResourceName(id);
476fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (name != null) {
477fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        Log.d("PreloadDrawable", name);
478fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
479fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
480fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
481fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
482fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean isColorDrawable;
483fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final DrawableCache caches;
484fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final long key;
485fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
486fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
487fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = true;
488fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mColorDrawableCache;
489fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = value.data;
490fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
491fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                isColorDrawable = false;
492fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches = mDrawableCache;
493fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                key = (((long) value.assetCookie) << 32) | value.data;
494fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
495fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
496fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // First, check whether we have a cached version of this drawable
497fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // that was inflated against the specified theme. Skip the cache if
498fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // we're currently preloading or we're not using the cache.
499fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (!mPreloading && useCache) {
500fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
501fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (cachedDrawable != null) {
502fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    return cachedDrawable;
503fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
504fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
505fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
506fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Next, check preloaded drawables. Preloaded drawables may contain
507fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // unresolved theme attributes.
508fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final Drawable.ConstantState cs;
509fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
510fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedColorDrawables.get(key);
511fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
512fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
513fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
514fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
515fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Drawable dr;
516fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (cs != null) {
517fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = cs.newDrawable(wrapper);
518fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else if (isColorDrawable) {
519fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = new ColorDrawable(value.data);
520fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
521fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = loadDrawableForCookie(wrapper, value, id, null);
522fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
523fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
524fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Determine if the drawable has unresolved theme attributes. If it
525fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // does, we'll need to apply a theme and store it in a theme-specific
526fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache.
527fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
528fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (canApplyTheme && theme != null) {
529fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = dr.mutate();
530fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.applyTheme(theme);
531fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.clearMutated();
532fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
533fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
534fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // If we were able to obtain a drawable, store it in the appropriate
535fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // cache: preload, not themed, null theme, or theme-specific. Don't
536fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // pollute the cache with drawables loaded from a foreign density.
537fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (dr != null && useCache) {
538fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr.setChangingConfigurations(value.changingConfigurations);
539fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
540fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
541fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
542fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return dr;
543fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
544fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String name;
545fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
546fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = getResourceName(id);
547fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e2) {
548fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                name = "(missing name)";
549fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
550fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
551fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // The target drawable might fail to load for any number of
552fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // reasons, but we always want to include the resource name.
553fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Since the client already expects this method to throw a
554fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // NotFoundException, just throw one of those.
555fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException nfe = new NotFoundException("Drawable " + name
556fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " with resource ID #0x" + Integer.toHexString(id), e);
557fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            nfe.setStackTrace(new StackTraceElement[0]);
558fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw nfe;
559fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
560fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
561fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
562fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
563082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
564fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable.ConstantState cs = dr.getConstantState();
565fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (cs == null) {
566fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return;
567fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
568fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
569fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
570fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final int changingConfigs = cs.getChangingConfigurations();
571fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (isColorDrawable) {
572fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
573fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedColorDrawables.put(key, cs);
574fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
575fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
576fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(
577fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
578fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
579fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // If this resource does not vary based on layout direction,
580fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // we can put it in all of the preload maps.
581fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[0].put(key, cs);
582fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[1].put(key, cs);
583fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } else {
584fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        // Otherwise, only in the layout dir we loaded it for.
585fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
586fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
587fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
588fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
589fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
590fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mAccessLock) {
591fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                caches.put(key, theme, cs, usesTheme);
592fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
593fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
594fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
595fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
596fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
597082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            int resourceId, String name) {
598fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // We allow preloading of resources even if they vary by font scale (which
599fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // doesn't impact resource selection) or density (which we handle specially by
600fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // simply turning off all preloading), as well as any other configs specified
601fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // by the caller.
602fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
603fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
604fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
605fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
606fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
607fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
608fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
609fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
610fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // This should never happen in production, so we should log a
611fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // warning even if we're not debugging.
612fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloaded " + name + " resource #0x"
613fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
614fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ") that varies with configuration!!");
615fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return false;
616fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
617fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
618fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            String resName;
619fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
620fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = getResourceName(resourceId);
621fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (NotFoundException e) {
622fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                resName = "?";
623fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
624fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.w(TAG, "Preloading " + name + " resource #0x"
625fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(resourceId)
626fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + " (" + resName + ")");
627fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
628fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return true;
629fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
630fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
631fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
632fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads a drawable from XML or resources stream.
633fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
634fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
635082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
636fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
637fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
638fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
639fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
640fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
641fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
642fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
643fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
644fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
645fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
646fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
647fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
648fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
649fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
650fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
651fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
652fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
653fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
654fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
655fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
656fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
657fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
658fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final Drawable dr;
659fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
660fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
661fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        try {
662fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (file.endsWith(".xml")) {
663fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser rp = loadXmlResourceParser(
664fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "drawable");
665fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromXml(wrapper, rp, theme);
666fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rp.close();
667fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
668fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final InputStream is = mAssets.openNonAsset(
669fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
670fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
671fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                is.close();
672fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
673fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } catch (Exception e) {
674fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
675fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            final NotFoundException rnf = new NotFoundException(
676fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
677fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            rnf.initCause(e);
678fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw rnf;
679fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
680fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
681fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
682fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return dr;
683fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
684fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
685fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
686fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Given the value and id, we can get the XML filename as in value.data, based on that, we
687fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * first try to load CSL from the cache. If not found, try to get from the constant state.
688fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Last, parse the XML and generate the CSL.
689fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
690fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
691082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            TypedValue value, int id) {
692fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
693fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
694fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
695fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
696fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return complexColor;
697fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
698fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
699fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
700fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
701fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
702fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
703fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = factory.newInstance(wrapper, theme);
704fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
705fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor == null) {
706fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
707fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
708fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
709fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null) {
710fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (mPreloading) {
711fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
712fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "color")) {
713fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
714fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
715fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } else {
716fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                cache.put(key, theme, complexColor.getConstantState());
717fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
718fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
719fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
720fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
721fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
722fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
723fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
724082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
725fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
726fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
727fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
728fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
729fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("loadComplexColor", name);
730fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
731fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
732fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
733fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
734fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
735fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
736fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
737fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
738fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
739fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
740fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
741fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
742fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
743fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor;
744fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
745fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
746fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
747fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
748fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
749fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from complex color resource ID #0x"
750fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
751fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
752fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
753fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
754fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
755fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
756fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
757fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
758fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
759fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
760fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
761fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
762fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
763fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
764fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
765082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme)
766fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
767fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_PRELOAD) {
768fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
769fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
770fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
771fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) android.util.Log.d("PreloadColorStateList", name);
772fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
773fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
774fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
775fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final long key = (((long) value.assetCookie) << 32) | value.data;
776fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
777fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        // Handle inline color definitions.
778fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
779fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
780fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return getColorStateListFromInt(value, key);
781fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
782fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
783fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
784fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (complexColor != null && complexColor instanceof ColorStateList) {
785fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) complexColor;
786fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
787fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
788fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException(
789fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                "Can't find ColorStateList from drawable resource ID #0x"
790fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + Integer.toHexString(id));
791fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
792fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
793fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
794fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
795fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ColorStateList csl;
796fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final android.content.res.ConstantState<ComplexColor> factory =
797fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.get(key);
798fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (factory != null) {
799fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return (ColorStateList) factory.newInstance();
800fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
801fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
802fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        csl = ColorStateList.valueOf(value.data);
803fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
804fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
805fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
806fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "color")) {
807fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                sPreloadedComplexColors.put(key, csl.getConstantState());
808fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
809fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
810fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
811fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return csl;
812fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
813fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
814fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
815fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
816fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
817fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
818fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
819fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * and selector tag.
820fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
821fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
822fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
823fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @Nullable
824fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
825082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            Resources.Theme theme) {
826fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (value.string == null) {
827fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new UnsupportedOperationException(
828fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "Can't convert to ComplexColor: type=0x" + value.type);
829fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
830fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
831fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        final String file = value.string.toString();
832fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
833fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (TRACE_FOR_MISS_PRELOAD) {
834fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            // Log only framework resources
835fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if ((id >>> 24) == 0x1) {
836fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = getResourceName(id);
837fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name != null) {
838fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
839fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + ": " + name + " at " + file);
840fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
841fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
842fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
843fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
844fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (DEBUG_LOAD) {
845fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
846fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
847fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
848fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        ComplexColor complexColor = null;
849fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
850fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
851fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (file.endsWith(".xml")) {
852fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
853fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlResourceParser parser = loadXmlResourceParser(
854fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        file, id, value.assetCookie, "ComplexColor");
855fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
856fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final AttributeSet attrs = Xml.asAttributeSet(parser);
857fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                int type;
858fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                while ((type = parser.next()) != XmlPullParser.START_TAG
859fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        && type != XmlPullParser.END_DOCUMENT) {
860fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Seek parser to start tag.
861fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
862fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (type != XmlPullParser.START_TAG) {
863fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new XmlPullParserException("No start tag found");
864fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
865fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
866fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String name = parser.getName();
867fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (name.equals("gradient")) {
868fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
869fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                } else if (name.equals("selector")) {
870fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
871fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
872fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                parser.close();
873fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
874fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
875fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException(
876fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        "File " + file + " from ComplexColor resource ID #0x"
877fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                + Integer.toHexString(id));
878fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
879fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
880fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
881fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        } else {
882fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
883fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throw new NotFoundException(
884fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    "File " + file + " from drawable resource ID #0x"
885fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            + Integer.toHexString(id) + ": .xml extension required");
886fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
887fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
888fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
889fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return complexColor;
890fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
891fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
892fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
893fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Loads an XML parser for the specified file.
894fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     *
895fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param file the path for the XML file to parse
896fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param id the resource identifier for the file
897fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param assetCookie the asset cookie for the file
898fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @param type the type of resource (used for logging)
899fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @return a parser for the specified XML file
900fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * @throws NotFoundException if the file could not be loaded
901fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
902fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    @NonNull
903082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie,
904082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski            @NonNull String type)
905fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            throws NotFoundException {
906fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (id != 0) {
907fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            try {
908fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (mCachedXmlBlocks) {
909fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
910fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
911fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
912fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // First see if this block is in our cache.
913fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int num = cachedXmlBlockFiles.length;
914fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    for (int i = 0; i < num; i++) {
915fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
916fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                                && cachedXmlBlockFiles[i].equals(file)) {
917fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            return cachedXmlBlocks[i].newParser();
918fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
919fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
920fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
921fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // Not in the cache, create a new block and put it at
922fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    // the next slot in the cache.
923fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
924fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    if (block != null) {
925fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
926fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        mLastCachedXmlBlockIndex = pos;
927fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
928fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        if (oldBlock != null) {
929fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            oldBlock.close();
930fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        }
931fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockCookies[pos] = assetCookie;
932fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlockFiles[pos] = file;
933fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        cachedXmlBlocks[pos] = block;
934fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        return block.newParser();
935fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
936fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
937fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            } catch (Exception e) {
938fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final NotFoundException rnf = new NotFoundException("File " + file
939fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
940fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                rnf.initCause(e);
941fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw rnf;
942fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
943fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
944fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
945fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
946fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                + Integer.toHexString(id));
947fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
948fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
949fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
950fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Start preloading of resource data using this Resources object.  Only
951fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * for use by the zygote process for loading common system resources.
952fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * {@hide}
953fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
954fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public final void startPreloading() {
955fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        synchronized (sSync) {
956fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            if (sPreloaded) {
957fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                throw new IllegalStateException("Resources already preloaded");
958fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
959fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            sPreloaded = true;
960fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = true;
961fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
962fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            updateConfiguration(null, null, null);
963fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
964fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
965fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
966fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    /**
967fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * Called by zygote when it is done preloading resources, to change back
968fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     * to normal Resources operation.
969fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski     */
970fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    void finishPreloading() {
971fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        if (mPreloading) {
972fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mPreloading = false;
973fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            flushLayoutCache();
974fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
975fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
976fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
977fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
978fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return sPreloadedDrawables[0];
979fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
980fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
981fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    ThemeImpl newThemeImpl() {
982fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        return new ThemeImpl();
983fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
984fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
985082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    /**
986082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     * Creates a new ThemeImpl which is already set to the given Resources.ThemeKey.
987082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski     */
988082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    ThemeImpl newThemeImpl(Resources.ThemeKey key) {
989082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        ThemeImpl impl = new ThemeImpl();
990082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.mKey.setTo(key);
991082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        impl.rebase();
992082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski        return impl;
993082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski    }
994082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski
995fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    public class ThemeImpl {
996fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
997fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Unique key for the series of styles applied to this theme.
998fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
999fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
1000fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1001fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @SuppressWarnings("hiding")
1002fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final AssetManager mAssets;
1003fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private final long mTheme;
1004fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1005fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1006fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Resource identifier for the theme.
1007fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1008fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        private int mThemeResId = 0;
1009fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1010fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ ThemeImpl() {
1011fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets = ResourcesImpl.this.mAssets;
1012fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mTheme = mAssets.createTheme();
1013fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1014fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1015fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @Override
1016fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        protected void finalize() throws Throwable {
1017fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            super.finalize();
1018fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            mAssets.releaseTheme(mTheme);
1019fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1020fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1021fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ Resources.ThemeKey getKey() {
1022fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mKey;
1023fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1024fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1025fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ long getNativeTheme() {
1026fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mTheme;
1027fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1028fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1029fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /*package*/ int getAppliedStyleResId() {
1030fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mThemeResId;
1031fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1032fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1033fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void applyStyle(int resId, boolean force) {
1034fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1035fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyThemeStyle(mTheme, resId, force);
1036fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1037fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mThemeResId = resId;
1038fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                mKey.append(resId, force);
1039fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1040fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1041fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1042fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void setTo(ThemeImpl other) {
1043fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1044fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                synchronized (other.mKey) {
1045fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.copyTheme(mTheme, other.mTheme);
1046fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1047fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mThemeResId = other.mThemeResId;
1048fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    mKey.setTo(other.getKey());
1049fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1050fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1051fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1052fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1053fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1054fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
1055082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                AttributeSet set,
1056082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleableRes int[] attrs,
1057082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @AttrRes int defStyleAttr,
1058082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @StyleRes int defStyleRes) {
1059fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1060fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1061fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1062fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1063fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // XXX note that for now we only work with compiled XML files.
1064fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // To support generic XML files we will need to manually parse
1065fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // out the attributes from the XML file (applying type information
1066fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // contained in the resources and such).
1067fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
1068fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
1069fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        parser != null ? parser.mParseState : 0,
1070fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        attrs, array.mData, array.mIndices);
1071fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1072fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = parser;
1073fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1074fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1075fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1076fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1077fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1078fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        @NonNull
1079fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
1080082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] values,
1081082614c6a57a115ee0c5975e3579bf34a178c0f8Adam Lesinski                @NonNull int[] attrs) {
1082fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1083fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int len = attrs.length;
1084fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                if (values == null || len != values.length) {
1085fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    throw new IllegalArgumentException(
1086fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                            "Base attribute values must the same length as attrs");
1087fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1088fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1089fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
1090fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
1091fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mTheme = wrapper;
1092fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                array.mXml = null;
1093fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return array;
1094fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1095fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1096fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1097fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
1098fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1099fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
1100fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1101fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1102fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1103fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int[] getAllAttributes() {
1104fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            return mAssets.getStyleAttributes(getAppliedStyleResId());
1105fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1106fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1107fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        int getChangingConfigurations() {
1108fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1109fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int nativeChangingConfig =
1110fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        AssetManager.getThemeChangingConfigurations(mTheme);
1111fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
1112fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1113fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1114fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1115fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        public void dump(int priority, String tag, String prefix) {
1116fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1117fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
1118fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1119fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1120fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1121fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        String[] getTheme() {
1122fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1123fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final int N = mKey.mCount;
1124fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                final String[] themes = new String[N * 2];
1125fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
1126fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[j];
1127fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean forced = mKey.mForce[j];
1128fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    try {
1129fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = getResourceName(resId);
1130fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    } catch (NotFoundException e) {
1131fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                        themes[i] = Integer.toHexString(i);
1132fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    }
1133fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    themes[i + 1] = forced ? "forced" : "not forced";
1134fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1135fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                return themes;
1136fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1137fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1138fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1139fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        /**
1140fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * Rebases the theme against the parent Resource object's current
1141fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * configuration by re-applying the styles passed to
1142fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         * {@link #applyStyle(int, boolean)}.
1143fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski         */
1144fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        void rebase() {
1145fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            synchronized (mKey) {
1146fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                AssetManager.clearTheme(mTheme);
1147fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski
1148fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                // Reapply the same styles in the same order.
1149fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                for (int i = 0; i < mKey.mCount; i++) {
1150fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final int resId = mKey.mResId[i];
1151fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    final boolean force = mKey.mForce[i];
1152fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                    AssetManager.applyThemeStyle(mTheme, resId, force);
1153fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski                }
1154fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski            }
1155fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski        }
1156fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski    }
1157fb302ccd8e0610a09691ea5503ff8111dc7a2e41Adam Lesinski}
1158