1 /* 2 * Copyright (C) 2015 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.content.Context; 20 import android.os.Handler; 21 import android.os.PowerManager; 22 import android.os.SystemClock; 23 import android.util.Log; 24 25 import com.android.keyguard.KeyguardConstants; 26 import com.android.keyguard.KeyguardUpdateMonitor; 27 import com.android.keyguard.KeyguardUpdateMonitorCallback; 28 import com.android.systemui.keyguard.KeyguardViewMediator; 29 30 /** 31 * Controller which coordinates all the fingerprint unlocking actions with the UI. 32 */ 33 public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { 34 35 private static final String TAG = "FingerprintController"; 36 private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK; 37 private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000; 38 private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock"; 39 40 /** 41 * Mode in which we don't need to wake up the device when we get a fingerprint. 42 */ 43 public static final int MODE_NONE = 0; 44 45 /** 46 * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire 47 * a fingerprint while the screen is off and the device was sleeping. 48 */ 49 public static final int MODE_WAKE_AND_UNLOCK = 1; 50 51 /** 52 * Mode in which we wake the device up, and fade out the Keyguard contents because they were 53 * already visible while pulsing in doze mode. 54 */ 55 public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2; 56 57 /** 58 * Mode in which we wake up the device, but play the normal dismiss animation. Active when we 59 * acquire a fingerprint pulsing in doze mode. 60 */ 61 public static final int MODE_SHOW_BOUNCER = 3; 62 63 /** 64 * Mode in which we only wake up the device, and keyguard was not showing when we acquired a 65 * fingerprint. 66 * */ 67 public static final int MODE_ONLY_WAKE = 4; 68 69 /** 70 * Mode in which fingerprint unlocks the device. 71 */ 72 public static final int MODE_UNLOCK = 5; 73 74 /** 75 * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently 76 * not allowed. 77 */ 78 public static final int MODE_DISMISS_BOUNCER = 6; 79 80 /** 81 * How much faster we collapse the lockscreen when authenticating with fingerprint. 82 */ 83 private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f; 84 85 private PowerManager mPowerManager; 86 private Handler mHandler = new Handler(); 87 private PowerManager.WakeLock mWakeLock; 88 private KeyguardUpdateMonitor mUpdateMonitor; 89 private int mMode; 90 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 91 private StatusBarWindowManager mStatusBarWindowManager; 92 private DozeScrimController mDozeScrimController; 93 private KeyguardViewMediator mKeyguardViewMediator; 94 private ScrimController mScrimController; 95 private PhoneStatusBar mPhoneStatusBar; 96 private boolean mGoingToSleep; 97 private int mPendingAuthenticatedUserId = -1; 98 FingerprintUnlockController(Context context, StatusBarWindowManager statusBarWindowManager, DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator, ScrimController scrimController, PhoneStatusBar phoneStatusBar)99 public FingerprintUnlockController(Context context, 100 StatusBarWindowManager statusBarWindowManager, 101 DozeScrimController dozeScrimController, 102 KeyguardViewMediator keyguardViewMediator, 103 ScrimController scrimController, 104 PhoneStatusBar phoneStatusBar) { 105 mPowerManager = context.getSystemService(PowerManager.class); 106 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); 107 mUpdateMonitor.registerCallback(this); 108 mStatusBarWindowManager = statusBarWindowManager; 109 mDozeScrimController = dozeScrimController; 110 mKeyguardViewMediator = keyguardViewMediator; 111 mScrimController = scrimController; 112 mPhoneStatusBar = phoneStatusBar; 113 } 114 setStatusBarKeyguardViewManager( StatusBarKeyguardViewManager statusBarKeyguardViewManager)115 public void setStatusBarKeyguardViewManager( 116 StatusBarKeyguardViewManager statusBarKeyguardViewManager) { 117 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 118 } 119 120 private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() { 121 @Override 122 public void run() { 123 if (DEBUG_FP_WAKELOCK) { 124 Log.i(TAG, "fp wakelock: TIMEOUT!!"); 125 } 126 releaseFingerprintWakeLock(); 127 } 128 }; 129 releaseFingerprintWakeLock()130 private void releaseFingerprintWakeLock() { 131 if (mWakeLock != null) { 132 mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable); 133 if (DEBUG_FP_WAKELOCK) { 134 Log.i(TAG, "releasing fp wakelock"); 135 } 136 mWakeLock.release(); 137 mWakeLock = null; 138 } 139 } 140 141 @Override onFingerprintAcquired()142 public void onFingerprintAcquired() { 143 releaseFingerprintWakeLock(); 144 if (!mUpdateMonitor.isDeviceInteractive()) { 145 mWakeLock = mPowerManager.newWakeLock( 146 PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME); 147 mWakeLock.acquire(); 148 if (DEBUG_FP_WAKELOCK) { 149 Log.i(TAG, "fingerprint acquired, grabbing fp wakelock"); 150 } 151 mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable, 152 FINGERPRINT_WAKELOCK_TIMEOUT_MS); 153 if (mDozeScrimController.isPulsing()) { 154 155 // If we are waking the device up while we are pulsing the clock and the 156 // notifications would light up first, creating an unpleasant animation. 157 // Defer changing the screen brightness by forcing doze brightness on our window 158 // until the clock and the notifications are faded out. 159 mStatusBarWindowManager.setForceDozeBrightness(true); 160 } 161 } 162 } 163 164 @Override onFingerprintAuthenticated(int userId)165 public void onFingerprintAuthenticated(int userId) { 166 if (mUpdateMonitor.isGoingToSleep()) { 167 mPendingAuthenticatedUserId = userId; 168 return; 169 } 170 boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive(); 171 mMode = calculateMode(); 172 if (!wasDeviceInteractive) { 173 if (DEBUG_FP_WAKELOCK) { 174 Log.i(TAG, "fp wakelock: Authenticated, waking up..."); 175 } 176 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT"); 177 } 178 releaseFingerprintWakeLock(); 179 switch (mMode) { 180 case MODE_DISMISS_BOUNCER: 181 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated( 182 false /* strongAuth */); 183 break; 184 case MODE_UNLOCK: 185 case MODE_SHOW_BOUNCER: 186 if (!wasDeviceInteractive) { 187 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 188 } 189 mStatusBarKeyguardViewManager.animateCollapsePanels( 190 FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); 191 break; 192 case MODE_WAKE_AND_UNLOCK_PULSING: 193 mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */, 194 true /* allowEnterAnimation */); 195 // Fall through. 196 case MODE_WAKE_AND_UNLOCK: 197 mStatusBarWindowManager.setStatusBarFocusable(false); 198 mDozeScrimController.abortPulsing(); 199 mKeyguardViewMediator.onWakeAndUnlocking(); 200 mScrimController.setWakeAndUnlocking(); 201 if (mPhoneStatusBar.getNavigationBarView() != null) { 202 mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true); 203 } 204 break; 205 case MODE_ONLY_WAKE: 206 case MODE_NONE: 207 break; 208 } 209 if (mMode != MODE_WAKE_AND_UNLOCK_PULSING) { 210 mStatusBarWindowManager.setForceDozeBrightness(false); 211 } 212 mPhoneStatusBar.notifyFpAuthModeChanged(); 213 } 214 215 @Override onStartedGoingToSleep(int why)216 public void onStartedGoingToSleep(int why) { 217 mPendingAuthenticatedUserId = -1; 218 } 219 220 @Override onFinishedGoingToSleep(int why)221 public void onFinishedGoingToSleep(int why) { 222 if (mPendingAuthenticatedUserId != -1) { 223 224 // Post this to make sure it's executed after the device is fully locked. 225 mHandler.post(new Runnable() { 226 @Override 227 public void run() { 228 onFingerprintAuthenticated(mPendingAuthenticatedUserId); 229 } 230 }); 231 } 232 mPendingAuthenticatedUserId = -1; 233 } 234 getMode()235 public int getMode() { 236 return mMode; 237 } 238 calculateMode()239 private int calculateMode() { 240 boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed(); 241 if (!mUpdateMonitor.isDeviceInteractive()) { 242 if (!mStatusBarKeyguardViewManager.isShowing()) { 243 return MODE_ONLY_WAKE; 244 } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { 245 return MODE_WAKE_AND_UNLOCK_PULSING; 246 } else if (unlockingAllowed) { 247 return MODE_WAKE_AND_UNLOCK; 248 } else { 249 return MODE_SHOW_BOUNCER; 250 } 251 } 252 if (mStatusBarKeyguardViewManager.isShowing()) { 253 if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) { 254 return MODE_DISMISS_BOUNCER; 255 } else if (unlockingAllowed) { 256 return MODE_UNLOCK; 257 } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) { 258 return MODE_SHOW_BOUNCER; 259 } 260 } 261 return MODE_NONE; 262 } 263 264 @Override onFingerprintAuthFailed()265 public void onFingerprintAuthFailed() { 266 cleanup(); 267 } 268 269 @Override onFingerprintError(int msgId, String errString)270 public void onFingerprintError(int msgId, String errString) { 271 cleanup(); 272 } 273 cleanup()274 private void cleanup() { 275 mMode = MODE_NONE; 276 releaseFingerprintWakeLock(); 277 mStatusBarWindowManager.setForceDozeBrightness(false); 278 mPhoneStatusBar.notifyFpAuthModeChanged(); 279 } 280 startKeyguardFadingAway()281 public void startKeyguardFadingAway() { 282 283 // Disable brightness override when the ambient contents are fully invisible. 284 mHandler.postDelayed(new Runnable() { 285 @Override 286 public void run() { 287 mStatusBarWindowManager.setForceDozeBrightness(false); 288 } 289 }, PhoneStatusBar.FADE_KEYGUARD_DURATION_PULSING); 290 } 291 finishKeyguardFadingAway()292 public void finishKeyguardFadingAway() { 293 mMode = MODE_NONE; 294 if (mPhoneStatusBar.getNavigationBarView() != null) { 295 mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(false); 296 } 297 mPhoneStatusBar.notifyFpAuthModeChanged(); 298 } 299 } 300