blob: c77500a9fd70631d9d9e349620cc713137ede786 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Tor Norbye417ee5b2015-03-10 20:57:37 -070019import android.annotation.StyleRes;
Mathew Inwooda570dee2018-08-17 14:56:00 +010020import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.Context;
22import android.content.ContextWrapper;
Alan Viverette99bf63f2015-08-25 13:45:38 -040023import android.content.res.AssetManager;
Dianne Hackborn756220b2012-08-14 16:45:30 -070024import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.res.Resources;
26
27/**
Alan Viverette04067f32015-08-25 14:07:02 -040028 * A context wrapper that allows you to modify or replace the theme of the
29 * wrapped context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030 */
31public class ContextThemeWrapper extends ContextWrapper {
Mathew Inwooda570dee2018-08-17 14:56:00 +010032 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033 private int mThemeResource;
Mathew Inwooda570dee2018-08-17 14:56:00 +010034 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 private Resources.Theme mTheme;
Mathew Inwooda570dee2018-08-17 14:56:00 +010036 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 private LayoutInflater mInflater;
Dianne Hackborn756220b2012-08-14 16:45:30 -070038 private Configuration mOverrideConfiguration;
Mathew Inwooda570dee2018-08-17 14:56:00 +010039 @UnsupportedAppUsage
Dianne Hackborn756220b2012-08-14 16:45:30 -070040 private Resources mResources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
Alan Viverette04067f32015-08-25 14:07:02 -040042 /**
43 * Creates a new context wrapper with no theme and no base context.
Christopher Tate79047c62017-03-21 11:37:06 -070044 * <p class="note">
45 * <strong>Note:</strong> A base context <strong>must</strong> be attached
Alan Viverette04067f32015-08-25 14:07:02 -040046 * using {@link #attachBaseContext(Context)} before calling any other
47 * method on the newly constructed context wrapper.
48 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 public ContextThemeWrapper() {
50 super(null);
51 }
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080052
Alan Viverette04067f32015-08-25 14:07:02 -040053 /**
54 * Creates a new context wrapper with the specified theme.
55 * <p>
56 * The specified theme will be applied on top of the base context's theme.
57 * Any attributes not explicitly defined in the theme identified by
58 * <var>themeResId</var> will retain their original values.
59 *
60 * @param base the base context
61 * @param themeResId the resource ID of the theme to be applied on top of
62 * the base context's theme
63 */
Tor Norbye417ee5b2015-03-10 20:57:37 -070064 public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 super(base);
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080066 mThemeResource = themeResId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 }
68
Alan Viverette04067f32015-08-25 14:07:02 -040069 /**
70 * Creates a new context wrapper with the specified theme.
71 * <p>
72 * Unlike {@link #ContextThemeWrapper(Context, int)}, the theme passed to
73 * this constructor will completely replace the base context's theme.
74 *
75 * @param base the base context
76 * @param theme the theme against which resources should be inflated
77 */
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080078 public ContextThemeWrapper(Context base, Resources.Theme theme) {
79 super(base);
80 mTheme = theme;
81 }
82
83 @Override
84 protected void attachBaseContext(Context newBase) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 super.attachBaseContext(newBase);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 }
Dianne Hackborn756220b2012-08-14 16:45:30 -070087
88 /**
89 * Call to set an "override configuration" on this context -- this is
90 * a configuration that replies one or more values of the standard
91 * configuration that is applied to the context. See
92 * {@link Context#createConfigurationContext(Configuration)} for more
93 * information.
94 *
95 * <p>This method can only be called once, and must be called before any
Alan Viverette99bf63f2015-08-25 13:45:38 -040096 * calls to {@link #getResources()} or {@link #getAssets()} are made.
Dianne Hackborn756220b2012-08-14 16:45:30 -070097 */
98 public void applyOverrideConfiguration(Configuration overrideConfiguration) {
99 if (mResources != null) {
Alan Viverette99bf63f2015-08-25 13:45:38 -0400100 throw new IllegalStateException(
101 "getResources() or getAssets() has already been called");
Dianne Hackborn756220b2012-08-14 16:45:30 -0700102 }
103 if (mOverrideConfiguration != null) {
104 throw new IllegalStateException("Override configuration has already been set");
105 }
106 mOverrideConfiguration = new Configuration(overrideConfiguration);
107 }
108
Adam Lesinski3ad1b482016-04-01 16:41:41 -0700109 /**
110 * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
111 * callbacks.
112 * @hide
113 */
114 public Configuration getOverrideConfiguration() {
115 return mOverrideConfiguration;
116 }
117
Dianne Hackborn756220b2012-08-14 16:45:30 -0700118 @Override
Alan Viverette99bf63f2015-08-25 13:45:38 -0400119 public AssetManager getAssets() {
120 // Ensure we're returning assets with the correct configuration.
Alan Viverette713a5cd2015-12-16 15:46:32 -0500121 return getResourcesInternal().getAssets();
Alan Viverette99bf63f2015-08-25 13:45:38 -0400122 }
123
124 @Override
Dianne Hackborn756220b2012-08-14 16:45:30 -0700125 public Resources getResources() {
Alan Viverette713a5cd2015-12-16 15:46:32 -0500126 return getResourcesInternal();
127 }
128
129 private Resources getResourcesInternal() {
Alan Viverette04067f32015-08-25 14:07:02 -0400130 if (mResources == null) {
131 if (mOverrideConfiguration == null) {
132 mResources = super.getResources();
133 } else {
134 final Context resContext = createConfigurationContext(mOverrideConfiguration);
135 mResources = resContext.getResources();
136 }
Dianne Hackborn756220b2012-08-14 16:45:30 -0700137 }
Alan Viverette04067f32015-08-25 14:07:02 -0400138 return mResources;
Dianne Hackborn756220b2012-08-14 16:45:30 -0700139 }
Alan Viverette04067f32015-08-25 14:07:02 -0400140
Alan Viverettecc2a1d42015-05-01 11:28:37 -0700141 @Override
142 public void setTheme(int resid) {
143 if (mThemeResource != resid) {
144 mThemeResource = resid;
145 initializeTheme();
146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 }
Alan Viverette04067f32015-08-25 14:07:02 -0400148
Dianne Hackborn247fe742011-01-08 17:25:57 -0800149 /** @hide */
150 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100151 @UnsupportedAppUsage
Dianne Hackborn247fe742011-01-08 17:25:57 -0800152 public int getThemeResId() {
153 return mThemeResource;
154 }
155
Alan Viverette04067f32015-08-25 14:07:02 -0400156 @Override
157 public Resources.Theme getTheme() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 if (mTheme != null) {
159 return mTheme;
160 }
161
Alan Viverette5effd7e2014-05-05 12:25:33 -0700162 mThemeResource = Resources.selectDefaultTheme(mThemeResource,
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800163 getApplicationInfo().targetSdkVersion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 initializeTheme();
165
166 return mTheme;
167 }
168
Alan Viverette04067f32015-08-25 14:07:02 -0400169 @Override
170 public Object getSystemService(String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 if (LAYOUT_INFLATER_SERVICE.equals(name)) {
172 if (mInflater == null) {
Fabrice Di Meglioebb9f3a2014-03-07 17:04:52 -0800173 mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 }
175 return mInflater;
176 }
Fabrice Di Meglioebb9f3a2014-03-07 17:04:52 -0800177 return getBaseContext().getSystemService(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 }
Alan Viverette04067f32015-08-25 14:07:02 -0400179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 /**
181 * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
Alan Viverette04067f32015-08-25 14:07:02 -0400182 * resource to the current Theme object. May be overridden to change the
183 * default (simple) behavior. This method will not be called in multiple
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 * threads simultaneously.
185 *
Alan Viverette04067f32015-08-25 14:07:02 -0400186 * @param theme the theme being modified
187 * @param resId the style resource being applied to <var>theme</var>
188 * @param first {@code true} if this is the first time a style is being
189 * applied to <var>theme</var>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 */
Alan Viverette04067f32015-08-25 14:07:02 -0400191 protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
192 theme.applyStyle(resId, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 }
194
Mathew Inwooda570dee2018-08-17 14:56:00 +0100195 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private void initializeTheme() {
197 final boolean first = mTheme == null;
198 if (first) {
199 mTheme = getResources().newTheme();
Alan Viverette04067f32015-08-25 14:07:02 -0400200 final Resources.Theme theme = getBaseContext().getTheme();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 if (theme != null) {
202 mTheme.setTo(theme);
203 }
204 }
205 onApplyThemeResource(mTheme, mThemeResource, first);
206 }
207}
208