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