1 /*
2  * Copyright (C) 2019 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 com.android.settings.widget;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.res.ColorStateList;
22 import android.content.res.Resources;
23 import android.content.res.Resources.Theme;
24 import android.content.res.TypedArray;
25 import android.graphics.drawable.DrawableWrapper;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 
29 import com.android.settings.R;
30 
31 import org.xmlpull.v1.XmlPullParser;
32 import org.xmlpull.v1.XmlPullParserException;
33 
34 import java.io.IOException;
35 
36 /**
37  * A Drawable that tints a contained Drawable, overriding the existing tint specified in the
38  * underlying drawable. This class should only be used in XML.
39  *
40  * @attr ref android.R.styleable#DrawableWrapper_drawable
41  * @attr ref R.styleable#TintDrawable_tint
42  */
43 public class TintDrawable extends DrawableWrapper {
44     private ColorStateList mTint;
45     private int[] mThemeAttrs;
46 
47     /** No-arg constructor used by drawable inflation. */
TintDrawable()48     public TintDrawable() {
49         super(null);
50     }
51 
52     @Override
inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)53     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
54             @NonNull AttributeSet attrs, @Nullable Theme theme)
55             throws XmlPullParserException, IOException {
56         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.TintDrawable);
57 
58         super.inflate(r, parser, attrs, theme);
59 
60         mThemeAttrs = a.extractThemeAttrs();
61         updateStateFromTypedArray(a);
62         a.recycle();
63 
64         applyTint();
65     }
66 
67     @Override
applyTheme(Theme t)68     public void applyTheme(Theme t) {
69         super.applyTheme(t);
70 
71         if (mThemeAttrs != null) {
72             final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.TintDrawable);
73             updateStateFromTypedArray(a);
74             a.recycle();
75         }
76 
77         // Ensure tint is reapplied after applying the theme to ensure this drawables'
78         // tint overrides the underlying drawables' tint.
79         applyTint();
80     }
81 
82     @Override
canApplyTheme()83     public boolean canApplyTheme() {
84         return (mThemeAttrs != null && mThemeAttrs.length > 0) || super.canApplyTheme();
85     }
86 
updateStateFromTypedArray(@onNull TypedArray a)87     private void updateStateFromTypedArray(@NonNull TypedArray a) {
88         if (a.hasValue(R.styleable.TintDrawable_android_drawable)) {
89             setDrawable(a.getDrawable(R.styleable.TintDrawable_android_drawable));
90         }
91         if (a.hasValue(R.styleable.TintDrawable_android_tint)) {
92             mTint = a.getColorStateList(R.styleable.TintDrawable_android_tint);
93         }
94     }
95 
applyTint()96     private void applyTint() {
97         if (getDrawable() != null && mTint != null) {
98             getDrawable().mutate().setTintList(mTint);
99         }
100     }
101 }
102