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