OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / phone / ScrimController.java
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.phone;
18
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.PropertyValuesHolder;
22 import android.animation.ValueAnimator;
23 import android.content.Context;
24 import android.graphics.Color;
25 import android.graphics.Rect;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.view.ViewTreeObserver;
29 import android.view.animation.DecelerateInterpolator;
30 import android.view.animation.Interpolator;
31 import android.view.animation.PathInterpolator;
32
33 import com.android.systemui.R;
34 import com.android.systemui.statusbar.ExpandableNotificationRow;
35 import com.android.systemui.statusbar.NotificationData;
36 import com.android.systemui.statusbar.ScrimView;
37 import com.android.systemui.statusbar.policy.HeadsUpManager;
38 import com.android.systemui.statusbar.stack.StackStateAnimator;
39
40 /**
41  * Controls both the scrim behind the notifications and in front of the notifications (when a
42  * security method gets shown).
43  */
44 public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
45         HeadsUpManager.OnHeadsUpChangedListener {
46     public static final long ANIMATION_DURATION = 220;
47     public static final Interpolator KEYGUARD_FADE_OUT_INTERPOLATOR
48             = new PathInterpolator(0f, 0, 0.7f, 1f);
49     private static final float SCRIM_BEHIND_ALPHA = 0.62f;
50     private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.45f;
51     private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
52     private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
53     private static final int TAG_KEY_ANIM = R.id.scrim;
54     private static final int TAG_KEY_ANIM_TARGET = R.id.scrim_target;
55     private static final int TAG_START_ALPHA = R.id.scrim_alpha_start;
56     private static final int TAG_END_ALPHA = R.id.scrim_alpha_end;
57
58     protected final ScrimView mScrimBehind;
59     private final ScrimView mScrimInFront;
60     private final UnlockMethodCache mUnlockMethodCache;
61     private final View mHeadsUpScrim;
62
63     private float mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
64     private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
65     private float mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
66
67     protected boolean mKeyguardShowing;
68     private float mFraction;
69
70     private boolean mDarkenWhileDragging;
71     protected boolean mBouncerShowing;
72     private boolean mWakeAndUnlocking;
73     private boolean mAnimateChange;
74     private boolean mUpdatePending;
75     private boolean mExpanding;
76     private boolean mAnimateKeyguardFadingOut;
77     private long mDurationOverride = -1;
78     private long mAnimationDelay;
79     private Runnable mOnAnimationFinished;
80     private final Interpolator mInterpolator = new DecelerateInterpolator();
81     private boolean mDozing;
82     private float mDozeInFrontAlpha;
83     private float mDozeBehindAlpha;
84     private float mCurrentInFrontAlpha;
85     private float mCurrentBehindAlpha;
86     private float mCurrentHeadsUpAlpha = 1;
87     private int mPinnedHeadsUpCount;
88     private float mTopHeadsUpDragAmount;
89     private View mDraggedHeadsUpView;
90     private boolean mForceHideScrims;
91     private boolean mSkipFirstFrame;
92     private boolean mDontAnimateBouncerChanges;
93     private boolean mKeyguardFadingOutInProgress;
94     private ValueAnimator mKeyguardFadeoutAnimation;
95
96     public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) {
97         mScrimBehind = scrimBehind;
98         mScrimInFront = scrimInFront;
99         mHeadsUpScrim = headsUpScrim;
100         final Context context = scrimBehind.getContext();
101         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
102         updateHeadsUpScrim(false);
103     }
104
105     public void setKeyguardShowing(boolean showing) {
106         mKeyguardShowing = showing;
107         scheduleUpdate();
108     }
109
110     public void setShowScrimBehind(boolean show) {
111         if (show) {
112             mScrimBehindAlpha = SCRIM_BEHIND_ALPHA;
113             mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD;
114             mScrimBehindAlphaUnlocking = SCRIM_BEHIND_ALPHA_UNLOCKING;
115         } else {
116             mScrimBehindAlpha = 0;
117             mScrimBehindAlphaKeyguard = 0;
118             mScrimBehindAlphaUnlocking = 0;
119         }
120         scheduleUpdate();
121     }
122
123     public void onTrackingStarted() {
124         mExpanding = true;
125         mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
126     }
127
128     public void onExpandingFinished() {
129         mExpanding = false;
130     }
131
132     public void setPanelExpansion(float fraction) {
133         if (mFraction != fraction) {
134             mFraction = fraction;
135             scheduleUpdate();
136             if (mPinnedHeadsUpCount != 0) {
137                 updateHeadsUpScrim(false);
138             }
139             if (mKeyguardFadeoutAnimation != null) {
140                 mKeyguardFadeoutAnimation.cancel();
141             }
142         }
143     }
144
145     public void setBouncerShowing(boolean showing) {
146         mBouncerShowing = showing;
147         mAnimateChange = !mExpanding && !mDontAnimateBouncerChanges;
148         scheduleUpdate();
149     }
150
151     public void setWakeAndUnlocking() {
152         mWakeAndUnlocking = true;
153         scheduleUpdate();
154     }
155
156     public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished,
157             boolean skipFirstFrame) {
158         mWakeAndUnlocking = false;
159         mAnimateKeyguardFadingOut = true;
160         mDurationOverride = duration;
161         mAnimationDelay = delay;
162         mAnimateChange = true;
163         mSkipFirstFrame = skipFirstFrame;
164         mOnAnimationFinished = onAnimationFinished;
165         scheduleUpdate();
166
167         // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
168         // the changes we just scheduled.
169         onPreDraw();
170     }
171
172     public void abortKeyguardFadingOut() {
173         if (mAnimateKeyguardFadingOut) {
174             endAnimateKeyguardFadingOut(true /* force */);
175         }
176     }
177
178     public void animateGoingToFullShade(long delay, long duration) {
179         mDurationOverride = duration;
180         mAnimationDelay = delay;
181         mAnimateChange = true;
182         scheduleUpdate();
183     }
184
185     public void animateNextChange() {
186         mAnimateChange = true;
187     }
188
189     public void setDozing(boolean dozing) {
190         if (mDozing != dozing) {
191             mDozing = dozing;
192             scheduleUpdate();
193         }
194     }
195
196     public void setDozeInFrontAlpha(float alpha) {
197         mDozeInFrontAlpha = alpha;
198         updateScrimColor(mScrimInFront);
199     }
200
201     public void setDozeBehindAlpha(float alpha) {
202         mDozeBehindAlpha = alpha;
203         updateScrimColor(mScrimBehind);
204     }
205
206     public float getDozeBehindAlpha() {
207         return mDozeBehindAlpha;
208     }
209
210     public float getDozeInFrontAlpha() {
211         return mDozeInFrontAlpha;
212     }
213
214     private void scheduleUpdate() {
215         if (mUpdatePending) return;
216
217         // Make sure that a frame gets scheduled.
218         mScrimBehind.invalidate();
219         mScrimBehind.getViewTreeObserver().addOnPreDrawListener(this);
220         mUpdatePending = true;
221     }
222
223     protected void updateScrims() {
224         if (mAnimateKeyguardFadingOut || mForceHideScrims) {
225             setScrimInFrontColor(0f);
226             setScrimBehindColor(0f);
227         } else if (mWakeAndUnlocking) {
228
229             // During wake and unlock, we first hide everything behind a black scrim, which then
230             // gets faded out from animateKeyguardFadingOut.
231             if (mDozing) {
232                 setScrimInFrontColor(0f);
233                 setScrimBehindColor(1f);
234             } else {
235                 setScrimInFrontColor(1f);
236                 setScrimBehindColor(0f);
237             }
238         } else if (!mKeyguardShowing && !mBouncerShowing) {
239             updateScrimNormal();
240             setScrimInFrontColor(0);
241         } else {
242             updateScrimKeyguard();
243         }
244         mAnimateChange = false;
245     }
246
247     private void updateScrimKeyguard() {
248         if (mExpanding && mDarkenWhileDragging) {
249             float behindFraction = Math.max(0, Math.min(mFraction, 1));
250             float fraction = 1 - behindFraction;
251             fraction = (float) Math.pow(fraction, 0.8f);
252             behindFraction = (float) Math.pow(behindFraction, 0.8f);
253             setScrimInFrontColor(fraction * SCRIM_IN_FRONT_ALPHA);
254             setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
255         } else if (mBouncerShowing) {
256             setScrimInFrontColor(SCRIM_IN_FRONT_ALPHA);
257             setScrimBehindColor(0f);
258         } else {
259             float fraction = Math.max(0, Math.min(mFraction, 1));
260             setScrimInFrontColor(0f);
261             setScrimBehindColor(fraction
262                     * (mScrimBehindAlphaKeyguard - mScrimBehindAlphaUnlocking)
263                     + mScrimBehindAlphaUnlocking);
264         }
265     }
266
267     private void updateScrimNormal() {
268         float frac = mFraction;
269         // let's start this 20% of the way down the screen
270         frac = frac * 1.2f - 0.2f;
271         if (frac <= 0) {
272             setScrimBehindColor(0);
273         } else {
274             // woo, special effects
275             final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
276             setScrimBehindColor(k * mScrimBehindAlpha);
277         }
278     }
279
280     private void setScrimBehindColor(float alpha) {
281         setScrimColor(mScrimBehind, alpha);
282     }
283
284     private void setScrimInFrontColor(float alpha) {
285         setScrimColor(mScrimInFront, alpha);
286         if (alpha == 0f) {
287             mScrimInFront.setClickable(false);
288         } else {
289
290             // Eat touch events (unless dozing).
291             mScrimInFront.setClickable(!mDozing);
292         }
293     }
294
295     private void setScrimColor(View scrim, float alpha) {
296         updateScrim(mAnimateChange, scrim, alpha, getCurrentScrimAlpha(scrim));
297     }
298
299     private float getDozeAlpha(View scrim) {
300         return scrim == mScrimBehind ? mDozeBehindAlpha : mDozeInFrontAlpha;
301     }
302
303     private float getCurrentScrimAlpha(View scrim) {
304         return scrim == mScrimBehind ? mCurrentBehindAlpha
305                 : scrim == mScrimInFront ? mCurrentInFrontAlpha
306                 : mCurrentHeadsUpAlpha;
307     }
308
309     private void setCurrentScrimAlpha(View scrim, float alpha) {
310         if (scrim == mScrimBehind) {
311             mCurrentBehindAlpha = alpha;
312         } else if (scrim == mScrimInFront) {
313             mCurrentInFrontAlpha = alpha;
314         } else {
315             alpha = Math.max(0.0f, Math.min(1.0f, alpha));
316             mCurrentHeadsUpAlpha = alpha;
317         }
318     }
319
320     private void updateScrimColor(View scrim) {
321         float alpha1 = getCurrentScrimAlpha(scrim);
322         if (scrim instanceof ScrimView) {
323             float alpha2 = getDozeAlpha(scrim);
324             float alpha = 1 - (1 - alpha1) * (1 - alpha2);
325             alpha = Math.max(0, Math.min(1.0f, alpha));
326             ((ScrimView) scrim).setScrimColor(Color.argb((int) (alpha * 255), 0, 0, 0));
327         } else {
328             scrim.setAlpha(alpha1);
329         }
330     }
331
332     private void startScrimAnimation(final View scrim, float target) {
333         float current = getCurrentScrimAlpha(scrim);
334         ValueAnimator anim = ValueAnimator.ofFloat(current, target);
335         anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
336             @Override
337             public void onAnimationUpdate(ValueAnimator animation) {
338                 float alpha = (float) animation.getAnimatedValue();
339                 setCurrentScrimAlpha(scrim, alpha);
340                 updateScrimColor(scrim);
341             }
342         });
343         anim.setInterpolator(getInterpolator());
344         anim.setStartDelay(mAnimationDelay);
345         anim.setDuration(mDurationOverride != -1 ? mDurationOverride : ANIMATION_DURATION);
346         anim.addListener(new AnimatorListenerAdapter() {
347             @Override
348             public void onAnimationEnd(Animator animation) {
349                 if (mOnAnimationFinished != null) {
350                     mOnAnimationFinished.run();
351                     mOnAnimationFinished = null;
352                 }
353                 if (mKeyguardFadingOutInProgress) {
354                     mKeyguardFadeoutAnimation = null;
355                     mKeyguardFadingOutInProgress = false;
356                 }
357                 scrim.setTag(TAG_KEY_ANIM, null);
358                 scrim.setTag(TAG_KEY_ANIM_TARGET, null);
359             }
360         });
361         anim.start();
362         if (mAnimateKeyguardFadingOut) {
363             mKeyguardFadingOutInProgress = true;
364             mKeyguardFadeoutAnimation = anim;
365         }
366         if (mSkipFirstFrame) {
367             anim.setCurrentPlayTime(16);
368         }
369         scrim.setTag(TAG_KEY_ANIM, anim);
370         scrim.setTag(TAG_KEY_ANIM_TARGET, target);
371     }
372
373     private Interpolator getInterpolator() {
374         return mAnimateKeyguardFadingOut ? KEYGUARD_FADE_OUT_INTERPOLATOR : mInterpolator;
375     }
376
377     @Override
378     public boolean onPreDraw() {
379         mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
380         mUpdatePending = false;
381         if (mDontAnimateBouncerChanges) {
382             mDontAnimateBouncerChanges = false;
383         }
384         updateScrims();
385         mDurationOverride = -1;
386         mAnimationDelay = 0;
387         mSkipFirstFrame = false;
388
389         // Make sure that we always call the listener even if we didn't start an animation.
390         endAnimateKeyguardFadingOut(false /* force */);
391         return true;
392     }
393
394     private void endAnimateKeyguardFadingOut(boolean force) {
395         mAnimateKeyguardFadingOut = false;
396         if (force || (!isAnimating(mScrimInFront) && !isAnimating(mScrimBehind))) {
397             if (mOnAnimationFinished != null) {
398                 mOnAnimationFinished.run();
399                 mOnAnimationFinished = null;
400             }
401             mKeyguardFadingOutInProgress = false;
402         }
403     }
404
405     private boolean isAnimating(View scrim) {
406         return scrim.getTag(TAG_KEY_ANIM) != null;
407     }
408
409     public void setDrawBehindAsSrc(boolean asSrc) {
410         mScrimBehind.setDrawAsSrc(asSrc);
411     }
412
413     @Override
414     public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
415     }
416
417     @Override
418     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
419         mPinnedHeadsUpCount++;
420         updateHeadsUpScrim(true);
421     }
422
423     @Override
424     public void onHeadsUpUnPinned(ExpandableNotificationRow headsUp) {
425         mPinnedHeadsUpCount--;
426         if (headsUp == mDraggedHeadsUpView) {
427             mDraggedHeadsUpView = null;
428             mTopHeadsUpDragAmount = 0.0f;
429         }
430         updateHeadsUpScrim(true);
431     }
432
433     @Override
434     public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
435     }
436
437     private void updateHeadsUpScrim(boolean animate) {
438         updateScrim(animate, mHeadsUpScrim, calculateHeadsUpAlpha(), mCurrentHeadsUpAlpha);
439     }
440
441     private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
442         if (mKeyguardFadingOutInProgress) {
443             return;
444         }
445
446         ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
447                 TAG_KEY_ANIM);
448         float animEndValue = -1;
449         if (previousAnimator != null) {
450             if (animate || alpha == currentAlpha) {
451                 previousAnimator.cancel();
452             } else {
453                 animEndValue = StackStateAnimator.getChildTag(scrim, TAG_END_ALPHA);
454             }
455         }
456         if (alpha != currentAlpha && alpha != animEndValue) {
457             if (animate) {
458                 startScrimAnimation(scrim, alpha);
459                 scrim.setTag(TAG_START_ALPHA, currentAlpha);
460                 scrim.setTag(TAG_END_ALPHA, alpha);
461             } else {
462                 if (previousAnimator != null) {
463                     float previousStartValue = StackStateAnimator.getChildTag(scrim,
464                             TAG_START_ALPHA);
465                     float previousEndValue = StackStateAnimator.getChildTag(scrim,
466                             TAG_END_ALPHA);
467                     // we need to increase all animation keyframes of the previous animator by the
468                     // relative change to the end value
469                     PropertyValuesHolder[] values = previousAnimator.getValues();
470                     float relativeDiff = alpha - previousEndValue;
471                     float newStartValue = previousStartValue + relativeDiff;
472                     newStartValue = Math.max(0, Math.min(1.0f, newStartValue));
473                     values[0].setFloatValues(newStartValue, alpha);
474                     scrim.setTag(TAG_START_ALPHA, newStartValue);
475                     scrim.setTag(TAG_END_ALPHA, alpha);
476                     previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
477                 } else {
478                     // update the alpha directly
479                     setCurrentScrimAlpha(scrim, alpha);
480                     updateScrimColor(scrim);
481                 }
482             }
483         }
484     }
485
486     /**
487      * Set the amount the current top heads up view is dragged. The range is from 0 to 1 and 0 means
488      * the heads up is in its resting space and 1 means it's fully dragged out.
489      *
490      * @param draggedHeadsUpView the dragged view
491      * @param topHeadsUpDragAmount how far is it dragged
492      */
493     public void setTopHeadsUpDragAmount(View draggedHeadsUpView, float topHeadsUpDragAmount) {
494         mTopHeadsUpDragAmount = topHeadsUpDragAmount;
495         mDraggedHeadsUpView = draggedHeadsUpView;
496         updateHeadsUpScrim(false);
497     }
498
499     private float calculateHeadsUpAlpha() {
500         float alpha;
501         if (mPinnedHeadsUpCount >= 2) {
502             alpha = 1.0f;
503         } else if (mPinnedHeadsUpCount == 0) {
504             alpha = 0.0f;
505         } else {
506             alpha = 1.0f - mTopHeadsUpDragAmount;
507         }
508         float expandFactor = (1.0f - mFraction);
509         expandFactor = Math.max(expandFactor, 0.0f);
510         return alpha * expandFactor;
511     }
512
513     public void forceHideScrims(boolean hide) {
514         mForceHideScrims = hide;
515         mAnimateChange = false;
516         scheduleUpdate();
517     }
518
519     public void dontAnimateBouncerChangesUntilNextFrame() {
520         mDontAnimateBouncerChanges = true;
521     }
522
523     public void setExcludedBackgroundArea(Rect area) {
524         mScrimBehind.setExcludedArea(area);
525     }
526
527     public int getScrimBehindColor() {
528         return mScrimBehind.getScrimColorWithAlpha();
529     }
530
531     public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
532         mScrimBehind.setChangeRunnable(changeRunnable);
533     }
534
535     public void onDensityOrFontScaleChanged() {
536         ViewGroup.LayoutParams layoutParams = mHeadsUpScrim.getLayoutParams();
537         layoutParams.height = mHeadsUpScrim.getResources().getDimensionPixelSize(
538                 R.dimen.heads_up_scrim_height);
539         mHeadsUpScrim.setLayoutParams(layoutParams);
540     }
541 }