blob: 876331b5c57f292a2f0985ac3354be2ba6dc7460 [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
Nader Jawada1eef722019-02-06 14:52:39 -080019import android.annotation.Nullable;
Tor Norbye417ee5b2015-03-10 20:57:37 -070020import android.annotation.StyleRes;
Artur Satayevad9254c2019-12-10 17:47:54 +000021import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
23import android.content.ContextWrapper;
Alan Viverette99bf63f2015-08-25 13:45:38 -040024import android.content.res.AssetManager;
Dianne Hackborn756220b2012-08-14 16:45:30 -070025import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.res.Resources;
Nader Jawada1eef722019-02-06 14:52:39 -080027import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29/**
Alan Viverette04067f32015-08-25 14:07:02 -040030 * A context wrapper that allows you to modify or replace the theme of the
31 * wrapped context.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032 */
33public class ContextThemeWrapper extends ContextWrapper {
Mathew Inwooda570dee2018-08-17 14:56:00 +010034 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 private int mThemeResource;
Nader Jawada1eef722019-02-06 14:52:39 -080036 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768723)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 private Resources.Theme mTheme;
Mathew Inwooda570dee2018-08-17 14:56:00 +010038 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private LayoutInflater mInflater;
Dianne Hackborn756220b2012-08-14 16:45:30 -070040 private Configuration mOverrideConfiguration;
Mathew Inwooda570dee2018-08-17 14:56:00 +010041 @UnsupportedAppUsage
Dianne Hackborn756220b2012-08-14 16:45:30 -070042 private Resources mResources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
Alan Viverette04067f32015-08-25 14:07:02 -040044 /**
45 * Creates a new context wrapper with no theme and no base context.
Christopher Tate79047c62017-03-21 11:37:06 -070046 * <p class="note">
47 * <strong>Note:</strong> A base context <strong>must</strong> be attached
Alan Viverette04067f32015-08-25 14:07:02 -040048 * using {@link #attachBaseContext(Context)} before calling any other
49 * method on the newly constructed context wrapper.
50 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 public ContextThemeWrapper() {
52 super(null);
53 }
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080054
Alan Viverette04067f32015-08-25 14:07:02 -040055 /**
56 * Creates a new context wrapper with the specified theme.
57 * <p>
58 * The specified theme will be applied on top of the base context's theme.
59 * Any attributes not explicitly defined in the theme identified by
60 * <var>themeResId</var> will retain their original values.
61 *
62 * @param base the base context
63 * @param themeResId the resource ID of the theme to be applied on top of
64 * the base context's theme
65 */
Tor Norbye417ee5b2015-03-10 20:57:37 -070066 public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 super(base);
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080068 mThemeResource = themeResId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 }
70
Alan Viverette04067f32015-08-25 14:07:02 -040071 /**
72 * Creates a new context wrapper with the specified theme.
73 * <p>
74 * Unlike {@link #ContextThemeWrapper(Context, int)}, the theme passed to
75 * this constructor will completely replace the base context's theme.
76 *
77 * @param base the base context
78 * @param theme the theme against which resources should be inflated
79 */
Alan Viveretteb9ead4a2015-01-14 10:43:31 -080080 public ContextThemeWrapper(Context base, Resources.Theme theme) {
81 super(base);
82 mTheme = theme;
83 }
84
85 @Override
86 protected void attachBaseContext(Context newBase) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 super.attachBaseContext(newBase);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 }
Dianne Hackborn756220b2012-08-14 16:45:30 -070089
90 /**
91 * Call to set an "override configuration" on this context -- this is
92 * a configuration that replies one or more values of the standard
93 * configuration that is applied to the context. See
94 * {@link Context#createConfigurationContext(Configuration)} for more
95 * information.
96 *
97 * <p>This method can only be called once, and must be called before any
Alan Viverette99bf63f2015-08-25 13:45:38 -040098 * calls to {@link #getResources()} or {@link #getAssets()} are made.
Dianne Hackborn756220b2012-08-14 16:45:30 -070099 */
100 public void applyOverrideConfiguration(Configuration overrideConfiguration) {
101 if (mResources != null) {
Alan Viverette99bf63f2015-08-25 13:45:38 -0400102 throw new IllegalStateException(
103 "getResources() or getAssets() has already been called");
Dianne Hackborn756220b2012-08-14 16:45:30 -0700104 }
105 if (mOverrideConfiguration != null) {
106 throw new IllegalStateException("Override configuration has already been set");
107 }
108 mOverrideConfiguration = new Configuration(overrideConfiguration);
109 }
110
Adam Lesinski3ad1b482016-04-01 16:41:41 -0700111 /**
112 * Used by ActivityThread to apply the overridden configuration to onConfigurationChange
113 * callbacks.
114 * @hide
115 */
116 public Configuration getOverrideConfiguration() {
117 return mOverrideConfiguration;
118 }
119
Dianne Hackborn756220b2012-08-14 16:45:30 -0700120 @Override
Alan Viverette99bf63f2015-08-25 13:45:38 -0400121 public AssetManager getAssets() {
122 // Ensure we're returning assets with the correct configuration.
Alan Viverette713a5cd2015-12-16 15:46:32 -0500123 return getResourcesInternal().getAssets();
Alan Viverette99bf63f2015-08-25 13:45:38 -0400124 }
125
126 @Override
Dianne Hackborn756220b2012-08-14 16:45:30 -0700127 public Resources getResources() {
Alan Viverette713a5cd2015-12-16 15:46:32 -0500128 return getResourcesInternal();
129 }
130
131 private Resources getResourcesInternal() {
Alan Viverette04067f32015-08-25 14:07:02 -0400132 if (mResources == null) {
133 if (mOverrideConfiguration == null) {
134 mResources = super.getResources();
135 } else {
136 final Context resContext = createConfigurationContext(mOverrideConfiguration);
137 mResources = resContext.getResources();
138 }
Dianne Hackborn756220b2012-08-14 16:45:30 -0700139 }
Alan Viverette04067f32015-08-25 14:07:02 -0400140 return mResources;
Dianne Hackborn756220b2012-08-14 16:45:30 -0700141 }
Alan Viverette04067f32015-08-25 14:07:02 -0400142
Alan Viverettecc2a1d42015-05-01 11:28:37 -0700143 @Override
144 public void setTheme(int resid) {
145 if (mThemeResource != resid) {
146 mThemeResource = resid;
147 initializeTheme();
148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 }
Alan Viverette04067f32015-08-25 14:07:02 -0400150
Nader Jawada1eef722019-02-06 14:52:39 -0800151 /**
152 * Set the configure the current theme. If null is provided then the default Theme is returned
153 * on the next call to {@link #getTheme()}
154 * @param theme Theme to consume in the wrapper, a value of null resets the theme to the default
155 */
156 public void setTheme(@Nullable Resources.Theme theme) {
157 mTheme = theme;
158 }
159
Dianne Hackborn247fe742011-01-08 17:25:57 -0800160 /** @hide */
161 @Override
Mathew Inwooda570dee2018-08-17 14:56:00 +0100162 @UnsupportedAppUsage
Dianne Hackborn247fe742011-01-08 17:25:57 -0800163 public int getThemeResId() {
164 return mThemeResource;
165 }
166
Alan Viverette04067f32015-08-25 14:07:02 -0400167 @Override
168 public Resources.Theme getTheme() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 if (mTheme != null) {
170 return mTheme;
171 }
172
Alan Viverette5effd7e2014-05-05 12:25:33 -0700173 mThemeResource = Resources.selectDefaultTheme(mThemeResource,
Dianne Hackbornd922ae02011-01-14 11:43:24 -0800174 getApplicationInfo().targetSdkVersion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 initializeTheme();
176
177 return mTheme;
178 }
179
Alan Viverette04067f32015-08-25 14:07:02 -0400180 @Override
181 public Object getSystemService(String name) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 if (LAYOUT_INFLATER_SERVICE.equals(name)) {
183 if (mInflater == null) {
Fabrice Di Meglioebb9f3a2014-03-07 17:04:52 -0800184 mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 }
186 return mInflater;
187 }
Fabrice Di Meglioebb9f3a2014-03-07 17:04:52 -0800188 return getBaseContext().getSystemService(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 }
Alan Viverette04067f32015-08-25 14:07:02 -0400190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /**
192 * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
Alan Viverette04067f32015-08-25 14:07:02 -0400193 * resource to the current Theme object. May be overridden to change the
194 * default (simple) behavior. This method will not be called in multiple
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 * threads simultaneously.
196 *
Alan Viverette04067f32015-08-25 14:07:02 -0400197 * @param theme the theme being modified
198 * @param resId the style resource being applied to <var>theme</var>
199 * @param first {@code true} if this is the first time a style is being
200 * applied to <var>theme</var>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 */
Alan Viverette04067f32015-08-25 14:07:02 -0400202 protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
203 theme.applyStyle(resId, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 }
205
Mathew Inwooda570dee2018-08-17 14:56:00 +0100206 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 private void initializeTheme() {
208 final boolean first = mTheme == null;
209 if (first) {
210 mTheme = getResources().newTheme();
Alan Viverette04067f32015-08-25 14:07:02 -0400211 final Resources.Theme theme = getBaseContext().getTheme();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 if (theme != null) {
213 mTheme.setTo(theme);
214 }
215 }
216 onApplyThemeResource(mTheme, mThemeResource, first);
217 }
218}
219