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