• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ValueAnimator;
22 import android.annotation.NonNull;
23 import android.content.Context;
24 import android.os.Handler;
25 import android.util.Log;
26 import android.view.animation.Interpolator;
27 
28 import com.android.systemui.Interpolators;
29 import com.android.systemui.doze.DozeHost;
30 import com.android.systemui.doze.DozeLog;
31 
32 /**
33  * Controller which handles all the doze animations of the scrims.
34  */
35 public class DozeScrimController {
36     private static final String TAG = "DozeScrimController";
37     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
38 
39     private final DozeParameters mDozeParameters;
40     private final Handler mHandler = new Handler();
41     private final ScrimController mScrimController;
42 
43     private boolean mDozing;
44     private DozeHost.PulseCallback mPulseCallback;
45     private int mPulseReason;
46     private Animator mInFrontAnimator;
47     private Animator mBehindAnimator;
48     private float mInFrontTarget;
49     private float mBehindTarget;
50 
DozeScrimController(ScrimController scrimController, Context context)51     public DozeScrimController(ScrimController scrimController, Context context) {
52         mScrimController = scrimController;
53         mDozeParameters = new DozeParameters(context);
54     }
55 
setDozing(boolean dozing, boolean animate)56     public void setDozing(boolean dozing, boolean animate) {
57         if (mDozing == dozing) return;
58         mDozing = dozing;
59         if (mDozing) {
60             abortAnimations();
61             mScrimController.setDozeBehindAlpha(1f);
62             mScrimController.setDozeInFrontAlpha(1f);
63         } else {
64             cancelPulsing();
65             if (animate) {
66                 startScrimAnimation(false /* inFront */, 0f /* target */,
67                         NotificationPanelView.DOZE_ANIMATION_DURATION,
68                         Interpolators.LINEAR_OUT_SLOW_IN);
69                 startScrimAnimation(true /* inFront */, 0f /* target */,
70                         NotificationPanelView.DOZE_ANIMATION_DURATION,
71                         Interpolators.LINEAR_OUT_SLOW_IN);
72             } else {
73                 abortAnimations();
74                 mScrimController.setDozeBehindAlpha(0f);
75                 mScrimController.setDozeInFrontAlpha(0f);
76             }
77         }
78     }
79 
80     /** When dozing, fade screen contents in and out using the front scrim. */
pulse(@onNull DozeHost.PulseCallback callback, int reason)81     public void pulse(@NonNull DozeHost.PulseCallback callback, int reason) {
82         if (callback == null) {
83             throw new IllegalArgumentException("callback must not be null");
84         }
85 
86         if (!mDozing || mPulseCallback != null) {
87             // Pulse suppressed.
88             callback.onPulseFinished();
89             return;
90         }
91 
92         // Begin pulse.  Note that it's very important that the pulse finished callback
93         // be invoked when we're done so that the caller can drop the pulse wakelock.
94         mPulseCallback = callback;
95         mPulseReason = reason;
96         mHandler.post(mPulseIn);
97     }
98 
99     /**
100      * Aborts pulsing immediately.
101      */
abortPulsing()102     public void abortPulsing() {
103         cancelPulsing();
104         if (mDozing) {
105             mScrimController.setDozeBehindAlpha(1f);
106             mScrimController.setDozeInFrontAlpha(1f);
107         }
108     }
109 
onScreenTurnedOn()110     public void onScreenTurnedOn() {
111         if (isPulsing()) {
112             final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
113             startScrimAnimation(true /* inFront */, 0f,
114                     mDozeParameters.getPulseInDuration(pickup),
115                     pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
116                     mPulseInFinished);
117         }
118     }
119 
isPulsing()120     public boolean isPulsing() {
121         return mPulseCallback != null;
122     }
123 
isDozing()124     public boolean isDozing() {
125         return mDozing;
126     }
127 
cancelPulsing()128     private void cancelPulsing() {
129         if (DEBUG) Log.d(TAG, "Cancel pulsing");
130 
131         if (mPulseCallback != null) {
132             mHandler.removeCallbacks(mPulseIn);
133             mHandler.removeCallbacks(mPulseOut);
134             pulseFinished();
135         }
136     }
137 
pulseStarted()138     private void pulseStarted() {
139         if (mPulseCallback != null) {
140             mPulseCallback.onPulseStarted();
141         }
142     }
143 
pulseFinished()144     private void pulseFinished() {
145         if (mPulseCallback != null) {
146             mPulseCallback.onPulseFinished();
147             mPulseCallback = null;
148         }
149     }
150 
abortAnimations()151     private void abortAnimations() {
152         if (mInFrontAnimator != null) {
153             mInFrontAnimator.cancel();
154         }
155         if (mBehindAnimator != null) {
156             mBehindAnimator.cancel();
157         }
158     }
159 
startScrimAnimation(final boolean inFront, float target, long duration, Interpolator interpolator)160     private void startScrimAnimation(final boolean inFront, float target, long duration,
161             Interpolator interpolator) {
162         startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
163     }
164 
startScrimAnimation(final boolean inFront, float target, long duration, Interpolator interpolator, final Runnable endRunnable)165     private void startScrimAnimation(final boolean inFront, float target, long duration,
166             Interpolator interpolator, final Runnable endRunnable) {
167         Animator current = getCurrentAnimator(inFront);
168         if (current != null) {
169             float currentTarget = getCurrentTarget(inFront);
170             if (currentTarget == target) {
171                 return;
172             }
173             current.cancel();
174         }
175         ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target);
176         anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
177             @Override
178             public void onAnimationUpdate(ValueAnimator animation) {
179                 float value = (float) animation.getAnimatedValue();
180                 setDozeAlpha(inFront, value);
181             }
182         });
183         anim.setInterpolator(interpolator);
184         anim.setDuration(duration);
185         anim.addListener(new AnimatorListenerAdapter() {
186             @Override
187             public void onAnimationEnd(Animator animation) {
188                 setCurrentAnimator(inFront, null);
189                 if (endRunnable != null) {
190                     endRunnable.run();
191                 }
192             }
193         });
194         anim.start();
195         setCurrentAnimator(inFront, anim);
196         setCurrentTarget(inFront, target);
197     }
198 
getCurrentTarget(boolean inFront)199     private float getCurrentTarget(boolean inFront) {
200         return inFront ? mInFrontTarget : mBehindTarget;
201     }
202 
setCurrentTarget(boolean inFront, float target)203     private void setCurrentTarget(boolean inFront, float target) {
204         if (inFront) {
205             mInFrontTarget = target;
206         } else {
207             mBehindTarget = target;
208         }
209     }
210 
getCurrentAnimator(boolean inFront)211     private Animator getCurrentAnimator(boolean inFront) {
212         return inFront ? mInFrontAnimator : mBehindAnimator;
213     }
214 
setCurrentAnimator(boolean inFront, Animator animator)215     private void setCurrentAnimator(boolean inFront, Animator animator) {
216         if (inFront) {
217             mInFrontAnimator = animator;
218         } else {
219             mBehindAnimator = animator;
220         }
221     }
222 
setDozeAlpha(boolean inFront, float alpha)223     private void setDozeAlpha(boolean inFront, float alpha) {
224         if (inFront) {
225             mScrimController.setDozeInFrontAlpha(alpha);
226         } else {
227             mScrimController.setDozeBehindAlpha(alpha);
228         }
229     }
230 
getDozeAlpha(boolean inFront)231     private float getDozeAlpha(boolean inFront) {
232         return inFront
233                 ? mScrimController.getDozeInFrontAlpha()
234                 : mScrimController.getDozeBehindAlpha();
235     }
236 
237     private final Runnable mPulseIn = new Runnable() {
238         @Override
239         public void run() {
240             if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
241                     + DozeLog.pulseReasonToString(mPulseReason));
242             if (!mDozing) return;
243             DozeLog.tracePulseStart(mPulseReason);
244 
245             // Signal that the pulse is ready to turn the screen on and draw.
246             pulseStarted();
247         }
248     };
249 
250     private final Runnable mPulseInFinished = new Runnable() {
251         @Override
252         public void run() {
253             if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
254             if (!mDozing) return;
255             mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
256         }
257     };
258 
259     private final Runnable mPulseOut = new Runnable() {
260         @Override
261         public void run() {
262             if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
263             if (!mDozing) return;
264             startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
265                     Interpolators.ALPHA_IN, mPulseOutFinished);
266         }
267     };
268 
269     private final Runnable mPulseOutFinished = new Runnable() {
270         @Override
271         public void run() {
272             if (DEBUG) Log.d(TAG, "Pulse out finished");
273             DozeLog.tracePulseFinish();
274 
275             // Signal that the pulse is all finished so we can turn the screen off now.
276             pulseFinished();
277         }
278     };
279 }
280