DozeScrimController.java revision 048af1f727dc81a6450e004391d072599ac449ee
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.graphics.Color; 25import android.os.Handler; 26import android.util.Log; 27import android.view.animation.Animation; 28import android.view.animation.AnimationUtils; 29import android.view.animation.Interpolator; 30 31import com.android.systemui.doze.DozeHost; 32import com.android.systemui.doze.DozeLog; 33 34/** 35 * Controller which handles all the doze animations of the scrims. 36 */ 37public class DozeScrimController { 38 private static final String TAG = "DozeScrimController"; 39 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 40 41 private final DozeParameters mDozeParameters; 42 private final Interpolator mPulseInInterpolator = PhoneStatusBar.ALPHA_OUT; 43 private final Interpolator mPulseOutInterpolator = PhoneStatusBar.ALPHA_IN; 44 private final Interpolator mDozeAnimationInterpolator; 45 private final Handler mHandler = new Handler(); 46 private final ScrimController mScrimController; 47 48 private boolean mDozing; 49 private DozeHost.PulseCallback mPulseCallback; 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 = AnimationUtils.loadInterpolator(context, 59 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) { 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 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); 221 if (!mDozing) return; 222 DozeLog.tracePulseStart(); 223 startScrimAnimation(true /* inFront */, 0f, mDozeParameters.getPulseInDuration(), 224 mPulseInInterpolator, mDozeParameters.getPulseInDelay(), mPulseInFinished); 225 226 // Signal that the pulse is ready to turn the screen on and draw. 227 pulseStarted(); 228 } 229 }; 230 231 private final Runnable mPulseInFinished = new Runnable() { 232 @Override 233 public void run() { 234 if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); 235 if (!mDozing) return; 236 mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); 237 } 238 }; 239 240 private final Runnable mPulseOut = new Runnable() { 241 @Override 242 public void run() { 243 if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); 244 if (!mDozing) return; 245 startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(), 246 mPulseOutInterpolator, 0 /* delay */, mPulseOutFinished); 247 } 248 }; 249 250 private final Runnable mPulseOutFinished = new Runnable() { 251 @Override 252 public void run() { 253 if (DEBUG) Log.d(TAG, "Pulse out finished"); 254 DozeLog.tracePulseFinish(); 255 256 // Signal that the pulse is all finished so we can turn the screen off now. 257 pulseFinished(); 258 } 259 }; 260} 261