1 /* 2 * Copyright (C) 2017 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.doze; 18 19 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; 20 21 import static com.android.systemui.doze.DozeMachine.State.DOZE; 22 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; 23 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; 24 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING; 25 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE; 26 27 import android.hardware.biometrics.BiometricAuthenticator; 28 import android.os.Handler; 29 import android.util.Log; 30 import android.view.Display; 31 32 import androidx.annotation.Nullable; 33 34 import com.android.keyguard.KeyguardUpdateMonitor; 35 import com.android.systemui.biometrics.AuthController; 36 import com.android.systemui.biometrics.UdfpsController; 37 import com.android.systemui.dagger.qualifiers.Main; 38 import com.android.systemui.doze.dagger.DozeScope; 39 import com.android.systemui.doze.dagger.WrappedService; 40 import com.android.systemui.statusbar.phone.DozeParameters; 41 import com.android.systemui.util.wakelock.SettableWakeLock; 42 import com.android.systemui.util.wakelock.WakeLock; 43 44 import javax.inject.Inject; 45 import javax.inject.Provider; 46 47 /** 48 * Controls the screen when dozing. 49 */ 50 @DozeScope 51 public class DozeScreenState implements DozeMachine.Part { 52 53 private static final boolean DEBUG = DozeService.DEBUG; 54 private static final String TAG = "DozeScreenState"; 55 56 /** 57 * Delay entering low power mode when animating to make sure that we'll have 58 * time to move all elements into their final positions while still at 60 fps. 59 */ 60 private static final int ENTER_DOZE_DELAY = 4000; 61 /** 62 * Hide wallpaper earlier when entering low power mode. The gap between 63 * hiding the wallpaper and changing the display mode is necessary to hide 64 * the black frame that's inherent to hardware specs. 65 */ 66 public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2500; 67 68 /** 69 * Add an extra delay to the transition to DOZE when udfps is current activated before 70 * the display state transitions from ON => DOZE. 71 */ 72 public static final int UDFPS_DISPLAY_STATE_DELAY = 1200; 73 74 private final DozeMachine.Service mDozeService; 75 private final Handler mHandler; 76 private final Runnable mApplyPendingScreenState = this::applyPendingScreenState; 77 private final DozeParameters mParameters; 78 private final DozeHost mDozeHost; 79 private final AuthController mAuthController; 80 private final Provider<UdfpsController> mUdfpsControllerProvider; 81 @Nullable private UdfpsController mUdfpsController; 82 private final DozeLog mDozeLog; 83 private final DozeScreenBrightness mDozeScreenBrightness; 84 85 private int mPendingScreenState = Display.STATE_UNKNOWN; 86 private SettableWakeLock mWakeLock; 87 88 @Inject DozeScreenState( @rappedService DozeMachine.Service service, @Main Handler handler, DozeHost host, DozeParameters parameters, WakeLock wakeLock, AuthController authController, Provider<UdfpsController> udfpsControllerProvider, DozeLog dozeLog, DozeScreenBrightness dozeScreenBrightness)89 public DozeScreenState( 90 @WrappedService DozeMachine.Service service, 91 @Main Handler handler, 92 DozeHost host, 93 DozeParameters parameters, 94 WakeLock wakeLock, 95 AuthController authController, 96 Provider<UdfpsController> udfpsControllerProvider, 97 DozeLog dozeLog, 98 DozeScreenBrightness dozeScreenBrightness) { 99 mDozeService = service; 100 mHandler = handler; 101 mParameters = parameters; 102 mDozeHost = host; 103 mWakeLock = new SettableWakeLock(wakeLock, TAG); 104 mAuthController = authController; 105 mUdfpsControllerProvider = udfpsControllerProvider; 106 mDozeLog = dozeLog; 107 mDozeScreenBrightness = dozeScreenBrightness; 108 109 updateUdfpsController(); 110 if (mUdfpsController == null) { 111 mAuthController.addCallback(mAuthControllerCallback); 112 } 113 } 114 updateUdfpsController()115 private void updateUdfpsController() { 116 if (mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) { 117 mUdfpsController = mUdfpsControllerProvider.get(); 118 } else { 119 mUdfpsController = null; 120 } 121 } 122 123 @Override destroy()124 public void destroy() { 125 mAuthController.removeCallback(mAuthControllerCallback); 126 } 127 128 @Override transitionTo(DozeMachine.State oldState, DozeMachine.State newState)129 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { 130 int screenState = newState.screenState(mParameters); 131 mDozeHost.cancelGentleSleep(); 132 133 if (newState == DozeMachine.State.FINISH) { 134 // Make sure not to apply the screen state after DozeService was destroyed. 135 mPendingScreenState = Display.STATE_UNKNOWN; 136 mHandler.removeCallbacks(mApplyPendingScreenState); 137 138 applyScreenState(screenState); 139 mWakeLock.setAcquired(false); 140 return; 141 } 142 143 if (screenState == Display.STATE_UNKNOWN) { 144 // We'll keep it in the existing state 145 return; 146 } 147 148 final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState); 149 final boolean pulseEnding = oldState == DOZE_PULSE_DONE && newState.isAlwaysOn(); 150 final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE) 151 && newState.isAlwaysOn(); 152 final boolean turningOff = (oldState.isAlwaysOn() && newState == DOZE) 153 || (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED); 154 final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED; 155 if (messagePending || justInitialized || pulseEnding || turningOn) { 156 // During initialization, we hide the navigation bar. That is however only applied after 157 // a traversal; setting the screen state here is immediate however, so it can happen 158 // that the screen turns on again before the navigation bar is hidden. To work around 159 // that, wait for a traversal to happen before applying the initial screen state. 160 mPendingScreenState = screenState; 161 162 // Delay screen state transitions even longer while animations are running. 163 boolean shouldDelayTransitionEnteringDoze = newState == DOZE_AOD 164 && mParameters.shouldDelayDisplayDozeTransition() && !turningOn; 165 166 // Delay screen state transition longer if UDFPS is actively authenticating a fp 167 boolean shouldDelayTransitionForUDFPS = newState == DOZE_AOD 168 && mUdfpsController != null && mUdfpsController.isFingerDown(); 169 170 if (!messagePending) { 171 if (DEBUG) { 172 Log.d(TAG, "Display state changed to " + screenState + " delayed by " 173 + (shouldDelayTransitionEnteringDoze ? ENTER_DOZE_DELAY : 1)); 174 } 175 176 if (shouldDelayTransitionEnteringDoze) { 177 if (justInitialized) { 178 // If we are delaying transitioning to doze and the display was not 179 // turned on we set it to 'on' first to make sure that the animation 180 // is visible before eventually moving it to doze state. 181 // The display might be off at this point for example on foldable devices 182 // when we switch displays and go to doze at the same time. 183 applyScreenState(Display.STATE_ON); 184 185 // Restore pending screen state as it gets cleared by 'applyScreenState' 186 mPendingScreenState = screenState; 187 } 188 189 mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY); 190 } else if (shouldDelayTransitionForUDFPS) { 191 mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState); 192 mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY); 193 } else { 194 mHandler.post(mApplyPendingScreenState); 195 } 196 } else if (DEBUG) { 197 Log.d(TAG, "Pending display state change to " + screenState); 198 } 199 200 if (shouldDelayTransitionEnteringDoze || shouldDelayTransitionForUDFPS) { 201 mWakeLock.setAcquired(true); 202 } 203 } else if (turningOff) { 204 mDozeHost.prepareForGentleSleep(() -> applyScreenState(screenState)); 205 } else { 206 applyScreenState(screenState); 207 } 208 } 209 applyPendingScreenState()210 private void applyPendingScreenState() { 211 if (mUdfpsController != null && mUdfpsController.isFingerDown()) { 212 mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState); 213 mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY); 214 return; 215 } 216 217 applyScreenState(mPendingScreenState); 218 mPendingScreenState = Display.STATE_UNKNOWN; 219 } 220 applyScreenState(int screenState)221 private void applyScreenState(int screenState) { 222 if (screenState != Display.STATE_UNKNOWN) { 223 if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")"); 224 mDozeService.setDozeScreenState(screenState); 225 if (screenState == Display.STATE_DOZE) { 226 // If we're entering doze, update the doze screen brightness. We might have been 227 // clamping it to the dim brightness during the screen off animation, and we should 228 // now change it to the brightness we actually want according to the sensor. 229 mDozeScreenBrightness.updateBrightnessAndReady(false /* force */); 230 } 231 mPendingScreenState = Display.STATE_UNKNOWN; 232 mWakeLock.setAcquired(false); 233 } 234 } 235 236 private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { 237 @Override 238 public void onAllAuthenticatorsRegistered(@BiometricAuthenticator.Modality int modality) { 239 if (modality == TYPE_FINGERPRINT) { 240 updateUdfpsController(); 241 } 242 } 243 244 @Override 245 public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) { 246 if (modality == TYPE_FINGERPRINT) { 247 updateUdfpsController(); 248 } 249 } 250 }; 251 } 252