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