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 17 package com.android.systemui.statusbar.phone; 18 19 import android.annotation.NonNull; 20 import android.os.Handler; 21 import android.util.Log; 22 23 import com.android.internal.annotations.VisibleForTesting; 24 import com.android.systemui.Dependency; 25 import com.android.systemui.doze.DozeHost; 26 import com.android.systemui.doze.DozeLog; 27 import com.android.systemui.plugins.statusbar.StatusBarStateController; 28 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; 29 30 import javax.inject.Inject; 31 import javax.inject.Singleton; 32 33 /** 34 * Controller which handles all the doze animations of the scrims. 35 */ 36 @Singleton 37 public class DozeScrimController implements StateListener { 38 private static final String TAG = "DozeScrimController"; 39 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 40 41 private final DozeLog mDozeLog; 42 private final DozeParameters mDozeParameters; 43 private final Handler mHandler = new Handler(); 44 45 private boolean mDozing; 46 private DozeHost.PulseCallback mPulseCallback; 47 private int mPulseReason; 48 private boolean mFullyPulsing; 49 50 private final ScrimController.Callback mScrimCallback = new ScrimController.Callback() { 51 @Override 52 public void onDisplayBlanked() { 53 if (DEBUG) { 54 Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" 55 + DozeLog.reasonToString(mPulseReason)); 56 } 57 if (!mDozing) { 58 return; 59 } 60 61 // Signal that the pulse is ready to turn the screen on and draw. 62 pulseStarted(); 63 } 64 65 @Override 66 public void onFinished() { 67 if (DEBUG) { 68 Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); 69 } 70 if (!mDozing) { 71 return; 72 } 73 // Notifications should time out on their own. Pulses due to notifications should 74 // instead be managed externally based off the notification's lifetime. 75 // Dock also controls the time out by self. 76 if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION 77 && mPulseReason != DozeLog.PULSE_REASON_DOCKING) { 78 mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); 79 mHandler.postDelayed(mPulseOutExtended, 80 mDozeParameters.getPulseVisibleDurationExtended()); 81 } 82 mFullyPulsing = true; 83 } 84 85 /** 86 * Transition was aborted before it was over. 87 */ 88 @Override 89 public void onCancelled() { 90 pulseFinished(); 91 } 92 }; 93 94 @Inject DozeScrimController(DozeParameters dozeParameters, DozeLog dozeLog)95 public DozeScrimController(DozeParameters dozeParameters, DozeLog dozeLog) { 96 mDozeParameters = dozeParameters; 97 //Never expected to be destroyed 98 Dependency.get(StatusBarStateController.class).addCallback(this); 99 mDozeLog = dozeLog; 100 } 101 102 @VisibleForTesting setDozing(boolean dozing)103 public void setDozing(boolean dozing) { 104 if (mDozing == dozing) return; 105 mDozing = dozing; 106 if (!mDozing) { 107 cancelPulsing(); 108 } 109 } 110 111 /** When dozing, fade screen contents in and out using the front scrim. */ pulse(@onNull DozeHost.PulseCallback callback, int reason)112 public void pulse(@NonNull DozeHost.PulseCallback callback, int reason) { 113 if (callback == null) { 114 throw new IllegalArgumentException("callback must not be null"); 115 } 116 117 if (!mDozing || mPulseCallback != null) { 118 if (DEBUG) { 119 Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? " 120 + (mPulseCallback != null)); 121 } 122 // Pulse suppressed. 123 callback.onPulseFinished(); 124 return; 125 } 126 127 // Begin pulse. Note that it's very important that the pulse finished callback 128 // be invoked when we're done so that the caller can drop the pulse wakelock. 129 mPulseCallback = callback; 130 mPulseReason = reason; 131 } 132 pulseOutNow()133 public void pulseOutNow() { 134 if (mPulseCallback != null && mFullyPulsing) { 135 mPulseOut.run(); 136 } 137 } 138 isPulsing()139 public boolean isPulsing() { 140 return mPulseCallback != null; 141 } 142 isDozing()143 public boolean isDozing() { 144 return mDozing; 145 } 146 extendPulse()147 public void extendPulse() { 148 mHandler.removeCallbacks(mPulseOut); 149 } 150 151 /** 152 * When pulsing, cancel any timeouts that would take you out of the pulsing state. 153 */ cancelPendingPulseTimeout()154 public void cancelPendingPulseTimeout() { 155 mHandler.removeCallbacks(mPulseOut); 156 mHandler.removeCallbacks(mPulseOutExtended); 157 } 158 cancelPulsing()159 private void cancelPulsing() { 160 if (mPulseCallback != null) { 161 if (DEBUG) Log.d(TAG, "Cancel pulsing"); 162 mFullyPulsing = false; 163 mHandler.removeCallbacks(mPulseOut); 164 mHandler.removeCallbacks(mPulseOutExtended); 165 pulseFinished(); 166 } 167 } 168 pulseStarted()169 private void pulseStarted() { 170 mDozeLog.tracePulseStart(mPulseReason); 171 if (mPulseCallback != null) { 172 mPulseCallback.onPulseStarted(); 173 } 174 } 175 pulseFinished()176 private void pulseFinished() { 177 mDozeLog.tracePulseFinish(); 178 if (mPulseCallback != null) { 179 mPulseCallback.onPulseFinished(); 180 mPulseCallback = null; 181 } 182 } 183 184 private final Runnable mPulseOutExtended = new Runnable() { 185 @Override 186 public void run() { 187 mHandler.removeCallbacks(mPulseOut); 188 mPulseOut.run(); 189 } 190 }; 191 192 private final Runnable mPulseOut = new Runnable() { 193 @Override 194 public void run() { 195 mFullyPulsing = false; 196 mHandler.removeCallbacks(mPulseOut); 197 mHandler.removeCallbacks(mPulseOutExtended); 198 if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); 199 if (!mDozing) return; 200 pulseFinished(); 201 } 202 }; 203 getScrimCallback()204 public ScrimController.Callback getScrimCallback() { 205 return mScrimCallback; 206 } 207 208 @Override onStateChanged(int newState)209 public void onStateChanged(int newState) { 210 // don't care 211 } 212 213 @Override onDozingChanged(boolean isDozing)214 public void onDozingChanged(boolean isDozing) { 215 setDozing(isDozing); 216 } 217 }