[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.res.ColorStateList;
20import android.graphics.PorterDuff;
21import android.graphics.drawable.Drawable;
22import android.os.Build;
23import android.support.annotation.NonNull;
24import android.support.v4.view.ViewCompat;
25import android.support.v7.appcompat.R;
26import android.util.AttributeSet;
27import android.view.View;
28
29class AppCompatBackgroundHelper {
30
31    private final View mView;
32    private final AppCompatDrawableManager mDrawableManager;
33
34    private TintInfo mInternalBackgroundTint;
35    private TintInfo mBackgroundTint;
36    private TintInfo mTmpInfo;
37
38    AppCompatBackgroundHelper(View view, AppCompatDrawableManager drawableManager) {
39        mView = view;
40        mDrawableManager = drawableManager;
41    }
42
43    void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
44        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
45                R.styleable.ViewBackgroundHelper, defStyleAttr, 0);
46        try {
47            if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) {
48                ColorStateList tint = mDrawableManager.getTintList(mView.getContext(),
49                        a.getResourceId(R.styleable.ViewBackgroundHelper_android_background, -1));
50                if (tint != null) {
51                    setInternalBackgroundTint(tint);
52                }
53            }
54            if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTint)) {
55                ViewCompat.setBackgroundTintList(mView,
56                        a.getColorStateList(R.styleable.ViewBackgroundHelper_backgroundTint));
57            }
58            if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTintMode)) {
59                ViewCompat.setBackgroundTintMode(mView,
60                        DrawableUtils.parseTintMode(
61                                a.getInt(R.styleable.ViewBackgroundHelper_backgroundTintMode, -1),
62                                null));
63            }
64        } finally {
65            a.recycle();
66        }
67    }
68
69    void onSetBackgroundResource(int resId) {
70        // Update the default background tint
71        setInternalBackgroundTint(mDrawableManager != null
72                ? mDrawableManager.getTintList(mView.getContext(), resId)
73                : null);
74    }
75
76    void onSetBackgroundDrawable(Drawable background) {
77        // We don't know that this drawable is, so we need to clear the default background tint
78        setInternalBackgroundTint(null);
79    }
80
81    void setSupportBackgroundTintList(ColorStateList tint) {
82        if (mBackgroundTint == null) {
83            mBackgroundTint = new TintInfo();
84        }
85        mBackgroundTint.mTintList = tint;
86        mBackgroundTint.mHasTintList = true;
87
88        applySupportBackgroundTint();
89    }
90
91    ColorStateList getSupportBackgroundTintList() {
92        return mBackgroundTint != null ? mBackgroundTint.mTintList : null;
93    }
94
95    void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) {
96        if (mBackgroundTint == null) {
97            mBackgroundTint = new TintInfo();
98        }
99        mBackgroundTint.mTintMode = tintMode;
100        mBackgroundTint.mHasTintMode = true;
101
102        applySupportBackgroundTint();
103    }
104
105    PorterDuff.Mode getSupportBackgroundTintMode() {
106        return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
107    }
108
109    void applySupportBackgroundTint() {
110        final Drawable background = mView.getBackground();
111        if (background != null) {
112            if (Build.VERSION.SDK_INT == 21 && applyFrameworkTintUsingColorFilter(background)) {
113                // GradientDrawable doesn't implement setTintList on API 21, and since there is
114                // no nice way to unwrap DrawableContainers we have to blanket apply this
115                // on API 21. This needs to be called before the internal tints below so it takes
116                // effect on any widgets using the compat tint on API 21 (EditText)
117                return;
118            }
119
120            if (mBackgroundTint != null) {
121                AppCompatDrawableManager.tintDrawable(background, mBackgroundTint,
122                        mView.getDrawableState());
123            } else if (mInternalBackgroundTint != null) {
124                AppCompatDrawableManager.tintDrawable(background, mInternalBackgroundTint,
125                        mView.getDrawableState());
126            }
127        }
128    }
129
130    void setInternalBackgroundTint(ColorStateList tint) {
131        if (tint != null) {
132            if (mInternalBackgroundTint == null) {
133                mInternalBackgroundTint = new TintInfo();
134            }
135            mInternalBackgroundTint.mTintList = tint;
136            mInternalBackgroundTint.mHasTintList = true;
137        } else {
138            mInternalBackgroundTint = null;
139        }
140        applySupportBackgroundTint();
141    }
142
143    /**
144     * Applies the framework background tint to a view, but using the compat method (ColorFilter)
145     *
146     * @return true if a tint was applied
147     */
148    private boolean applyFrameworkTintUsingColorFilter(@NonNull Drawable background) {
149        if (mTmpInfo == null) {
150            mTmpInfo = new TintInfo();
151        }
152        final TintInfo info = mTmpInfo;
153        info.clear();
154
155        final ColorStateList tintList = ViewCompat.getBackgroundTintList(mView);
156        if (tintList != null) {
157            info.mHasTintList = true;
158            info.mTintList = tintList;
159        }
160        final PorterDuff.Mode mode = ViewCompat.getBackgroundTintMode(mView);
161        if (mode != null) {
162            info.mHasTintMode = true;
163            info.mTintMode = mode;
164        }
165
166        if (info.mHasTintList || info.mHasTintMode) {
167            AppCompatDrawableManager.tintDrawable(background, info, mView.getDrawableState());
168            return true;
169        }
170
171        return false;
172    }
173}
174