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.os.Trace; 24 import android.util.Log; 25 26 import com.android.keyguard.KeyguardConstants; 27 import com.android.keyguard.KeyguardUpdateMonitor; 28 import com.android.keyguard.KeyguardUpdateMonitorCallback; 29 import com.android.internal.util.LatencyTracker; 30 import com.android.systemui.Dependency; 31 import com.android.systemui.keyguard.KeyguardViewMediator; 32 import com.android.systemui.keyguard.ScreenLifecycle; 33 import com.android.systemui.keyguard.WakefulnessLifecycle; 34 35 import java.io.PrintWriter; 36 37 /** 38 * Controller which coordinates all the fingerprint unlocking actions with the UI. 39 */ 40 public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { 41 42 private static final String TAG = "FingerprintController"; 43 private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK; 44 private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000; 45 private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock"; 46 47 /** 48 * Mode in which we don't need to wake up the device when we get a fingerprint. 49 */ 50 public static final int MODE_NONE = 0; 51 52 /** 53 * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire 54 * a fingerprint while the screen is off and the device was sleeping. 55 */ 56 public static final int MODE_WAKE_AND_UNLOCK = 1; 57 58 /** 59 * Mode in which we wake the device up, and fade out the Keyguard contents because they were 60 * already visible while pulsing in doze mode. 61 */ 62 public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2; 63 64 /** 65 * Mode in which we wake up the device, but play the normal dismiss animation. Active when we 66 * acquire a fingerprint pulsing in doze mode. 67 */ 68 public static final int MODE_SHOW_BOUNCER = 3; 69 70 /** 71 * Mode in which we only wake up the device, and keyguard was not showing when we acquired a 72 * fingerprint. 73 * */ 74 public static final int MODE_ONLY_WAKE = 4; 75 76 /** 77 * Mode in which fingerprint unlocks the device. 78 */ 79 public static final int MODE_UNLOCK = 5; 80 81 /** 82 * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently 83 * not allowed. 84 */ 85 public static final int MODE_DISMISS_BOUNCER = 6; 86 87 /** 88 * Mode in which fingerprint wakes and unlocks the device from a dream. 89 */ 90 public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 7; 91 92 /** 93 * How much faster we collapse the lockscreen when authenticating with fingerprint. 94 */ 95 private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.1f; 96 97 private PowerManager mPowerManager; 98 private Handler mHandler = new Handler(); 99 private PowerManager.WakeLock mWakeLock; 100 private KeyguardUpdateMonitor mUpdateMonitor; 101 private int mMode; 102 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 103 private StatusBarWindowManager mStatusBarWindowManager; 104 private DozeScrimController mDozeScrimController; 105 private KeyguardViewMediator mKeyguardViewMediator; 106 private ScrimController mScrimController; 107 private StatusBar mStatusBar; 108 private final UnlockMethodCache mUnlockMethodCache; 109 private final Context mContext; 110 private int mPendingAuthenticatedUserId = -1; 111 private boolean mPendingShowBouncer; 112 private boolean mHasScreenTurnedOnSinceAuthenticating; 113 FingerprintUnlockController(Context context, DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator, ScrimController scrimController, StatusBar statusBar, UnlockMethodCache unlockMethodCache)114 public FingerprintUnlockController(Context context, 115 DozeScrimController dozeScrimController, 116 KeyguardViewMediator keyguardViewMediator, 117 ScrimController scrimController, 118 StatusBar statusBar, 119 UnlockMethodCache unlockMethodCache) { 120 mContext = context; 121 mPowerManager = context.getSystemService(PowerManager.class); 122 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context); 123 mUpdateMonitor.registerCallback(this); 124 Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver); 125 Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver); 126 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class); 127 mDozeScrimController = dozeScrimController; 128 mKeyguardViewMediator = keyguardViewMediator; 129 mScrimController = scrimController; 130 mStatusBar = statusBar; 131 mUnlockMethodCache = unlockMethodCache; 132 } 133 setStatusBarKeyguardViewManager( StatusBarKeyguardViewManager statusBarKeyguardViewManager)134 public void setStatusBarKeyguardViewManager( 135 StatusBarKeyguardViewManager statusBarKeyguardViewManager) { 136 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 137 } 138 139 private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() { 140 @Override 141 public void run() { 142 if (DEBUG_FP_WAKELOCK) { 143 Log.i(TAG, "fp wakelock: TIMEOUT!!"); 144 } 145 releaseFingerprintWakeLock(); 146 } 147 }; 148 releaseFingerprintWakeLock()149 private void releaseFingerprintWakeLock() { 150 if (mWakeLock != null) { 151 mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable); 152 if (DEBUG_FP_WAKELOCK) { 153 Log.i(TAG, "releasing fp wakelock"); 154 } 155 mWakeLock.release(); 156 mWakeLock = null; 157 } 158 } 159 160 @Override onFingerprintAcquired()161 public void onFingerprintAcquired() { 162 Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired"); 163 releaseFingerprintWakeLock(); 164 if (!mUpdateMonitor.isDeviceInteractive()) { 165 if (LatencyTracker.isEnabled(mContext)) { 166 LatencyTracker.getInstance(mContext).onActionStart( 167 LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK); 168 } 169 mWakeLock = mPowerManager.newWakeLock( 170 PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME); 171 Trace.beginSection("acquiring wake-and-unlock"); 172 mWakeLock.acquire(); 173 Trace.endSection(); 174 if (DEBUG_FP_WAKELOCK) { 175 Log.i(TAG, "fingerprint acquired, grabbing fp wakelock"); 176 } 177 mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable, 178 FINGERPRINT_WAKELOCK_TIMEOUT_MS); 179 } 180 Trace.endSection(); 181 } 182 pulsingOrAod()183 private boolean pulsingOrAod() { 184 final ScrimState scrimState = mScrimController.getState(); 185 return scrimState == ScrimState.AOD 186 || scrimState == ScrimState.PULSING; 187 } 188 189 @Override onFingerprintAuthenticated(int userId)190 public void onFingerprintAuthenticated(int userId) { 191 Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated"); 192 if (mUpdateMonitor.isGoingToSleep()) { 193 mPendingAuthenticatedUserId = userId; 194 Trace.endSection(); 195 return; 196 } 197 startWakeAndUnlock(calculateMode()); 198 } 199 startWakeAndUnlock(int mode)200 public void startWakeAndUnlock(int mode) { 201 // TODO(b/62444020): remove when this bug is fixed 202 Log.v(TAG, "startWakeAndUnlock(" + mode + ")"); 203 boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive(); 204 mMode = mode; 205 mHasScreenTurnedOnSinceAuthenticating = false; 206 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) { 207 // If we are waking the device up while we are pulsing the clock and the 208 // notifications would light up first, creating an unpleasant animation. 209 // Defer changing the screen brightness by forcing doze brightness on our window 210 // until the clock and the notifications are faded out. 211 mStatusBarWindowManager.setForceDozeBrightness(true); 212 } 213 if (!wasDeviceInteractive) { 214 if (DEBUG_FP_WAKELOCK) { 215 Log.i(TAG, "fp wakelock: Authenticated, waking up..."); 216 } 217 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT"); 218 } 219 Trace.beginSection("release wake-and-unlock"); 220 releaseFingerprintWakeLock(); 221 Trace.endSection(); 222 switch (mMode) { 223 case MODE_DISMISS_BOUNCER: 224 Trace.beginSection("MODE_DISMISS"); 225 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated( 226 false /* strongAuth */); 227 Trace.endSection(); 228 break; 229 case MODE_UNLOCK: 230 case MODE_SHOW_BOUNCER: 231 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER"); 232 if (!wasDeviceInteractive) { 233 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested(); 234 mPendingShowBouncer = true; 235 } else { 236 showBouncer(); 237 } 238 Trace.endSection(); 239 break; 240 case MODE_WAKE_AND_UNLOCK_FROM_DREAM: 241 case MODE_WAKE_AND_UNLOCK_PULSING: 242 case MODE_WAKE_AND_UNLOCK: 243 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) { 244 Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING"); 245 mStatusBar.updateMediaMetaData(false /* metaDataChanged */, 246 true /* allowEnterAnimation */); 247 } else if (mMode == MODE_WAKE_AND_UNLOCK){ 248 Trace.beginSection("MODE_WAKE_AND_UNLOCK"); 249 } else { 250 Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM"); 251 mUpdateMonitor.awakenFromDream(); 252 } 253 mStatusBarWindowManager.setStatusBarFocusable(false); 254 mKeyguardViewMediator.onWakeAndUnlocking(); 255 if (mStatusBar.getNavigationBarView() != null) { 256 mStatusBar.getNavigationBarView().setWakeAndUnlocking(true); 257 } 258 Trace.endSection(); 259 break; 260 case MODE_ONLY_WAKE: 261 case MODE_NONE: 262 break; 263 } 264 mStatusBar.notifyFpAuthModeChanged(); 265 Trace.endSection(); 266 } 267 showBouncer()268 private void showBouncer() { 269 if (calculateMode() == MODE_SHOW_BOUNCER) { 270 mStatusBarKeyguardViewManager.showBouncer(false); 271 } 272 mStatusBarKeyguardViewManager.animateCollapsePanels( 273 FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR); 274 mPendingShowBouncer = false; 275 } 276 277 @Override onStartedGoingToSleep(int why)278 public void onStartedGoingToSleep(int why) { 279 resetMode(); 280 mPendingAuthenticatedUserId = -1; 281 } 282 283 @Override onFinishedGoingToSleep(int why)284 public void onFinishedGoingToSleep(int why) { 285 Trace.beginSection("FingerprintUnlockController#onFinishedGoingToSleep"); 286 if (mPendingAuthenticatedUserId != -1) { 287 288 // Post this to make sure it's executed after the device is fully locked. 289 mHandler.post(new Runnable() { 290 @Override 291 public void run() { 292 onFingerprintAuthenticated(mPendingAuthenticatedUserId); 293 } 294 }); 295 } 296 mPendingAuthenticatedUserId = -1; 297 Trace.endSection(); 298 } 299 hasPendingAuthentication()300 public boolean hasPendingAuthentication() { 301 return mPendingAuthenticatedUserId != -1 302 && mUpdateMonitor.isUnlockingWithFingerprintAllowed() 303 && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser(); 304 } 305 getMode()306 public int getMode() { 307 return mMode; 308 } 309 calculateMode()310 private int calculateMode() { 311 boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed(); 312 boolean deviceDreaming = mUpdateMonitor.isDreaming(); 313 314 if (!mUpdateMonitor.isDeviceInteractive()) { 315 if (!mStatusBarKeyguardViewManager.isShowing()) { 316 return MODE_ONLY_WAKE; 317 } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { 318 return MODE_WAKE_AND_UNLOCK_PULSING; 319 } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) { 320 return MODE_WAKE_AND_UNLOCK; 321 } else { 322 return MODE_SHOW_BOUNCER; 323 } 324 } 325 if (unlockingAllowed && deviceDreaming) { 326 return MODE_WAKE_AND_UNLOCK_FROM_DREAM; 327 } 328 if (mStatusBarKeyguardViewManager.isShowing()) { 329 if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) { 330 return MODE_DISMISS_BOUNCER; 331 } else if (unlockingAllowed) { 332 return MODE_UNLOCK; 333 } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) { 334 return MODE_SHOW_BOUNCER; 335 } 336 } 337 return MODE_NONE; 338 } 339 340 @Override onFingerprintAuthFailed()341 public void onFingerprintAuthFailed() { 342 cleanup(); 343 } 344 345 @Override onFingerprintError(int msgId, String errString)346 public void onFingerprintError(int msgId, String errString) { 347 cleanup(); 348 } 349 cleanup()350 private void cleanup() { 351 releaseFingerprintWakeLock(); 352 } 353 startKeyguardFadingAway()354 public void startKeyguardFadingAway() { 355 356 // Disable brightness override when the ambient contents are fully invisible. 357 mHandler.postDelayed(new Runnable() { 358 @Override 359 public void run() { 360 mStatusBarWindowManager.setForceDozeBrightness(false); 361 } 362 }, StatusBar.FADE_KEYGUARD_DURATION_PULSING); 363 } 364 finishKeyguardFadingAway()365 public void finishKeyguardFadingAway() { 366 resetMode(); 367 } 368 resetMode()369 private void resetMode() { 370 mMode = MODE_NONE; 371 mStatusBarWindowManager.setForceDozeBrightness(false); 372 if (mStatusBar.getNavigationBarView() != null) { 373 mStatusBar.getNavigationBarView().setWakeAndUnlocking(false); 374 } 375 mStatusBar.notifyFpAuthModeChanged(); 376 } 377 378 private final WakefulnessLifecycle.Observer mWakefulnessObserver = 379 new WakefulnessLifecycle.Observer() { 380 @Override 381 public void onFinishedWakingUp() { 382 if (mPendingShowBouncer) { 383 FingerprintUnlockController.this.showBouncer(); 384 } 385 } 386 }; 387 388 private final ScreenLifecycle.Observer mScreenObserver = 389 new ScreenLifecycle.Observer() { 390 @Override 391 public void onScreenTurnedOn() { 392 mHasScreenTurnedOnSinceAuthenticating = true; 393 } 394 }; 395 hasScreenTurnedOnSinceAuthenticating()396 public boolean hasScreenTurnedOnSinceAuthenticating() { 397 return mHasScreenTurnedOnSinceAuthenticating; 398 } 399 dump(PrintWriter pw)400 public void dump(PrintWriter pw) { 401 pw.println(" FingerprintUnlockController:"); 402 pw.print(" mMode="); pw.println(mMode); 403 pw.print(" mWakeLock="); pw.println(mWakeLock); 404 } 405 406 /** 407 * Successful authentication with fingerprint that wakes up the device. 408 */ isWakeAndUnlock()409 public boolean isWakeAndUnlock() { 410 return mMode == MODE_WAKE_AND_UNLOCK 411 || mMode == MODE_WAKE_AND_UNLOCK_PULSING 412 || mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM; 413 } 414 415 /** 416 * Successful authentication with fingerprint when the screen was either on or off. 417 */ isFingerprintUnlock()418 public boolean isFingerprintUnlock() { 419 return isWakeAndUnlock() || mMode == MODE_UNLOCK; 420 } 421 } 422