• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.systemui.util;
18 
19 import android.content.res.ColorStateList;
20 import android.content.res.Resources;
21 import android.content.res.Resources.Theme;
22 import android.content.res.TypedArray;
23 import android.graphics.drawable.Drawable;
24 import android.graphics.drawable.DrawableWrapper;
25 import android.graphics.drawable.InsetDrawable;
26 import android.util.AttributeSet;
27 
28 import androidx.annotation.NonNull;
29 import androidx.annotation.Nullable;
30 
31 import com.android.systemui.R;
32 
33 import org.xmlpull.v1.XmlPullParser;
34 import org.xmlpull.v1.XmlPullParserException;
35 
36 import java.io.IOException;
37 
38 /**
39  * An extension of {@link DrawableWrapper} that supports alpha and tint XML properties.
40  *
41  * {@link DrawableWrapper} supports setting these properties programmatically, but doesn't expose
42  * corresponding XML properties for some reason. This class allows to set these values in the XML,
43  * supporting theming.
44  *
45  * This class should only be used in XML.
46  *
47  * @attr ref android.R.styleable#DrawableWrapper_drawable
48  * @attr ref R.styleable#AlphaTintDrawableWrapper_tint
49  * @attr ref R.styleable#AlphaTintDrawableWrapper_alpha
50  */
51 public class AlphaTintDrawableWrapper extends InsetDrawable {
52     private ColorStateList mTint;
53     private int[] mThemeAttrs;
54 
55     /** No-arg constructor used by drawable inflation. */
AlphaTintDrawableWrapper()56     public AlphaTintDrawableWrapper() {
57         super(null, 0);
58     }
59 
AlphaTintDrawableWrapper(Drawable drawable, int[] themeAttrs)60     AlphaTintDrawableWrapper(Drawable drawable, int[] themeAttrs) {
61         super(drawable, 0);
62         mThemeAttrs = themeAttrs;
63     }
64 
65     @Override
inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)66     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
67             @NonNull AttributeSet attrs, @Nullable Theme theme)
68             throws XmlPullParserException, IOException {
69         final TypedArray a = obtainAttributes(r, theme, attrs,
70                 R.styleable.AlphaTintDrawableWrapper);
71 
72         super.inflate(r, parser, attrs, theme);
73 
74         mThemeAttrs = a.extractThemeAttrs();
75         updateStateFromTypedArray(a);
76         a.recycle();
77 
78         applyTint();
79     }
80 
81     @Override
applyTheme(Theme t)82     public void applyTheme(Theme t) {
83         super.applyTheme(t);
84 
85         if (mThemeAttrs != null && t != null) {
86             final TypedArray a = t.resolveAttributes(mThemeAttrs,
87                     R.styleable.AlphaTintDrawableWrapper);
88             updateStateFromTypedArray(a);
89             a.recycle();
90         }
91 
92         // Ensure tint is reapplied after applying the theme to ensure this drawables'
93         // tint overrides the underlying drawables' tint.
94         applyTint();
95     }
96 
97     @Override
canApplyTheme()98     public boolean canApplyTheme() {
99         return (mThemeAttrs != null && mThemeAttrs.length > 0) || super.canApplyTheme();
100     }
101 
updateStateFromTypedArray(@onNull TypedArray a)102     private void updateStateFromTypedArray(@NonNull TypedArray a) {
103         if (a.hasValue(R.styleable.AlphaTintDrawableWrapper_android_tint)) {
104             mTint = a.getColorStateList(R.styleable.AlphaTintDrawableWrapper_android_tint);
105         }
106         if (a.hasValue(R.styleable.AlphaTintDrawableWrapper_android_alpha)) {
107             float alpha = a.getFloat(R.styleable.AlphaTintDrawableWrapper_android_alpha, 1);
108             setAlpha(Math.round(alpha * 255));
109         }
110     }
111 
112     @Override
setTintList(ColorStateList tint)113     public void setTintList(ColorStateList tint) {
114         super.setTintList(tint);
115         mTint = tint;
116     }
117 
applyTint()118     private void applyTint() {
119         if (getDrawable() != null && mTint != null) {
120             getDrawable().mutate().setTintList(mTint);
121         }
122     }
123 
124     @Nullable
125     @Override
getConstantState()126     public ConstantState getConstantState() {
127         return new AlphaTintState(super.getConstantState(), mThemeAttrs, getAlpha(), mTint);
128     }
129 
130     static class AlphaTintState extends Drawable.ConstantState {
131 
132         private ConstantState mWrappedState;
133         private int[] mThemeAttrs;
134         private int mAlpha;
135         private ColorStateList mColorStateList;
136 
AlphaTintState( ConstantState wrappedState, int[] themeAttrs, int alpha, ColorStateList colorStateList )137         AlphaTintState(
138                 ConstantState wrappedState,
139                 int[] themeAttrs,
140                 int alpha,
141                 ColorStateList colorStateList
142         ) {
143             mWrappedState = wrappedState;
144             mThemeAttrs = themeAttrs;
145             mAlpha = alpha;
146             mColorStateList = colorStateList;
147         }
148 
149         @NonNull
150         @Override
newDrawable()151         public Drawable newDrawable() {
152             return newDrawable(null, null);
153         }
154 
155         @NonNull
156         @Override
newDrawable(Resources res, Theme theme)157         public Drawable newDrawable(Resources res, Theme theme) {
158             DrawableWrapper wrapper = (DrawableWrapper) mWrappedState.newDrawable(res, theme);
159             AlphaTintDrawableWrapper alphaTintDrawableWrapper =
160                     new AlphaTintDrawableWrapper(wrapper.getDrawable(), mThemeAttrs);
161             alphaTintDrawableWrapper.setTintList(mColorStateList);
162             alphaTintDrawableWrapper.setAlpha(mAlpha);
163             return alphaTintDrawableWrapper;
164         }
165 
166         @Override
canApplyTheme()167         public boolean canApplyTheme() {
168             return true;
169         }
170 
171         @Override
getChangingConfigurations()172         public int getChangingConfigurations() {
173             return mWrappedState.getChangingConfigurations();
174         }
175     }
176 }
177