1a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek/*
2a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * Copyright (C) 2014 The Android Open Source Project
3a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek *
4a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * Licensed under the Apache License, Version 2.0 (the "License");
5a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * you may not use this file except in compliance with the License.
6a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * You may obtain a copy of the License at
7a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek *
8a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek *      http://www.apache.org/licenses/LICENSE-2.0
9a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek *
10a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * Unless required by applicable law or agreed to in writing, software
11a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * distributed under the License is distributed on an "AS IS" BASIS,
12a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * See the License for the specific language governing permissions and
14a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * limitations under the License
15a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek */
16a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
17a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekpackage com.android.systemui.statusbar;
18a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
19a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.animation.Animator;
20a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.animation.AnimatorListenerAdapter;
21a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.animation.ValueAnimator;
22a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.content.Context;
23a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.graphics.Canvas;
24a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.graphics.Color;
256811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinekimport android.graphics.Paint;
26a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.graphics.PorterDuff;
276811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinekimport android.graphics.PorterDuffXfermode;
286811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinekimport android.graphics.Rect;
29a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.util.AttributeSet;
30a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.view.View;
31a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekimport android.view.animation.Interpolator;
32a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
33a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek/**
34a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek * A view which can draw a scrim
35a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek */
36a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinekpublic class ScrimView extends View
37a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek{
386811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek    private final Paint mPaint = new Paint();
39a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private int mScrimColor;
402bc5406d7aa78a24f907e45690525e6633a78f21Jorim Jaggi    private boolean mIsEmpty = true;
41a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private boolean mDrawAsSrc;
42a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private float mViewAlpha = 1.0f;
43a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private ValueAnimator mAlphaAnimator;
446811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek    private Rect mExcludedRect = new Rect();
456811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek    private boolean mHasExcludedArea;
46a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
47a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            = new ValueAnimator.AnimatorUpdateListener() {
48a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        @Override
49a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        public void onAnimationUpdate(ValueAnimator animation) {
50a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mViewAlpha = (float) animation.getAnimatedValue();
51a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            invalidate();
52a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
53a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    };
54a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
55a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        @Override
56a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        public void onAnimationEnd(Animator animation) {
57a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mAlphaAnimator = null;
58a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
59a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    };
60d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    private Runnable mChangeRunnable;
61a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
62a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public ScrimView(Context context) {
63a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        this(context, null);
64a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
65a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
66a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public ScrimView(Context context, AttributeSet attrs) {
67a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        this(context, attrs, 0);
68a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
69a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
70a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public ScrimView(Context context, AttributeSet attrs, int defStyleAttr) {
71a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        this(context, attrs, defStyleAttr, 0);
72a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
73a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
74a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
75a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        super(context, attrs, defStyleAttr, defStyleRes);
76a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
77a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
78a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    @Override
79a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    protected void onDraw(Canvas canvas) {
800e66439387e36876de94a60658917a7f3b0e6d27Jorim Jaggi        if (mDrawAsSrc || (!mIsEmpty && mViewAlpha > 0f)) {
81a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
82d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            int color = getScrimColorWithAlpha();
836811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            if (!mHasExcludedArea) {
846811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                canvas.drawColor(color, mode);
856811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            } else {
866811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                mPaint.setColor(color);
876811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                if (mExcludedRect.top > 0) {
886811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                    canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
896811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                }
906811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                if (mExcludedRect.left > 0) {
916811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                    canvas.drawRect(0,  mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
926811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                            mPaint);
936811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                }
946811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                if (mExcludedRect.right < getWidth()) {
956811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                    canvas.drawRect(mExcludedRect.right,
966811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                            mExcludedRect.top,
976811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                            getWidth(),
986811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                            mExcludedRect.bottom,
996811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                            mPaint);
1006811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                }
1016811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                if (mExcludedRect.bottom < getHeight()) {
1026811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                    canvas.drawRect(0,  mExcludedRect.bottom, getWidth(), getHeight(), mPaint);
1036811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                }
1046811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            }
105a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
106a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
107a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
108d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    public int getScrimColorWithAlpha() {
109d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        int color = mScrimColor;
110d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
111d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek                Color.green(color), Color.blue(color));
112d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        return color;
113d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    }
114d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek
115a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public void setDrawAsSrc(boolean asSrc) {
116a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mDrawAsSrc = asSrc;
1176811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek        mPaint.setXfermode(new PorterDuffXfermode(mDrawAsSrc ? PorterDuff.Mode.SRC
1186811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek                : PorterDuff.Mode.SRC_OVER));
119a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        invalidate();
120a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
121a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
122a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public void setScrimColor(int color) {
123a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        if (color != mScrimColor) {
124a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mIsEmpty = Color.alpha(color) == 0;
125a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mScrimColor = color;
126a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            invalidate();
127d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            if (mChangeRunnable != null) {
128d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek                mChangeRunnable.run();
129d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            }
130a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
131a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
132a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
133a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public int getScrimColor() {
134a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        return mScrimColor;
135a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
136a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
137a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    @Override
138a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public boolean hasOverlappingRendering() {
139a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        return false;
140a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
141a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
142a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public void setViewAlpha(float alpha) {
143a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        if (mAlphaAnimator != null) {
144a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mAlphaAnimator.cancel();
145a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
146d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        if (alpha != mViewAlpha) {
147d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            mViewAlpha = alpha;
148d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            invalidate();
149d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            if (mChangeRunnable != null) {
150d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek                mChangeRunnable.run();
151d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek            }
152d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        }
153a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
154a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek
155a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
156a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        if (mAlphaAnimator != null) {
157a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek            mAlphaAnimator.cancel();
158a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        }
159a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator = ValueAnimator.ofFloat(mViewAlpha, alpha);
160a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator.addUpdateListener(mAlphaUpdateListener);
161a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator.addListener(mClearAnimatorListener);
162a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator.setInterpolator(interpolator);
163a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator.setDuration(durationOut);
164a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek        mAlphaAnimator.start();
165a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek    }
1666811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek
1676811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek    public void setExcludedArea(Rect area) {
1686811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek        if (area == null) {
1696811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            mHasExcludedArea = false;
1706811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            invalidate();
1716811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek            return;
1726811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek        }
173936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi
174936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        int left = Math.max(area.left, 0);
175936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        int top = Math.max(area.top, 0);
176936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        int right = Math.min(area.right, getWidth());
177936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        int bottom = Math.min(area.bottom, getHeight());
178936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        mExcludedRect.set(left, top, right, bottom);
179936233c78e7c6e6e21c876af70b1d5374d4c063aJorim Jaggi        mHasExcludedArea = left < right && top < bottom;
1806811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek        invalidate();
1816811d728fb988a32cbfc836b768a261a7f60c98aSelim Cinek    }
182d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek
183d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    public void setChangeRunnable(Runnable changeRunnable) {
184d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek        mChangeRunnable = changeRunnable;
185d35c2793a3f4986f0513c17d729bdca57086c994Selim Cinek    }
186a0fad3ba06d0352f640532e69ed3d540b3795535Selim Cinek}
187