OSDN Git Service

AOD: Add support for dimming in software
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / statusbar / phone / DozeScrimController.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.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.View;
27 import android.view.animation.Interpolator;
28
29 import com.android.keyguard.KeyguardStatusView;
30 import com.android.systemui.Interpolators;
31 import com.android.systemui.doze.DozeHost;
32 import com.android.systemui.doze.DozeLog;
33 import com.android.systemui.doze.DozeTriggers;
34
35 /**
36  * Controller which handles all the doze animations of the scrims.
37  */
38 public class DozeScrimController {
39     private static final String TAG = "DozeScrimController";
40     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
41
42     private final DozeParameters mDozeParameters;
43     private final Handler mHandler = new Handler();
44     private final ScrimController mScrimController;
45
46     private final Context mContext;
47
48     private boolean mDozing;
49     private DozeHost.PulseCallback mPulseCallback;
50     private int mPulseReason;
51     private Animator mInFrontAnimator;
52     private Animator mBehindAnimator;
53     private float mInFrontTarget;
54     private float mBehindTarget;
55     private boolean mDozingAborted;
56     private boolean mWakeAndUnlocking;
57     private boolean mFullyPulsing;
58
59     private float mAodFrontScrimOpacity = 0;
60
61     public DozeScrimController(ScrimController scrimController, Context context) {
62         mContext = context;
63         mScrimController = scrimController;
64         mDozeParameters = new DozeParameters(context);
65     }
66
67     public void setDozing(boolean dozing, boolean animate) {
68         if (mDozing == dozing) return;
69         mDozing = dozing;
70         mWakeAndUnlocking = false;
71         if (mDozing) {
72             mDozingAborted = false;
73             abortAnimations();
74             mScrimController.setDozeBehindAlpha(1f);
75             mScrimController.setDozeInFrontAlpha(
76                     mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
77         } else {
78             cancelPulsing();
79             if (animate) {
80                 startScrimAnimation(false /* inFront */, 0f /* target */,
81                         NotificationPanelView.DOZE_ANIMATION_DURATION,
82                         Interpolators.LINEAR_OUT_SLOW_IN);
83                 startScrimAnimation(true /* inFront */, 0f /* target */,
84                         NotificationPanelView.DOZE_ANIMATION_DURATION,
85                         Interpolators.LINEAR_OUT_SLOW_IN);
86             } else {
87                 abortAnimations();
88                 mScrimController.setDozeBehindAlpha(0f);
89                 mScrimController.setDozeInFrontAlpha(0f);
90             }
91         }
92     }
93
94     /**
95      * Set the opacity of the front scrim when showing AOD1
96      *
97      * Used to emulate lower brightness values than the hardware supports natively.
98      */
99     public void setAodDimmingScrim(float scrimOpacity) {
100         mAodFrontScrimOpacity = scrimOpacity;
101         if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
102                 && mDozeParameters.getAlwaysOn()) {
103             mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
104         }
105     }
106
107     public void setWakeAndUnlocking() {
108         // Immediately abort the doze scrims in case of wake-and-unlock
109         // for pulsing so the Keyguard fade-out animation scrim can take over.
110         if (!mWakeAndUnlocking) {
111             mWakeAndUnlocking = true;
112             mScrimController.setDozeBehindAlpha(0f);
113             mScrimController.setDozeInFrontAlpha(0f);
114         }
115     }
116
117     /** When dozing, fade screen contents in and out using the front scrim. */
118     public void pulse(@NonNull DozeHost.PulseCallback callback, int reason) {
119         if (callback == null) {
120             throw new IllegalArgumentException("callback must not be null");
121         }
122
123         if (!mDozing || mPulseCallback != null) {
124             // Pulse suppressed.
125             callback.onPulseFinished();
126             return;
127         }
128
129         // Begin pulse.  Note that it's very important that the pulse finished callback
130         // be invoked when we're done so that the caller can drop the pulse wakelock.
131         mPulseCallback = callback;
132         mPulseReason = reason;
133         mScrimController.setDozeInFrontAlpha(1f);
134         mHandler.post(mPulseIn);
135     }
136
137     /**
138      * Aborts pulsing immediately.
139      */
140     public void abortPulsing() {
141         cancelPulsing();
142         if (mDozing && !mWakeAndUnlocking) {
143             mScrimController.setDozeBehindAlpha(1f);
144             mScrimController.setDozeInFrontAlpha(
145                     mDozeParameters.getAlwaysOn() && !mDozingAborted ?
146                             mAodFrontScrimOpacity : 1f);
147         }
148     }
149
150     /**
151      * Aborts dozing immediately.
152      */
153     public void abortDoze() {
154         mDozingAborted = true;
155         abortPulsing();
156     }
157
158     public void pulseOutNow() {
159         if (mPulseCallback != null && mFullyPulsing) {
160             mPulseOut.run();
161         }
162     }
163
164     public void onScreenTurnedOn() {
165         if (isPulsing()) {
166             final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
167                     || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
168             startScrimAnimation(true /* inFront */, 0f,
169                     mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
170                     pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
171                     mPulseInFinished);
172         }
173     }
174
175     public boolean isPulsing() {
176         return mPulseCallback != null;
177     }
178
179     public boolean isDozing() {
180         return mDozing;
181     }
182
183     public void extendPulse() {
184         mHandler.removeCallbacks(mPulseOut);
185     }
186
187     private void cancelPulsing() {
188         if (DEBUG) Log.d(TAG, "Cancel pulsing");
189
190         if (mPulseCallback != null) {
191             mFullyPulsing = false;
192             mHandler.removeCallbacks(mPulseIn);
193             mHandler.removeCallbacks(mPulseOut);
194             mHandler.removeCallbacks(mPulseOutExtended);
195             pulseFinished();
196         }
197     }
198
199     private void pulseStarted() {
200         if (mPulseCallback != null) {
201             mPulseCallback.onPulseStarted();
202         }
203     }
204
205     private void pulseFinished() {
206         if (mPulseCallback != null) {
207             mPulseCallback.onPulseFinished();
208             mPulseCallback = null;
209         }
210     }
211
212     private void abortAnimations() {
213         if (mInFrontAnimator != null) {
214             mInFrontAnimator.cancel();
215         }
216         if (mBehindAnimator != null) {
217             mBehindAnimator.cancel();
218         }
219     }
220
221     private void startScrimAnimation(final boolean inFront, float target, long duration,
222             Interpolator interpolator) {
223         startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
224     }
225
226     private void startScrimAnimation(final boolean inFront, float target, long duration,
227             Interpolator interpolator, final Runnable endRunnable) {
228         Animator current = getCurrentAnimator(inFront);
229         if (current != null) {
230             float currentTarget = getCurrentTarget(inFront);
231             if (currentTarget == target) {
232                 return;
233             }
234             current.cancel();
235         }
236         ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target);
237         anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
238             @Override
239             public void onAnimationUpdate(ValueAnimator animation) {
240                 float value = (float) animation.getAnimatedValue();
241                 setDozeAlpha(inFront, value);
242             }
243         });
244         anim.setInterpolator(interpolator);
245         anim.setDuration(duration);
246         anim.addListener(new AnimatorListenerAdapter() {
247             @Override
248             public void onAnimationEnd(Animator animation) {
249                 setCurrentAnimator(inFront, null);
250                 if (endRunnable != null) {
251                     endRunnable.run();
252                 }
253             }
254         });
255         anim.start();
256         setCurrentAnimator(inFront, anim);
257         setCurrentTarget(inFront, target);
258     }
259
260     private float getCurrentTarget(boolean inFront) {
261         return inFront ? mInFrontTarget : mBehindTarget;
262     }
263
264     private void setCurrentTarget(boolean inFront, float target) {
265         if (inFront) {
266             mInFrontTarget = target;
267         } else {
268             mBehindTarget = target;
269         }
270     }
271
272     private Animator getCurrentAnimator(boolean inFront) {
273         return inFront ? mInFrontAnimator : mBehindAnimator;
274     }
275
276     private void setCurrentAnimator(boolean inFront, Animator animator) {
277         if (inFront) {
278             mInFrontAnimator = animator;
279         } else {
280             mBehindAnimator = animator;
281         }
282     }
283
284     private void setDozeAlpha(boolean inFront, float alpha) {
285         if (mWakeAndUnlocking) {
286             return;
287         }
288         if (inFront) {
289             mScrimController.setDozeInFrontAlpha(alpha);
290         } else {
291             mScrimController.setDozeBehindAlpha(alpha);
292         }
293     }
294
295     private float getDozeAlpha(boolean inFront) {
296         return inFront
297                 ? mScrimController.getDozeInFrontAlpha()
298                 : mScrimController.getDozeBehindAlpha();
299     }
300
301     private final Runnable mPulseIn = new Runnable() {
302         @Override
303         public void run() {
304             if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
305                     + DozeLog.pulseReasonToString(mPulseReason));
306             if (!mDozing) return;
307             DozeLog.tracePulseStart(mPulseReason);
308
309             // Signal that the pulse is ready to turn the screen on and draw.
310             pulseStarted();
311         }
312     };
313
314     private final Runnable mPulseInFinished = new Runnable() {
315         @Override
316         public void run() {
317             if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
318             if (!mDozing) return;
319             mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
320             mHandler.postDelayed(mPulseOutExtended,
321                     mDozeParameters.getPulseVisibleDurationExtended());
322             mFullyPulsing = true;
323         }
324     };
325
326     private final Runnable mPulseOutExtended = new Runnable() {
327         @Override
328         public void run() {
329             mHandler.removeCallbacks(mPulseOut);
330             mPulseOut.run();
331         }
332     };
333
334     private final Runnable mPulseOut = new Runnable() {
335         @Override
336         public void run() {
337             mFullyPulsing = false;
338             mHandler.removeCallbacks(mPulseOut);
339             mHandler.removeCallbacks(mPulseOutExtended);
340             if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
341             if (!mDozing) return;
342             startScrimAnimation(true /* inFront */, 1,
343                     mDozeParameters.getPulseOutDuration(),
344                     Interpolators.ALPHA_IN, mPulseOutFinished);
345         }
346     };
347
348     private final Runnable mPulseOutFinished = new Runnable() {
349         @Override
350         public void run() {
351             if (DEBUG) Log.d(TAG, "Pulse out finished");
352             DozeLog.tracePulseFinish();
353
354             // Signal that the pulse is all finished so we can turn the screen off now.
355             pulseFinished();
356             if (mDozeParameters.getAlwaysOn()) {
357                 mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
358             }
359         }
360     };
361 }