2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.systemui.statusbar.phone;
19 import android.content.Context;
20 import android.hardware.biometrics.BiometricSourceType;
21 import android.metrics.LogMaker;
22 import android.os.Handler;
23 import android.os.PowerManager;
24 import android.os.SystemClock;
25 import android.os.Trace;
26 import android.provider.Settings;
27 import android.util.Log;
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.logging.MetricsLogger;
31 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
32 import com.android.internal.util.LatencyTracker;
33 import com.android.keyguard.KeyguardConstants;
34 import com.android.keyguard.KeyguardUpdateMonitor;
35 import com.android.keyguard.KeyguardUpdateMonitorCallback;
36 import com.android.systemui.Dependency;
37 import com.android.systemui.R;
38 import com.android.systemui.keyguard.KeyguardViewMediator;
39 import com.android.systemui.keyguard.ScreenLifecycle;
40 import com.android.systemui.keyguard.WakefulnessLifecycle;
41 import com.android.systemui.statusbar.NotificationMediaManager;
42 import com.android.systemui.tuner.TunerService;
44 import java.io.PrintWriter;
47 * Controller which coordinates all the biometric unlocking actions with the UI.
49 public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
51 private static final String TAG = "BiometricUnlockController";
52 private static final boolean DEBUG_BIO_WAKELOCK = KeyguardConstants.DEBUG_BIOMETRIC_WAKELOCK;
53 private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
54 private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
57 * Mode in which we don't need to wake up the device when we authenticate.
59 public static final int MODE_NONE = 0;
62 * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire
63 * a fingerprint while the screen is off and the device was sleeping.
65 public static final int MODE_WAKE_AND_UNLOCK = 1;
68 * Mode in which we wake the device up, and fade out the Keyguard contents because they were
69 * already visible while pulsing in doze mode.
71 public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2;
74 * Mode in which we wake up the device, but play the normal dismiss animation. Active when we
75 * acquire a fingerprint pulsing in doze mode.
77 public static final int MODE_SHOW_BOUNCER = 3;
80 * Mode in which we only wake up the device, and keyguard was not showing when we authenticated.
82 public static final int MODE_ONLY_WAKE = 4;
85 * Mode in which fingerprint unlocks the device.
87 public static final int MODE_UNLOCK = 5;
90 * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
93 public static final int MODE_DISMISS_BOUNCER = 6;
96 * Mode in which fingerprint wakes and unlocks the device from a dream.
98 public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 7;
101 * How much faster we collapse the lockscreen when authenticating with biometric.
103 private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
106 * If face unlock dismisses the lock screen or keeps user on keyguard by default on this device.
108 private final boolean mFaceDismissesKeyguardByDefault;
111 * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
114 protected boolean mFaceDismissesKeyguard;
116 private final NotificationMediaManager mMediaManager;
117 private final PowerManager mPowerManager;
118 private final Handler mHandler;
119 private PowerManager.WakeLock mWakeLock;
120 private final KeyguardUpdateMonitor mUpdateMonitor;
121 private final UnlockMethodCache mUnlockMethodCache;
122 private final StatusBarWindowController mStatusBarWindowController;
123 private final Context mContext;
124 private final int mWakeUpDelay;
126 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
127 private DozeScrimController mDozeScrimController;
128 private KeyguardViewMediator mKeyguardViewMediator;
129 private ScrimController mScrimController;
130 private StatusBar mStatusBar;
131 private int mPendingAuthenticatedUserId = -1;
132 private BiometricSourceType mPendingAuthenticatedBioSourceType = null;
133 private boolean mPendingShowBouncer;
134 private boolean mHasScreenTurnedOnSinceAuthenticating;
135 private boolean mFadedAwayAfterWakeAndUnlock;
137 private final TunerService.Tunable mFaceDismissedKeyguardTunable = new TunerService.Tunable() {
139 public void onTuningChanged(String key, String newValue) {
140 int defaultValue = mFaceDismissesKeyguardByDefault ? 1 : 0;
141 mFaceDismissesKeyguard = Settings.Secure.getIntForUser(mContext.getContentResolver(),
142 Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
143 defaultValue, KeyguardUpdateMonitor.getCurrentUser()) != 0;
147 private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
149 public BiometricUnlockController(Context context,
150 DozeScrimController dozeScrimController,
151 KeyguardViewMediator keyguardViewMediator,
152 ScrimController scrimController,
154 UnlockMethodCache unlockMethodCache, Handler handler,
155 KeyguardUpdateMonitor keyguardUpdateMonitor,
156 TunerService tunerService) {
157 this(context, dozeScrimController, keyguardViewMediator, scrimController, statusBar,
158 unlockMethodCache, handler, keyguardUpdateMonitor, tunerService,
159 context.getResources()
160 .getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze),
161 context.getResources().getBoolean(R.bool.config_faceAuthDismissesKeyguard));
165 protected BiometricUnlockController(Context context,
166 DozeScrimController dozeScrimController,
167 KeyguardViewMediator keyguardViewMediator,
168 ScrimController scrimController,
170 UnlockMethodCache unlockMethodCache, Handler handler,
171 KeyguardUpdateMonitor keyguardUpdateMonitor,
172 TunerService tunerService,
174 boolean faceDismissesKeyguard) {
176 mPowerManager = context.getSystemService(PowerManager.class);
177 mUpdateMonitor = keyguardUpdateMonitor;
178 mUpdateMonitor.registerCallback(this);
179 mMediaManager = Dependency.get(NotificationMediaManager.class);
180 Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
181 Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver);
182 mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
183 mDozeScrimController = dozeScrimController;
184 mKeyguardViewMediator = keyguardViewMediator;
185 mScrimController = scrimController;
186 mStatusBar = statusBar;
187 mUnlockMethodCache = unlockMethodCache;
189 mWakeUpDelay = wakeUpDelay;
190 mFaceDismissesKeyguardByDefault = faceDismissesKeyguard;
191 tunerService.addTunable(mFaceDismissedKeyguardTunable,
192 Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD);
195 public void setStatusBarKeyguardViewManager(
196 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
197 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
200 private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() {
203 if (DEBUG_BIO_WAKELOCK) {
204 Log.i(TAG, "biometric wakelock: TIMEOUT!!");
206 releaseBiometricWakeLock();
210 private void releaseBiometricWakeLock() {
211 if (mWakeLock != null) {
212 mHandler.removeCallbacks(mReleaseBiometricWakeLockRunnable);
213 if (DEBUG_BIO_WAKELOCK) {
214 Log.i(TAG, "releasing biometric wakelock");
222 public void onBiometricAcquired(BiometricSourceType biometricSourceType) {
223 Trace.beginSection("BiometricUnlockController#onBiometricAcquired");
224 releaseBiometricWakeLock();
225 if (!mUpdateMonitor.isDeviceInteractive()) {
226 if (LatencyTracker.isEnabled(mContext)) {
227 int action = LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
228 if (biometricSourceType == BiometricSourceType.FACE) {
229 action = LatencyTracker.ACTION_FACE_WAKE_AND_UNLOCK;
231 LatencyTracker.getInstance(mContext).onActionStart(action);
233 mWakeLock = mPowerManager.newWakeLock(
234 PowerManager.PARTIAL_WAKE_LOCK, BIOMETRIC_WAKE_LOCK_NAME);
235 Trace.beginSection("acquiring wake-and-unlock");
238 if (DEBUG_BIO_WAKELOCK) {
239 Log.i(TAG, "biometric acquired, grabbing biometric wakelock");
241 mHandler.postDelayed(mReleaseBiometricWakeLockRunnable,
242 BIOMETRIC_WAKELOCK_TIMEOUT_MS);
247 private boolean pulsingOrAod() {
248 final ScrimState scrimState = mScrimController.getState();
249 return scrimState == ScrimState.AOD
250 || scrimState == ScrimState.PULSING;
254 public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
255 Trace.beginSection("BiometricUnlockController#onBiometricAuthenticated");
256 if (mUpdateMonitor.isGoingToSleep()) {
257 mPendingAuthenticatedUserId = userId;
258 mPendingAuthenticatedBioSourceType = biometricSourceType;
262 mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
263 .setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
264 startWakeAndUnlock(calculateMode(biometricSourceType));
267 public void startWakeAndUnlock(int mode) {
268 // TODO(b/62444020): remove when this bug is fixed
269 Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
270 boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
272 mHasScreenTurnedOnSinceAuthenticating = false;
273 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
274 // If we are waking the device up while we are pulsing the clock and the
275 // notifications would light up first, creating an unpleasant animation.
276 // Defer changing the screen brightness by forcing doze brightness on our window
277 // until the clock and the notifications are faded out.
278 mStatusBarWindowController.setForceDozeBrightness(true);
280 // During wake and unlock, we need to draw black before waking up to avoid abrupt
281 // brightness changes due to display state transitions.
282 boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn();
283 boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
284 Runnable wakeUp = ()-> {
285 if (!wasDeviceInteractive) {
286 if (DEBUG_BIO_WAKELOCK) {
287 Log.i(TAG, "bio wakelock: Authenticated, waking up...");
289 mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
290 "android.policy:BIOMETRIC");
293 mKeyguardViewMediator.onWakeAndUnlocking();
295 Trace.beginSection("release wake-and-unlock");
296 releaseBiometricWakeLock();
304 case MODE_DISMISS_BOUNCER:
305 Trace.beginSection("MODE_DISMISS");
306 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
307 false /* strongAuth */);
311 case MODE_SHOW_BOUNCER:
312 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
313 if (!wasDeviceInteractive) {
314 mPendingShowBouncer = true;
320 case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
321 case MODE_WAKE_AND_UNLOCK_PULSING:
322 case MODE_WAKE_AND_UNLOCK:
323 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
324 Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
325 mMediaManager.updateMediaMetaData(false /* metaDataChanged */,
326 true /* allowEnterAnimation */);
327 } else if (mMode == MODE_WAKE_AND_UNLOCK){
328 Trace.beginSection("MODE_WAKE_AND_UNLOCK");
330 Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
331 mUpdateMonitor.awakenFromDream();
333 mStatusBarWindowController.setStatusBarFocusable(false);
335 mHandler.postDelayed(wakeUp, mWakeUpDelay);
337 mKeyguardViewMediator.onWakeAndUnlocking();
339 if (mStatusBar.getNavigationBarView() != null) {
340 mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
348 mStatusBar.notifyBiometricAuthModeChanged();
352 private void showBouncer() {
353 if (mMode == MODE_SHOW_BOUNCER) {
354 mStatusBarKeyguardViewManager.showBouncer(false);
356 mStatusBarKeyguardViewManager.animateCollapsePanels(
357 BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
358 mPendingShowBouncer = false;
362 public void onStartedGoingToSleep(int why) {
364 mFadedAwayAfterWakeAndUnlock = false;
365 mPendingAuthenticatedUserId = -1;
366 mPendingAuthenticatedBioSourceType = null;
370 public void onFinishedGoingToSleep(int why) {
371 Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
372 BiometricSourceType pendingType = mPendingAuthenticatedBioSourceType;
373 int pendingUserId = mPendingAuthenticatedUserId;
374 if (pendingUserId != -1 && pendingType != null) {
375 // Post this to make sure it's executed after the device is fully locked.
376 mHandler.post(() -> onBiometricAuthenticated(pendingUserId, pendingType));
378 mPendingAuthenticatedUserId = -1;
379 mPendingAuthenticatedBioSourceType = null;
383 public boolean hasPendingAuthentication() {
384 return mPendingAuthenticatedUserId != -1
385 && mUpdateMonitor.isUnlockingWithBiometricAllowed()
386 && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
389 public int getMode() {
393 private int calculateMode(BiometricSourceType biometricSourceType) {
394 boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
395 boolean deviceDreaming = mUpdateMonitor.isDreaming();
396 boolean faceStayingOnKeyguard = biometricSourceType == BiometricSourceType.FACE
397 && !mFaceDismissesKeyguard;
399 if (!mUpdateMonitor.isDeviceInteractive()) {
400 if (!mStatusBarKeyguardViewManager.isShowing()) {
401 return MODE_ONLY_WAKE;
402 } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
403 return faceStayingOnKeyguard ? MODE_NONE : MODE_WAKE_AND_UNLOCK_PULSING;
404 } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
405 return MODE_WAKE_AND_UNLOCK;
407 return MODE_SHOW_BOUNCER;
410 if (unlockingAllowed && deviceDreaming && !faceStayingOnKeyguard) {
411 return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
413 if (mStatusBarKeyguardViewManager.isShowing()) {
414 if ((mStatusBarKeyguardViewManager.isBouncerShowing()
415 || mStatusBarKeyguardViewManager.isBouncerPartiallyVisible())
416 && unlockingAllowed) {
417 return MODE_DISMISS_BOUNCER;
418 } else if (unlockingAllowed) {
419 return faceStayingOnKeyguard ? MODE_ONLY_WAKE : MODE_UNLOCK;
420 } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
421 return MODE_SHOW_BOUNCER;
428 public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
429 mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
430 .setType(MetricsEvent.TYPE_FAILURE).setSubtype(toSubtype(biometricSourceType)));
435 public void onBiometricError(int msgId, String errString,
436 BiometricSourceType biometricSourceType) {
437 mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
438 .setType(MetricsEvent.TYPE_ERROR).setSubtype(toSubtype(biometricSourceType))
439 .addTaggedData(MetricsEvent.FIELD_BIOMETRIC_AUTH_ERROR, msgId));
443 private void cleanup() {
444 releaseBiometricWakeLock();
447 public void startKeyguardFadingAway() {
449 // Disable brightness override when the ambient contents are fully invisible.
450 mHandler.postDelayed(new Runnable() {
453 mStatusBarWindowController.setForceDozeBrightness(false);
455 }, StatusBar.FADE_KEYGUARD_DURATION_PULSING);
458 public void finishKeyguardFadingAway() {
459 if (isWakeAndUnlock()) {
460 mFadedAwayAfterWakeAndUnlock = true;
465 private void resetMode() {
467 mStatusBarWindowController.setForceDozeBrightness(false);
468 if (mStatusBar.getNavigationBarView() != null) {
469 mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
471 mStatusBar.notifyBiometricAuthModeChanged();
474 private final WakefulnessLifecycle.Observer mWakefulnessObserver =
475 new WakefulnessLifecycle.Observer() {
477 public void onFinishedWakingUp() {
478 if (mPendingShowBouncer) {
479 BiometricUnlockController.this.showBouncer();
484 private final ScreenLifecycle.Observer mScreenObserver =
485 new ScreenLifecycle.Observer() {
487 public void onScreenTurnedOn() {
488 mHasScreenTurnedOnSinceAuthenticating = true;
492 public boolean hasScreenTurnedOnSinceAuthenticating() {
493 return mHasScreenTurnedOnSinceAuthenticating;
496 public void dump(PrintWriter pw) {
497 pw.println(" BiometricUnlockController:");
498 pw.print(" mMode="); pw.println(mMode);
499 pw.print(" mWakeLock="); pw.println(mWakeLock);
503 * Successful authentication with fingerprint, face, or iris that wakes up the device.
505 public boolean isWakeAndUnlock() {
506 return mMode == MODE_WAKE_AND_UNLOCK
507 || mMode == MODE_WAKE_AND_UNLOCK_PULSING
508 || mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM;
512 * Successful authentication with fingerprint, face, or iris that wakes up the device.
513 * This will return {@code true} even after the keyguard fades away.
515 public boolean unlockedByWakeAndUnlock() {
516 return isWakeAndUnlock() || mFadedAwayAfterWakeAndUnlock;
520 * Successful authentication with fingerprint, face, or iris when the screen was either
523 public boolean isBiometricUnlock() {
524 return isWakeAndUnlock() || mMode == MODE_UNLOCK;
528 * Translates biometric source type for logging purpose.
530 private int toSubtype(BiometricSourceType biometricSourceType) {
531 switch (biometricSourceType) {