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 64 public ScrimView(Context context) { 65 this(context, null); 66 } 67 68 public ScrimView(Context context, AttributeSet attrs) { 69 this(context, attrs, 0); 70 } 71 72 public ScrimView(Context context, AttributeSet attrs, int defStyleAttr) { 73 this(context, attrs, defStyleAttr, 0); 74 } 75 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 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 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 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 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 143 public int getScrimColor() { 144 return mScrimColor; 145 } 146 147 @Override 148 public boolean hasOverlappingRendering() { 149 return false; 150 } 151 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 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 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