• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.statusbar;
18 
19 import android.annotation.NonNull;
20 import android.content.Context;
21 import android.graphics.Canvas;
22 import android.graphics.Color;
23 import android.graphics.PorterDuff;
24 import android.graphics.PorterDuff.Mode;
25 import android.graphics.PorterDuffColorFilter;
26 import android.graphics.drawable.Drawable;
27 import android.util.AttributeSet;
28 import android.view.View;
29 
30 import androidx.core.graphics.ColorUtils;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.internal.colorextraction.ColorExtractor;
34 import com.android.internal.colorextraction.drawable.ScrimDrawable;
35 
36 /**
37  * A view which can draw a scrim
38  */
39 public class ScrimView extends View {
40     private final ColorExtractor.GradientColors mColors;
41     private float mViewAlpha = 1.0f;
42     private Drawable mDrawable;
43     private PorterDuffColorFilter mColorFilter;
44     private int mTintColor;
45     private Runnable mChangeRunnable;
46 
ScrimView(Context context)47     public ScrimView(Context context) {
48         this(context, null);
49     }
50 
ScrimView(Context context, AttributeSet attrs)51     public ScrimView(Context context, AttributeSet attrs) {
52         this(context, attrs, 0);
53     }
54 
ScrimView(Context context, AttributeSet attrs, int defStyleAttr)55     public ScrimView(Context context, AttributeSet attrs, int defStyleAttr) {
56         this(context, attrs, defStyleAttr, 0);
57     }
58 
ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)59     public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
60         super(context, attrs, defStyleAttr, defStyleRes);
61 
62         mDrawable = new ScrimDrawable();
63         mDrawable.setCallback(this);
64         mColors = new ColorExtractor.GradientColors();
65         updateColorWithTint(false);
66     }
67 
68     @Override
onDraw(Canvas canvas)69     protected void onDraw(Canvas canvas) {
70         if (mDrawable.getAlpha() > 0) {
71             mDrawable.draw(canvas);
72         }
73     }
74 
setDrawable(Drawable drawable)75     public void setDrawable(Drawable drawable) {
76         mDrawable = drawable;
77         mDrawable.setCallback(this);
78         mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
79         mDrawable.setAlpha((int) (255 * mViewAlpha));
80         invalidate();
81     }
82 
83     @Override
invalidateDrawable(@onNull Drawable drawable)84     public void invalidateDrawable(@NonNull Drawable drawable) {
85         super.invalidateDrawable(drawable);
86         if (drawable == mDrawable) {
87             invalidate();
88         }
89     }
90 
91     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)92     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
93         super.onLayout(changed, left, top, right, bottom);
94         if (changed) {
95             mDrawable.setBounds(left, top, right, bottom);
96             invalidate();
97         }
98     }
99 
setColors(@onNull ColorExtractor.GradientColors colors)100     public void setColors(@NonNull ColorExtractor.GradientColors colors) {
101         setColors(colors, false);
102     }
103 
setColors(@onNull ColorExtractor.GradientColors colors, boolean animated)104     public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
105         if (colors == null) {
106             throw new IllegalArgumentException("Colors cannot be null");
107         }
108         if (mColors.equals(colors)) {
109             return;
110         }
111         mColors.set(colors);
112         updateColorWithTint(animated);
113     }
114 
115     @VisibleForTesting
getDrawable()116     Drawable getDrawable() {
117         return mDrawable;
118     }
119 
getColors()120     public ColorExtractor.GradientColors getColors() {
121         return mColors;
122     }
123 
setTint(int color)124     public void setTint(int color) {
125         setTint(color, false);
126     }
127 
setTint(int color, boolean animated)128     public void setTint(int color, boolean animated) {
129         if (mTintColor == color) {
130             return;
131         }
132         mTintColor = color;
133         updateColorWithTint(animated);
134     }
135 
updateColorWithTint(boolean animated)136     private void updateColorWithTint(boolean animated) {
137         if (mDrawable instanceof ScrimDrawable) {
138             // Optimization to blend colors and avoid a color filter
139             ScrimDrawable drawable = (ScrimDrawable) mDrawable;
140             float tintAmount = Color.alpha(mTintColor) / 255f;
141             int mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor,
142                     tintAmount);
143             drawable.setColor(mainTinted, animated);
144         } else {
145             boolean hasAlpha = Color.alpha(mTintColor) != 0;
146             if (hasAlpha) {
147                 PorterDuff.Mode targetMode = mColorFilter == null ? Mode.SRC_OVER :
148                     mColorFilter.getMode();
149                 if (mColorFilter == null || mColorFilter.getColor() != mTintColor) {
150                     mColorFilter = new PorterDuffColorFilter(mTintColor, targetMode);
151                 }
152             } else {
153                 mColorFilter = null;
154             }
155 
156             mDrawable.setColorFilter(mColorFilter);
157             mDrawable.invalidateSelf();
158         }
159 
160         if (mChangeRunnable != null) {
161             mChangeRunnable.run();
162         }
163     }
164 
getTint()165     public int getTint() {
166         return mTintColor;
167     }
168 
169     @Override
hasOverlappingRendering()170     public boolean hasOverlappingRendering() {
171         return false;
172     }
173 
174     /**
175      * It might look counterintuitive to have another method to set the alpha instead of
176      * only using {@link #setAlpha(float)}. In this case we're in a hardware layer
177      * optimizing blend modes, so it makes sense.
178      *
179      * @param alpha Gradient alpha from 0 to 1.
180      */
setViewAlpha(float alpha)181     public void setViewAlpha(float alpha) {
182         if (alpha != mViewAlpha) {
183             mViewAlpha = alpha;
184 
185             mDrawable.setAlpha((int) (255 * alpha));
186             if (mChangeRunnable != null) {
187                 mChangeRunnable.run();
188             }
189         }
190     }
191 
getViewAlpha()192     public float getViewAlpha() {
193         return mViewAlpha;
194     }
195 
setChangeRunnable(Runnable changeRunnable)196     public void setChangeRunnable(Runnable changeRunnable) {
197         mChangeRunnable = changeRunnable;
198     }
199 
200     @Override
canReceivePointerEvents()201     protected boolean canReceivePointerEvents() {
202         return false;
203     }
204 }
205