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