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 17 package android.view; 18 19 import android.content.Context; 20 import android.content.ContextWrapper; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.os.Build; 24 25 /** 26 * A ContextWrapper that allows you to modify the theme from what is in the 27 * wrapped context. 28 */ 29 public class ContextThemeWrapper extends ContextWrapper { 30 private Context mBase; 31 private int mThemeResource; 32 private Resources.Theme mTheme; 33 private LayoutInflater mInflater; 34 private Configuration mOverrideConfiguration; 35 private Resources mResources; 36 37 public ContextThemeWrapper() { 38 super(null); 39 } 40 41 public ContextThemeWrapper(Context base, int themeres) { 42 super(base); 43 mBase = base; 44 mThemeResource = themeres; 45 } 46 47 @Override protected void attachBaseContext(Context newBase) { 48 super.attachBaseContext(newBase); 49 mBase = newBase; 50 } 51 52 /** 53 * Call to set an "override configuration" on this context -- this is 54 * a configuration that replies one or more values of the standard 55 * configuration that is applied to the context. See 56 * {@link Context#createConfigurationContext(Configuration)} for more 57 * information. 58 * 59 * <p>This method can only be called once, and must be called before any 60 * calls to {@link #getResources()} are made. 61 */ 62 public void applyOverrideConfiguration(Configuration overrideConfiguration) { 63 if (mResources != null) { 64 throw new IllegalStateException("getResources() has already been called"); 65 } 66 if (mOverrideConfiguration != null) { 67 throw new IllegalStateException("Override configuration has already been set"); 68 } 69 mOverrideConfiguration = new Configuration(overrideConfiguration); 70 } 71 72 @Override 73 public Resources getResources() { 74 if (mResources != null) { 75 return mResources; 76 } 77 if (mOverrideConfiguration == null) { 78 mResources = super.getResources(); 79 return mResources; 80 } else { 81 Context resc = createConfigurationContext(mOverrideConfiguration); 82 mResources = resc.getResources(); 83 return mResources; 84 } 85 } 86 87 @Override public void setTheme(int resid) { 88 mThemeResource = resid; 89 initializeTheme(); 90 } 91 92 /** @hide */ 93 @Override 94 public int getThemeResId() { 95 return mThemeResource; 96 } 97 98 @Override public Resources.Theme getTheme() { 99 if (mTheme != null) { 100 return mTheme; 101 } 102 103 mThemeResource = Resources.selectDefaultTheme(mThemeResource, 104 getApplicationInfo().targetSdkVersion); 105 initializeTheme(); 106 107 return mTheme; 108 } 109 110 @Override public Object getSystemService(String name) { 111 if (LAYOUT_INFLATER_SERVICE.equals(name)) { 112 if (mInflater == null) { 113 mInflater = LayoutInflater.from(mBase).cloneInContext(this); 114 } 115 return mInflater; 116 } 117 return mBase.getSystemService(name); 118 } 119 120 /** 121 * Called by {@link #setTheme} and {@link #getTheme} to apply a theme 122 * resource to the current Theme object. Can override to change the 123 * default (simple) behavior. This method will not be called in multiple 124 * threads simultaneously. 125 * 126 * @param theme The Theme object being modified. 127 * @param resid The theme style resource being applied to <var>theme</var>. 128 * @param first Set to true if this is the first time a style is being 129 * applied to <var>theme</var>. 130 */ 131 protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { 132 theme.applyStyle(resid, true); 133 } 134 135 private void initializeTheme() { 136 final boolean first = mTheme == null; 137 if (first) { 138 mTheme = getResources().newTheme(); 139 Resources.Theme theme = mBase.getTheme(); 140 if (theme != null) { 141 mTheme.setTo(theme); 142 } 143 } 144 onApplyThemeResource(mTheme, mThemeResource, first); 145 } 146 } 147 148