2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.systemui.statusbar.phone;
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;
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;
36 * Controller which handles all the doze animations of the scrims.
38 public class DozeScrimController {
39 private static final String TAG = "DozeScrimController";
40 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
42 private final DozeParameters mDozeParameters;
43 private final Handler mHandler = new Handler();
44 private final ScrimController mScrimController;
46 private final Context mContext;
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;
59 private float mAodFrontScrimOpacity = 0;
61 public DozeScrimController(ScrimController scrimController, Context context) {
63 mScrimController = scrimController;
64 mDozeParameters = new DozeParameters(context);
67 public void setDozing(boolean dozing, boolean animate) {
68 if (mDozing == dozing) return;
70 mWakeAndUnlocking = false;
72 mDozingAborted = false;
74 mScrimController.setDozeBehindAlpha(1f);
75 mScrimController.setDozeInFrontAlpha(
76 mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
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);
88 mScrimController.setDozeBehindAlpha(0f);
89 mScrimController.setDozeInFrontAlpha(0f);
95 * Set the opacity of the front scrim when showing AOD1
97 * Used to emulate lower brightness values than the hardware supports natively.
99 public void setAodDimmingScrim(float scrimOpacity) {
100 mAodFrontScrimOpacity = scrimOpacity;
101 if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
102 && mDozeParameters.getAlwaysOn()) {
103 mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
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);
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");
123 if (!mDozing || mPulseCallback != null) {
125 callback.onPulseFinished();
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);
138 * Aborts pulsing immediately.
140 public void abortPulsing() {
142 if (mDozing && !mWakeAndUnlocking) {
143 mScrimController.setDozeBehindAlpha(1f);
144 mScrimController.setDozeInFrontAlpha(
145 mDozeParameters.getAlwaysOn() && !mDozingAborted ?
146 mAodFrontScrimOpacity : 1f);
151 * Aborts dozing immediately.
153 public void abortDoze() {
154 mDozingAborted = true;
158 public void pulseOutNow() {
159 if (mPulseCallback != null && mFullyPulsing) {
164 public void onScreenTurnedOn() {
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,
175 public boolean isPulsing() {
176 return mPulseCallback != null;
179 public boolean isDozing() {
183 public void extendPulse() {
184 mHandler.removeCallbacks(mPulseOut);
187 private void cancelPulsing() {
188 if (DEBUG) Log.d(TAG, "Cancel pulsing");
190 if (mPulseCallback != null) {
191 mFullyPulsing = false;
192 mHandler.removeCallbacks(mPulseIn);
193 mHandler.removeCallbacks(mPulseOut);
194 mHandler.removeCallbacks(mPulseOutExtended);
199 private void pulseStarted() {
200 if (mPulseCallback != null) {
201 mPulseCallback.onPulseStarted();
205 private void pulseFinished() {
206 if (mPulseCallback != null) {
207 mPulseCallback.onPulseFinished();
208 mPulseCallback = null;
212 private void abortAnimations() {
213 if (mInFrontAnimator != null) {
214 mInFrontAnimator.cancel();
216 if (mBehindAnimator != null) {
217 mBehindAnimator.cancel();
221 private void startScrimAnimation(final boolean inFront, float target, long duration,
222 Interpolator interpolator) {
223 startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */);
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) {
236 ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target);
237 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
239 public void onAnimationUpdate(ValueAnimator animation) {
240 float value = (float) animation.getAnimatedValue();
241 setDozeAlpha(inFront, value);
244 anim.setInterpolator(interpolator);
245 anim.setDuration(duration);
246 anim.addListener(new AnimatorListenerAdapter() {
248 public void onAnimationEnd(Animator animation) {
249 setCurrentAnimator(inFront, null);
250 if (endRunnable != null) {
256 setCurrentAnimator(inFront, anim);
257 setCurrentTarget(inFront, target);
260 private float getCurrentTarget(boolean inFront) {
261 return inFront ? mInFrontTarget : mBehindTarget;
264 private void setCurrentTarget(boolean inFront, float target) {
266 mInFrontTarget = target;
268 mBehindTarget = target;
272 private Animator getCurrentAnimator(boolean inFront) {
273 return inFront ? mInFrontAnimator : mBehindAnimator;
276 private void setCurrentAnimator(boolean inFront, Animator animator) {
278 mInFrontAnimator = animator;
280 mBehindAnimator = animator;
284 private void setDozeAlpha(boolean inFront, float alpha) {
285 if (mWakeAndUnlocking) {
289 mScrimController.setDozeInFrontAlpha(alpha);
291 mScrimController.setDozeBehindAlpha(alpha);
295 private float getDozeAlpha(boolean inFront) {
297 ? mScrimController.getDozeInFrontAlpha()
298 : mScrimController.getDozeBehindAlpha();
301 private final Runnable mPulseIn = new Runnable() {
304 if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
305 + DozeLog.pulseReasonToString(mPulseReason));
306 if (!mDozing) return;
307 DozeLog.tracePulseStart(mPulseReason);
309 // Signal that the pulse is ready to turn the screen on and draw.
314 private final Runnable mPulseInFinished = new Runnable() {
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;
326 private final Runnable mPulseOutExtended = new Runnable() {
329 mHandler.removeCallbacks(mPulseOut);
334 private final Runnable mPulseOut = new Runnable() {
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);
348 private final Runnable mPulseOutFinished = new Runnable() {
351 if (DEBUG) Log.d(TAG, "Pulse out finished");
352 DozeLog.tracePulseFinish();
354 // Signal that the pulse is all finished so we can turn the screen off now.
356 if (mDozeParameters.getAlwaysOn()) {
357 mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);