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