[go: nahoru, domu]

1/*
2 * Copyright (C) 2015 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.support.v7.widget;
18
19import android.content.Context;
20import android.content.ContextWrapper;
21import android.content.res.Resources;
22import android.os.Build;
23import android.support.annotation.NonNull;
24import android.support.v7.app.AppCompatDelegate;
25import android.support.v7.widget.VectorEnabledTintResources;
26
27import java.lang.ref.WeakReference;
28import java.util.ArrayList;
29
30/**
31 * A {@link android.content.ContextWrapper} which returns a tint-aware
32 * {@link android.content.res.Resources} instance from {@link #getResources()}.
33 *
34 * @hide
35 */
36public class TintContextWrapper extends ContextWrapper {
37
38    private static final ArrayList<WeakReference<TintContextWrapper>> sCache = new ArrayList<>();
39
40    public static Context wrap(@NonNull final Context context) {
41        if (shouldWrap(context)) {
42            // First check our instance cache
43            for (int i = 0, count = sCache.size(); i < count; i++) {
44                final WeakReference<TintContextWrapper> ref = sCache.get(i);
45                final TintContextWrapper wrapper = ref != null ? ref.get() : null;
46                if (wrapper != null && wrapper.getBaseContext() == context) {
47                    return wrapper;
48                }
49            }
50            // If we reach here then the cache didn't have a hit, so create a new instance
51            // and add it to the cache
52            final TintContextWrapper wrapper = new TintContextWrapper(context);
53            sCache.add(new WeakReference<>(wrapper));
54            return wrapper;
55        }
56
57        return context;
58    }
59
60    private static boolean shouldWrap(@NonNull final Context context) {
61        if (context instanceof TintContextWrapper
62                || context.getResources() instanceof TintResources
63                || context.getResources() instanceof VectorEnabledTintResources) {
64            // If the Context already has a TintResources[Experimental] impl, no need to wrap again
65            // If the Context is already a TintContextWrapper, no need to wrap again
66            return false;
67        }
68        if (AppCompatDelegate.isCompatVectorFromResourcesEnabled()
69                && Build.VERSION.SDK_INT > VectorEnabledTintResources.MAX_SDK_WHERE_REQUIRED) {
70            // If we're running on API 21+ and have the vector resources enabled, there's
71            // no need to wrap
72            return false;
73        }
74        // Else, we should wrap
75        return true;
76    }
77
78    private Resources mResources;
79    private final Resources.Theme mTheme;
80
81    private TintContextWrapper(@NonNull final Context base) {
82        super(base);
83
84        if (VectorEnabledTintResources.shouldBeUsed()) {
85            // We need to create a copy of the Theme so that the Theme references our Resources
86            // instance
87            mTheme = getResources().newTheme();
88            mTheme.setTo(base.getTheme());
89        } else {
90            mTheme = null;
91        }
92    }
93
94    @Override
95    public Resources.Theme getTheme() {
96        return mTheme == null ? super.getTheme() : mTheme;
97    }
98
99    @Override
100    public void setTheme(int resid) {
101        if (mTheme == null) {
102            super.setTheme(resid);
103        } else {
104            mTheme.applyStyle(resid, true);
105        }
106    }
107
108    @Override
109    public Resources getResources() {
110        if (mResources == null) {
111            mResources = (mTheme == null)
112                    ? new TintResources(this, super.getResources())
113                    : new VectorEnabledTintResources(this, super.getResources());
114        }
115        return mResources;
116    }
117}