DozeScrimController.java revision 5fb4b98bdd33475703f8928699c8a6b91fd06550
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 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 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 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. */ 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 */ 106 public void abortPulsing() { 107 cancelPulsing(); 108 if (mDozing) { 109 mScrimController.setDozeBehindAlpha(1f); 110 mScrimController.setDozeInFrontAlpha(1f); 111 } 112 } 113 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 124 public boolean isPulsing() { 125 return mPulseCallback != null; 126 } 127 128 public boolean isDozing() { 129 return mDozing; 130 } 131 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 142 private void pulseStarted() { 143 if (mPulseCallback != null) { 144 mPulseCallback.onPulseStarted(); 145 } 146 } 147 148 private void pulseFinished() { 149 if (mPulseCallback != null) { 150 mPulseCallback.onPulseFinished(); 151 mPulseCallback = null; 152 } 153 } 154 155 private void abortAnimations() { 156 if (mInFrontAnimator != null) { 157 mInFrontAnimator.cancel(); 158 } 159 if (mBehindAnimator != null) { 160 mBehindAnimator.cancel(); 161 } 162 } 163 164 private void startScrimAnimation(final boolean inFront, float target, long duration, 165 Interpolator interpolator) { 166 startScrimAnimation(inFront, target, duration, interpolator, null /* endRunnable */); 167 } 168 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 203 private float getCurrentTarget(boolean inFront) { 204 return inFront ? mInFrontTarget : mBehindTarget; 205 } 206 207 private void setCurrentTarget(boolean inFront, float target) { 208 if (inFront) { 209 mInFrontTarget = target; 210 } else { 211 mBehindTarget = target; 212 } 213 } 214 215 private Animator getCurrentAnimator(boolean inFront) { 216 return inFront ? mInFrontAnimator : mBehindAnimator; 217 } 218 219 private void setCurrentAnimator(boolean inFront, Animator animator) { 220 if (inFront) { 221 mInFrontAnimator = animator; 222 } else { 223 mBehindAnimator = animator; 224 } 225 } 226 227 private void setDozeAlpha(boolean inFront, float alpha) { 228 if (inFront) { 229 mScrimController.setDozeInFrontAlpha(alpha); 230 } else { 231 mScrimController.setDozeBehindAlpha(alpha); 232 } 233 } 234 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