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.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.content.Context;
23 import android.content.res.TypedArray;
24 import android.graphics.Canvas;
25 import android.graphics.Color;
26 import android.graphics.Paint;
27 import android.graphics.PorterDuff;
28 import android.graphics.PorterDuffXfermode;
29 import android.graphics.Rect;
30 import android.util.AttributeSet;
31 import android.view.View;
32 import android.view.animation.Interpolator;
33 import com.android.systemui.R;
34 
35 /**
36  * A view which can draw a scrim
37  */
38 public class ScrimView extends View
39 {
40     private final Paint mPaint = new Paint();
41     private int mScrimColor;
42     private boolean mIsEmpty = true;
43     private boolean mDrawAsSrc;
44     private float mViewAlpha = 1.0f;
45     private ValueAnimator mAlphaAnimator;
46     private Rect mExcludedRect = new Rect();
47     private boolean mHasExcludedArea;
48     private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
49             = new ValueAnimator.AnimatorUpdateListener() {
50         @Override
51         public void onAnimationUpdate(ValueAnimator animation) {
52             mViewAlpha = (float) animation.getAnimatedValue();
53             invalidate();
54         }
55     };
56     private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
57         @Override
58         public void onAnimationEnd(Animator animation) {
59             mAlphaAnimator = null;
60         }
61     };
62     private Runnable mChangeRunnable;
63 
ScrimView(Context context)64     public ScrimView(Context context) {
65         this(context, null);
66     }
67 
ScrimView(Context context, AttributeSet attrs)68     public ScrimView(Context context, AttributeSet attrs) {
69         this(context, attrs, 0);
70     }
71 
ScrimView(Context context, AttributeSet attrs, int defStyleAttr)72     public ScrimView(Context context, AttributeSet attrs, int defStyleAttr) {
73         this(context, attrs, defStyleAttr, 0);
74     }
75 
ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)76     public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
77         super(context, attrs, defStyleAttr, defStyleRes);
78 
79         TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ScrimView);
80 
81         try {
82             mScrimColor = ta.getColor(R.styleable.ScrimView_scrimColor, Color.BLACK);
83         } finally {
84             ta.recycle();
85         }
86     }
87 
88     @Override
onDraw(Canvas canvas)89     protected void onDraw(Canvas canvas) {
90         if (mDrawAsSrc || (!mIsEmpty && mViewAlpha > 0f)) {
91             PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
92             int color = getScrimColorWithAlpha();
93             if (!mHasExcludedArea) {
94                 canvas.drawColor(color, mode);
95             } else {
96                 mPaint.setColor(color);
97                 if (mExcludedRect.top > 0) {
98                     canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
99                 }
100                 if (mExcludedRect.left > 0) {
101                     canvas.drawRect(0,  mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
102                             mPaint);
103                 }
104                 if (mExcludedRect.right < getWidth()) {
105                     canvas.drawRect(mExcludedRect.right,
106                             mExcludedRect.top,
107                             getWidth(),
108                             mExcludedRect.bottom,
109                             mPaint);
110                 }
111                 if (mExcludedRect.bottom < getHeight()) {
112                     canvas.drawRect(0,  mExcludedRect.bottom, getWidth(), getHeight(), mPaint);
113                 }
114             }
115         }
116     }
117 
getScrimColorWithAlpha()118     public int getScrimColorWithAlpha() {
119         int color = mScrimColor;
120         color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
121                 Color.green(color), Color.blue(color));
122         return color;
123     }
124 
setDrawAsSrc(boolean asSrc)125     public void setDrawAsSrc(boolean asSrc) {
126         mDrawAsSrc = asSrc;
127         mPaint.setXfermode(new PorterDuffXfermode(mDrawAsSrc ? PorterDuff.Mode.SRC
128                 : PorterDuff.Mode.SRC_OVER));
129         invalidate();
130     }
131 
setScrimColor(int color)132     public void setScrimColor(int color) {
133         if (color != mScrimColor) {
134             mIsEmpty = Color.alpha(color) == 0;
135             mScrimColor = color;
136             invalidate();
137             if (mChangeRunnable != null) {
138                 mChangeRunnable.run();
139             }
140         }
141     }
142 
getScrimColor()143     public int getScrimColor() {
144         return mScrimColor;
145     }
146 
147     @Override
hasOverlappingRendering()148     public boolean hasOverlappingRendering() {
149         return false;
150     }
151 
setViewAlpha(float alpha)152     public void setViewAlpha(float alpha) {
153         if (mAlphaAnimator != null) {
154             mAlphaAnimator.cancel();
155         }
156         if (alpha != mViewAlpha) {
157             mViewAlpha = alpha;
158             invalidate();
159             if (mChangeRunnable != null) {
160                 mChangeRunnable.run();
161             }
162         }
163     }
164 
animateViewAlpha(float alpha, long durationOut, Interpolator interpolator)165     public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
166         if (mAlphaAnimator != null) {
167             mAlphaAnimator.cancel();
168         }
169         mAlphaAnimator = ValueAnimator.ofFloat(mViewAlpha, alpha);
170         mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
171         mAlphaAnimator.addListener(mClearAnimatorListener);
172         mAlphaAnimator.setInterpolator(interpolator);
173         mAlphaAnimator.setDuration(durationOut);
174         mAlphaAnimator.start();
175     }
176 
setExcludedArea(Rect area)177     public void setExcludedArea(Rect area) {
178         if (area == null) {
179             mHasExcludedArea = false;
180             invalidate();
181             return;
182         }
183 
184         int left = Math.max(area.left, 0);
185         int top = Math.max(area.top, 0);
186         int right = Math.min(area.right, getWidth());
187         int bottom = Math.min(area.bottom, getHeight());
188         mExcludedRect.set(left, top, right, bottom);
189         mHasExcludedArea = left < right && top < bottom;
190         invalidate();
191     }
192 
193     public void setChangeRunnable(Runnable changeRunnable) {
194         mChangeRunnable = changeRunnable;
195     }
196 }
197