Home | History | Annotate | Download | only in view
      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