1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view; 18 19import android.content.Context; 20import android.content.ContextWrapper; 21import android.content.res.Configuration; 22import android.content.res.Resources; 23 24/** 25 * A ContextWrapper that allows you to modify the theme from what is in the 26 * wrapped context. 27 */ 28public class ContextThemeWrapper extends ContextWrapper { 29 private int mThemeResource; 30 private Resources.Theme mTheme; 31 private LayoutInflater mInflater; 32 private Configuration mOverrideConfiguration; 33 private Resources mResources; 34 35 public ContextThemeWrapper() { 36 super(null); 37 } 38 39 public ContextThemeWrapper(Context base, int themeres) { 40 super(base); 41 mThemeResource = themeres; 42 } 43 44 @Override protected void attachBaseContext(Context newBase) { 45 super.attachBaseContext(newBase); 46 } 47 48 /** 49 * Call to set an "override configuration" on this context -- this is 50 * a configuration that replies one or more values of the standard 51 * configuration that is applied to the context. See 52 * {@link Context#createConfigurationContext(Configuration)} for more 53 * information. 54 * 55 * <p>This method can only be called once, and must be called before any 56 * calls to {@link #getResources()} are made. 57 */ 58 public void applyOverrideConfiguration(Configuration overrideConfiguration) { 59 if (mResources != null) { 60 throw new IllegalStateException("getResources() has already been called"); 61 } 62 if (mOverrideConfiguration != null) { 63 throw new IllegalStateException("Override configuration has already been set"); 64 } 65 mOverrideConfiguration = new Configuration(overrideConfiguration); 66 } 67 68 @Override 69 public Resources getResources() { 70 if (mResources != null) { 71 return mResources; 72 } 73 if (mOverrideConfiguration == null) { 74 mResources = super.getResources(); 75 return mResources; 76 } else { 77 Context resc = createConfigurationContext(mOverrideConfiguration); 78 mResources = resc.getResources(); 79 return mResources; 80 } 81 } 82 83 @Override public void setTheme(int resid) { 84 mThemeResource = resid; 85 initializeTheme(); 86 } 87 88 /** @hide */ 89 @Override 90 public int getThemeResId() { 91 return mThemeResource; 92 } 93 94 @Override public Resources.Theme getTheme() { 95 if (mTheme != null) { 96 return mTheme; 97 } 98 99 mThemeResource = Resources.selectDefaultTheme(mThemeResource, 100 getApplicationInfo().targetSdkVersion); 101 initializeTheme(); 102 103 return mTheme; 104 } 105 106 @Override public Object getSystemService(String name) { 107 if (LAYOUT_INFLATER_SERVICE.equals(name)) { 108 if (mInflater == null) { 109 mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); 110 } 111 return mInflater; 112 } 113 return getBaseContext().getSystemService(name); 114 } 115 116 /** 117 * Called by {@link #setTheme} and {@link #getTheme} to apply a theme 118 * resource to the current Theme object. Can override to change the 119 * default (simple) behavior. This method will not be called in multiple 120 * threads simultaneously. 121 * 122 * @param theme The Theme object being modified. 123 * @param resid The theme style resource being applied to <var>theme</var>. 124 * @param first Set to true if this is the first time a style is being 125 * applied to <var>theme</var>. 126 */ 127 protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { 128 theme.applyStyle(resid, true); 129 } 130 131 private void initializeTheme() { 132 final boolean first = mTheme == null; 133 if (first) { 134 mTheme = getResources().newTheme(); 135 Resources.Theme theme = getBaseContext().getTheme(); 136 if (theme != null) { 137 mTheme.setTo(theme); 138 } 139 } 140 onApplyThemeResource(mTheme, mThemeResource, first); 141 } 142} 143 144