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 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 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 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 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 183 private boolean pulsingOrAod() { 184 final ScrimState scrimState = mScrimController.getState(); 185 return scrimState == ScrimState.AOD 186 || scrimState == ScrimState.PULSING; 187 } 188 189 @Override 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 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 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 278 public void onStartedGoingToSleep(int why) { 279 resetMode(); 280 mPendingAuthenticatedUserId = -1; 281 } 282 283 @Override 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 300 public boolean hasPendingAuthentication() { 301 return mPendingAuthenticatedUserId != -1 302 && mUpdateMonitor.isUnlockingWithFingerprintAllowed() 303 && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser(); 304 } 305 306 public int getMode() { 307 return mMode; 308 } 309 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 341 public void onFingerprintAuthFailed() { 342 cleanup(); 343 } 344 345 @Override 346 public void onFingerprintError(int msgId, String errString) { 347 cleanup(); 348 } 349 350 private void cleanup() { 351 releaseFingerprintWakeLock(); 352 } 353 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 365 public void finishKeyguardFadingAway() { 366 resetMode(); 367 } 368 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 396 public boolean hasScreenTurnedOnSinceAuthenticating() { 397 return mHasScreenTurnedOnSinceAuthenticating; 398 } 399 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 */ 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 */ 418 public boolean isFingerprintUnlock() { 419 return isWakeAndUnlock() || mMode == MODE_UNLOCK; 420 } 421 } 422