ScrimController.java revision ecc798e6668046c2f67cf30c6ab1db2eba80cab1
1ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi/*
2ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
3ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi *
4ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
5ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * you may not use this file except in compliance with the License.
6ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * You may obtain a copy of the License at
7ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi *
8ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
9ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi *
10ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
11ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
12ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * See the License for the specific language governing permissions and
14ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * limitations under the License
15ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi */
16ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
17ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggipackage com.android.systemui.statusbar.phone;
18ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
19ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.animation.Animator;
20ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.animation.AnimatorListenerAdapter;
21ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.animation.ValueAnimator;
22ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.content.res.Resources;
23ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.graphics.Color;
24ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.graphics.drawable.ColorDrawable;
25ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.View;
26ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.ViewTreeObserver;
27ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.animation.AccelerateInterpolator;
28ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.animation.AnimationUtils;
29ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.animation.DecelerateInterpolator;
30ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.animation.Interpolator;
31ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggiimport android.view.animation.LinearInterpolator;
32ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
33ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi/**
34ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * Controls both the scrim behind the notifications and in front of the notifications (when a
35ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi * security method gets shown).
36ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi */
37ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggipublic class ScrimController implements ViewTreeObserver.OnPreDrawListener {
38ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
39ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private static final float SCRIM_BEHIND_ALPHA = 0.62f;
40ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.5f;
41ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
42ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private static final long ANIMATION_DURATION = 220;
43ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
44ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private final View mScrimBehind;
45ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private final View mScrimInFront;
46ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private final UnlockMethodCache mUnlockMethodCache;
47ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
48ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private boolean mKeyguardShowing;
49ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private float mFraction;
50ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
51ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private boolean mDarkenWhileDragging;
52ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private boolean mBouncerShowing;
53ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private boolean mAnimateChange;
54ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private boolean mUpdatePending;
55ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
56ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private final Interpolator mInterpolator = new DecelerateInterpolator();
57ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
58ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public ScrimController(View scrimBehind, View scrimInFront) {
59ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mScrimBehind = scrimBehind;
60ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mScrimInFront = scrimInFront;
61ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mUnlockMethodCache = UnlockMethodCache.getInstance(scrimBehind.getContext());
62ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
63ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
64ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public void setKeyguardShowing(boolean showing) {
65ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mKeyguardShowing = showing;
66ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        scheduleUpdate();
67ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
68ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
69ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public void onTrackingStarted() {
70ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mDarkenWhileDragging = !mUnlockMethodCache.isMethodInsecure();
71ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
72ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
73ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public void setPanelExpansion(float fraction) {
74ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mFraction = fraction;
75ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        scheduleUpdate();
76ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
77ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
78ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public void setBouncerShowing(boolean showing) {
79ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mBouncerShowing = showing;
80ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mAnimateChange = true;
81ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        scheduleUpdate();
82ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
83ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
84ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void scheduleUpdate() {
85ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (mUpdatePending) return;
86ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
87ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mUpdatePending = true;
88ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
89ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
90ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void updateScrims() {
91ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (!mKeyguardShowing) {
92ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            updateScrimNormal();
93ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimInFrontColor(0);
94ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
95ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            updateScrimKeyguard();
96ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
97ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mAnimateChange = false;
98ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
99ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
100ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void updateScrimKeyguard() {
101ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (mBouncerShowing) {
102ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
103ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimBehindColor(0f);
104ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else if (mDarkenWhileDragging) {
105ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            float behindFraction = Math.max(0, Math.min(mFraction, 1));
106ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            float fraction = 1 - behindFraction;
107ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimInFrontColor(fraction * SCRIM_IN_FRONT_ALPHA);
108ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimBehindColor(behindFraction * SCRIM_BEHIND_ALPHA_KEYGUARD);
109ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
110ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimInFrontColor(0f);
111ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimBehindColor(SCRIM_BEHIND_ALPHA_KEYGUARD);
112ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
113ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
114ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
115ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void updateScrimNormal() {
116ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        float frac = mFraction;
117ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        // let's start this 20% of the way down the screen
118ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        frac = frac * 1.2f - 0.2f;
119ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (frac <= 0) {
120ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimBehindColor(0);
121ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
122ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            // woo, special effects
123ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
124ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            setScrimBehindColor(k * SCRIM_BEHIND_ALPHA);
125ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
126ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
127ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
128ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void setScrimBehindColor(float alpha) {
129ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        setScrimColor(mScrimBehind, alpha);
130ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
131ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
132ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void setScrimInFrontColor(float alpha) {
133ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        setScrimColor(mScrimInFront, alpha);
134ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (alpha == 0f) {
135ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            mScrimInFront.setClickable(false);
136ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
137ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
138ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            // Eat touch events.
139ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            mScrimInFront.setClickable(true);
140ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
141ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
142ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
143ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void setScrimColor(View scrim, float alpha) {
144ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        int color = Color.argb((int) (alpha * 255), 0, 0, 0);
145ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (mAnimateChange) {
146ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            startScrimAnimation(scrim, color);
147ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
148ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            scrim.setBackgroundColor(color);
149ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
150ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
151ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
152ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private void startScrimAnimation(final View scrim, int targetColor) {
153ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        int current = getBackgroundAlpha(scrim);
154ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        int target = Color.alpha(targetColor);
155ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (current == targetColor) {
156ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            return;
157ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
158ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        ValueAnimator anim = ValueAnimator.ofInt(current, target);
159ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
160ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            @Override
161ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            public void onAnimationUpdate(ValueAnimator animation) {
162ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi                int value = (int) animation.getAnimatedValue();
163ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi                scrim.setBackgroundColor(Color.argb(value, 0, 0, 0));
164ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            }
165ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        });
166ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        anim.setInterpolator(mInterpolator);
167ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        anim.setDuration(ANIMATION_DURATION);
168ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        anim.start();
169ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
170ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
171ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    private int getBackgroundAlpha(View scrim) {
172ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        if (scrim.getBackground() instanceof ColorDrawable) {
173ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            ColorDrawable drawable = (ColorDrawable) scrim.getBackground();
174ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            return Color.alpha(drawable.getColor());
175ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        } else {
176ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi            return 0;
177ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        }
178ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
179ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi
180ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    @Override
181ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    public boolean onPreDraw() {
182ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
183ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        mUpdatePending = false;
184ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        updateScrims();
185ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi        return true;
186ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi    }
187ecc798e6668046c2f67cf30c6ab1db2eba80cab1Jorim Jaggi}
188