DozeScrimController.java revision 621afac810e83e13a131c6f8db2658edd0347208
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 public boolean isPulsing() { 104 return mPulseCallback != null; 105 } 106 107 private void cancelPulsing() { 108 if (DEBUG) Log.d(TAG, "Cancel pulsing"); 109 110 if (mPulseCallback != null) { 111 mHandler.removeCallbacks(mPulseIn); 112 mHandler.removeCallbacks(mPulseOut); 113 pulseFinished(); 114 } 115 } 116 117 private void pulseStarted() { 118 if (mPulseCallback != null) { 119 mPulseCallback.onPulseStarted(); 120 } 121 } 122 123 private void pulseFinished() { 124 if (mPulseCallback != null) { 125 mPulseCallback.onPulseFinished(); 126 mPulseCallback = null; 127 } 128 } 129 130 private void abortAnimations() { 131 if (mInFrontAnimator != null) { 132 mInFrontAnimator.cancel(); 133 } 134 if (mBehindAnimator != null) { 135 mBehindAnimator.cancel(); 136 } 137 } 138 139 private void startScrimAnimation(final boolean inFront, float target, long duration, 140 Interpolator interpolator) { 141 startScrimAnimation(inFront, target, duration, interpolator, 0 /* delay */, 142 null /* endRunnable */); 143 } 144 145 private void startScrimAnimation(final boolean inFront, float target, long duration, 146 Interpolator interpolator, long delay, final Runnable endRunnable) { 147 Animator current = getCurrentAnimator(inFront); 148 if (current != null) { 149 float currentTarget = getCurrentTarget(inFront); 150 if (currentTarget == target) { 151 return; 152 } 153 current.cancel(); 154 } 155 ValueAnimator anim = ValueAnimator.ofFloat(getDozeAlpha(inFront), target); 156 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 157 @Override 158 public void onAnimationUpdate(ValueAnimator animation) { 159 float value = (float) animation.getAnimatedValue(); 160 setDozeAlpha(inFront, value); 161 } 162 }); 163 anim.setInterpolator(interpolator); 164 anim.setDuration(duration); 165 anim.setStartDelay(delay); 166 anim.addListener(new AnimatorListenerAdapter() { 167 @Override 168 public void onAnimationEnd(Animator animation) { 169 setCurrentAnimator(inFront, null); 170 if (endRunnable != null) { 171 endRunnable.run(); 172 } 173 } 174 }); 175 anim.start(); 176 setCurrentAnimator(inFront, anim); 177 setCurrentTarget(inFront, target); 178 } 179 180 private float getCurrentTarget(boolean inFront) { 181 return inFront ? mInFrontTarget : mBehindTarget; 182 } 183 184 private void setCurrentTarget(boolean inFront, float target) { 185 if (inFront) { 186 mInFrontTarget = target; 187 } else { 188 mBehindTarget = target; 189 } 190 } 191 192 private Animator getCurrentAnimator(boolean inFront) { 193 return inFront ? mInFrontAnimator : mBehindAnimator; 194 } 195 196 private void setCurrentAnimator(boolean inFront, Animator animator) { 197 if (inFront) { 198 mInFrontAnimator = animator; 199 } else { 200 mBehindAnimator = animator; 201 } 202 } 203 204 private void setDozeAlpha(boolean inFront, float alpha) { 205 if (inFront) { 206 mScrimController.setDozeInFrontAlpha(alpha); 207 } else { 208 mScrimController.setDozeBehindAlpha(alpha); 209 } 210 } 211 212 private float getDozeAlpha(boolean inFront) { 213 return inFront 214 ? mScrimController.getDozeInFrontAlpha() 215 : mScrimController.getDozeBehindAlpha(); 216 } 217 218 private final Runnable mPulseIn = new Runnable() { 219 @Override 220 public void run() { 221 if (DEBUG) Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" 222 + DozeLog.pulseReasonToString(mPulseReason)); 223 if (!mDozing) return; 224 DozeLog.tracePulseStart(mPulseReason); 225 final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP; 226 startScrimAnimation(true /* inFront */, 0f, 227 mDozeParameters.getPulseInDuration(pickup), 228 pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator, 229 mDozeParameters.getPulseInDelay(pickup), 230 mPulseInFinished); 231 232 // Signal that the pulse is ready to turn the screen on and draw. 233 pulseStarted(); 234 } 235 }; 236 237 private final Runnable mPulseInFinished = new Runnable() { 238 @Override 239 public void run() { 240 if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); 241 if (!mDozing) return; 242 mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); 243 } 244 }; 245 246 private final Runnable mPulseOut = new Runnable() { 247 @Override 248 public void run() { 249 if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); 250 if (!mDozing) return; 251 startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(), 252 mPulseOutInterpolator, 0 /* delay */, mPulseOutFinished); 253 } 254 }; 255 256 private final Runnable mPulseOutFinished = new Runnable() { 257 @Override 258 public void run() { 259 if (DEBUG) Log.d(TAG, "Pulse out finished"); 260 DozeLog.tracePulseFinish(); 261 262 // Signal that the pulse is all finished so we can turn the screen off now. 263 pulseFinished(); 264 } 265 }; 266} 267