19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.view;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19417ee5ba89f7e0fe5efd34fce74bf1ee5923d976Tor Norbyeimport android.annotation.StyleRes;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContextWrapper;
2299bf63fdafb011ccdd9b2315f73b351f28970644Alan Viveretteimport android.content.res.AssetManager;
23756220bd1912535840388a6743830d2e59ad4964Dianne Hackbornimport android.content.res.Configuration;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
2704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette * A context wrapper that allows you to modify or replace the theme of the
2804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette * wrapped context.
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ContextThemeWrapper extends ContextWrapper {
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mThemeResource;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Resources.Theme mTheme;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private LayoutInflater mInflater;
34756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    private Configuration mOverrideConfiguration;
35756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    private Resources mResources;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    /**
3804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * Creates a new context wrapper with no theme and no base context.
3979047c62b58fb0a0ddf28e2b90fe4d17e05bc528Christopher Tate     * <p class="note">
4079047c62b58fb0a0ddf28e2b90fe4d17e05bc528Christopher Tate     * <strong>Note:</strong> A base context <strong>must</strong> be attached
4104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * using {@link #attachBaseContext(Context)} before calling any other
4204067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * method on the newly constructed context wrapper.
4304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     */
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ContextThemeWrapper() {
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(null);
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
47b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette
4804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    /**
4904067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * Creates a new context wrapper with the specified theme.
5004067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * <p>
5104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * The specified theme will be applied on top of the base context's theme.
5204067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * Any attributes not explicitly defined in the theme identified by
5304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * <var>themeResId</var> will retain their original values.
5404067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     *
5504067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param base the base context
5604067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param themeResId the resource ID of the theme to be applied on top of
5704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     *                   the base context's theme
5804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     */
59417ee5ba89f7e0fe5efd34fce74bf1ee5923d976Tor Norbye    public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
60b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        super(base);
61b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mThemeResource = themeResId;
62b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    }
63b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette
6404067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    /**
6504067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * Creates a new context wrapper with the specified theme.
6604067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * <p>
6704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * Unlike {@link #ContextThemeWrapper(Context, int)}, the theme passed to
6804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * this constructor will completely replace the base context's theme.
6904067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     *
7004067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param base the base context
7104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param theme the theme against which resources should be inflated
7204067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     */
73b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    public ContextThemeWrapper(Context base, Resources.Theme theme) {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(base);
75b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette        mTheme = theme;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
78b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    @Override
79b9ead4a91599ca63e947f74f83b67a58bda64a82Alan Viverette    protected void attachBaseContext(Context newBase) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.attachBaseContext(newBase);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
82756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn
83756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    /**
84756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * Call to set an "override configuration" on this context -- this is
85756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * a configuration that replies one or more values of the standard
86756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * configuration that is applied to the context.  See
87756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * {@link Context#createConfigurationContext(Configuration)} for more
88756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * information.
89756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     *
90756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     * <p>This method can only be called once, and must be called before any
9199bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette     * calls to {@link #getResources()} or {@link #getAssets()} are made.
92756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn     */
93756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    public void applyOverrideConfiguration(Configuration overrideConfiguration) {
94756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        if (mResources != null) {
9599bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette            throw new IllegalStateException(
9699bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette                    "getResources() or getAssets() has already been called");
97756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        }
98756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        if (mOverrideConfiguration != null) {
99756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn            throw new IllegalStateException("Override configuration has already been set");
100756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        }
101756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        mOverrideConfiguration = new Configuration(overrideConfiguration);
102756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    }
103756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn
1043ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski    /**
1053ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski     * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
1063ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski     * callbacks.
1073ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski     * @hide
1083ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski     */
1093ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski    public Configuration getOverrideConfiguration() {
1103ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski        return mOverrideConfiguration;
1113ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski    }
1123ad1b4899fcf38de92b6ac8d84e55a738f0baad9Adam Lesinski
113756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    @Override
11499bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette    public AssetManager getAssets() {
11599bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette        // Ensure we're returning assets with the correct configuration.
116713a5cdb5347afa6556385f81ba972e1773f8e8fAlan Viverette        return getResourcesInternal().getAssets();
11799bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette    }
11899bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette
11999bf63fdafb011ccdd9b2315f73b351f28970644Alan Viverette    @Override
120756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    public Resources getResources() {
121713a5cdb5347afa6556385f81ba972e1773f8e8fAlan Viverette        return getResourcesInternal();
122713a5cdb5347afa6556385f81ba972e1773f8e8fAlan Viverette    }
123713a5cdb5347afa6556385f81ba972e1773f8e8fAlan Viverette
124713a5cdb5347afa6556385f81ba972e1773f8e8fAlan Viverette    private Resources getResourcesInternal() {
12504067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette        if (mResources == null) {
12604067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette            if (mOverrideConfiguration == null) {
12704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette                mResources = super.getResources();
12804067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette            } else {
12904067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette                final Context resContext = createConfigurationContext(mOverrideConfiguration);
13004067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette                mResources = resContext.getResources();
13104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette            }
132756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn        }
13304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette        return mResources;
134756220bd1912535840388a6743830d2e59ad4964Dianne Hackborn    }
13504067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette
136cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette    @Override
137cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette    public void setTheme(int resid) {
138cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette        if (mThemeResource != resid) {
139cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette            mThemeResource = resid;
140cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette            initializeTheme();
141cc2a1d48a0e4134823c940291f5db6fd9f2ae9b3Alan Viverette        }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette
144247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    /** @hide */
145247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    @Override
146247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    public int getThemeResId() {
147247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn        return mThemeResource;
148247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn    }
149247fe74c934cb3fba85aae7e051a8044f460fb11Dianne Hackborn
15004067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    @Override
15104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    public Resources.Theme getTheme() {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTheme != null) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mTheme;
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1565effd7e89f83824ac8982a6cbcebbf5cc331e436Alan Viverette        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
157d922ae01ca99a2b6d39a9393f86776a1d10ebd14Dianne Hackborn                getApplicationInfo().targetSdkVersion);
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeTheme();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTheme;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    @Override
16404067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    public Object getSystemService(String name) {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mInflater == null) {
167ebb9f3a1a3cb405dac7f98815b37c198c65739cdFabrice Di Meglio                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mInflater;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
171ebb9f3a1a3cb405dac7f98815b37c198c65739cdFabrice Di Meglio        return getBaseContext().getSystemService(name);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
17604067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * resource to the current Theme object. May be overridden to change the
17704067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * default (simple) behavior. This method will not be called in multiple
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * threads simultaneously.
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
18004067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param theme the theme being modified
18104067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param resId the style resource being applied to <var>theme</var>
18204067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     * @param first {@code true} if this is the first time a style is being
18304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette     *              applied to <var>theme</var>
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18504067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette    protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
18604067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette        theme.applyStyle(resId, true);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void initializeTheme() {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean first = mTheme == null;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (first) {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTheme = getResources().newTheme();
19304067f33c80b03eec74eee0e42c55ee40ce24f6aAlan Viverette            final Resources.Theme theme = getBaseContext().getTheme();
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (theme != null) {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTheme.setTo(theme);
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onApplyThemeResource(mTheme, mThemeResource, first);
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
202