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