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.os.Handler;
21 import android.os.PowerManager;
22 import android.os.SystemClock;
23 import android.os.Trace;
24 import android.util.Log;
26 import com.android.keyguard.KeyguardConstants;
27 import com.android.keyguard.KeyguardUpdateMonitor;
28 import com.android.keyguard.KeyguardUpdateMonitorCallback;
29 import com.android.keyguard.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;
35 import java.io.PrintWriter;
38 * Controller which coordinates all the fingerprint unlocking actions with the UI.
40 public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
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";
48 * Mode in which we don't need to wake up the device when we get a fingerprint.
50 public static final int MODE_NONE = 0;
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.
56 public static final int MODE_WAKE_AND_UNLOCK = 1;
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.
62 public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2;
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.
68 public static final int MODE_SHOW_BOUNCER = 3;
71 * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
74 public static final int MODE_ONLY_WAKE = 4;
77 * Mode in which fingerprint unlocks the device.
79 public static final int MODE_UNLOCK = 5;
82 * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
85 public static final int MODE_DISMISS_BOUNCER = 6;
88 * How much faster we collapse the lockscreen when authenticating with fingerprint.
90 private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
92 private PowerManager mPowerManager;
93 private Handler mHandler = new Handler();
94 private PowerManager.WakeLock mWakeLock;
95 private KeyguardUpdateMonitor mUpdateMonitor;
97 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
98 private StatusBarWindowManager mStatusBarWindowManager;
99 private DozeScrimController mDozeScrimController;
100 private KeyguardViewMediator mKeyguardViewMediator;
101 private ScrimController mScrimController;
102 private StatusBar mStatusBar;
103 private final UnlockMethodCache mUnlockMethodCache;
104 private final Context mContext;
105 private int mPendingAuthenticatedUserId = -1;
106 private boolean mPendingShowBouncer;
107 private boolean mHasScreenTurnedOnSinceAuthenticating;
109 public FingerprintUnlockController(Context context,
110 DozeScrimController dozeScrimController,
111 KeyguardViewMediator keyguardViewMediator,
112 ScrimController scrimController,
114 UnlockMethodCache unlockMethodCache) {
116 mPowerManager = context.getSystemService(PowerManager.class);
117 mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
118 mUpdateMonitor.registerCallback(this);
119 Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
120 Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver);
121 mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
122 mDozeScrimController = dozeScrimController;
123 mKeyguardViewMediator = keyguardViewMediator;
124 mScrimController = scrimController;
125 mStatusBar = statusBar;
126 mUnlockMethodCache = unlockMethodCache;
129 public void setStatusBarKeyguardViewManager(
130 StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
131 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
134 private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
137 if (DEBUG_FP_WAKELOCK) {
138 Log.i(TAG, "fp wakelock: TIMEOUT!!");
140 releaseFingerprintWakeLock();
144 private void releaseFingerprintWakeLock() {
145 if (mWakeLock != null) {
146 mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
147 if (DEBUG_FP_WAKELOCK) {
148 Log.i(TAG, "releasing fp wakelock");
156 public void onFingerprintAcquired() {
157 Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
158 releaseFingerprintWakeLock();
159 if (!mUpdateMonitor.isDeviceInteractive()) {
160 if (LatencyTracker.isEnabled(mContext)) {
161 LatencyTracker.getInstance(mContext).onActionStart(
162 LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
164 mWakeLock = mPowerManager.newWakeLock(
165 PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
166 Trace.beginSection("acquiring wake-and-unlock");
169 if (DEBUG_FP_WAKELOCK) {
170 Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
172 mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
173 FINGERPRINT_WAKELOCK_TIMEOUT_MS);
178 private boolean pulsingOrAod() {
179 boolean pulsing = mDozeScrimController.isPulsing();
180 boolean dozingWithScreenOn = mStatusBar.isDozing() && !mStatusBar.isScreenFullyOff();
181 return pulsing || dozingWithScreenOn;
185 public void onFingerprintAuthenticated(int userId) {
186 Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated");
187 if (mUpdateMonitor.isGoingToSleep()) {
188 mPendingAuthenticatedUserId = userId;
192 startWakeAndUnlock(calculateMode());
195 public void startWakeAndUnlock(int mode) {
196 boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
198 mHasScreenTurnedOnSinceAuthenticating = false;
199 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
200 // If we are waking the device up while we are pulsing the clock and the
201 // notifications would light up first, creating an unpleasant animation.
202 // Defer changing the screen brightness by forcing doze brightness on our window
203 // until the clock and the notifications are faded out.
204 mStatusBarWindowManager.setForceDozeBrightness(true);
206 if (!wasDeviceInteractive) {
207 if (DEBUG_FP_WAKELOCK) {
208 Log.i(TAG, "fp wakelock: Authenticated, waking up...");
210 mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
212 Trace.beginSection("release wake-and-unlock");
213 releaseFingerprintWakeLock();
216 case MODE_DISMISS_BOUNCER:
217 Trace.beginSection("MODE_DISMISS");
218 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
219 false /* strongAuth */);
223 case MODE_SHOW_BOUNCER:
224 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
225 if (!wasDeviceInteractive) {
226 mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
227 mPendingShowBouncer = true;
233 case MODE_WAKE_AND_UNLOCK_PULSING:
234 case MODE_WAKE_AND_UNLOCK:
235 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
236 Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
237 mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
238 true /* allowEnterAnimation */);
240 Trace.beginSection("MODE_WAKE_AND_UNLOCK");
242 mDozeScrimController.abortDoze();
244 mStatusBarWindowManager.setStatusBarFocusable(false);
245 mKeyguardViewMediator.onWakeAndUnlocking();
246 mScrimController.setWakeAndUnlocking();
247 mDozeScrimController.setWakeAndUnlocking();
248 if (mStatusBar.getNavigationBarView() != null) {
249 mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
257 mStatusBar.notifyFpAuthModeChanged();
261 private void showBouncer() {
262 mStatusBarKeyguardViewManager.animateCollapsePanels(
263 FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
264 mPendingShowBouncer = false;
268 public void onStartedGoingToSleep(int why) {
270 mPendingAuthenticatedUserId = -1;
274 public void onFinishedGoingToSleep(int why) {
275 Trace.beginSection("FingerprintUnlockController#onFinishedGoingToSleep");
276 if (mPendingAuthenticatedUserId != -1) {
278 // Post this to make sure it's executed after the device is fully locked.
279 mHandler.post(new Runnable() {
282 onFingerprintAuthenticated(mPendingAuthenticatedUserId);
286 mPendingAuthenticatedUserId = -1;
290 public boolean hasPendingAuthentication() {
291 return mPendingAuthenticatedUserId != -1
292 && mUpdateMonitor.isUnlockingWithFingerprintAllowed()
293 && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
296 public int getMode() {
300 private int calculateMode() {
301 boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed();
303 if (!mUpdateMonitor.isDeviceInteractive()) {
304 if (!mStatusBarKeyguardViewManager.isShowing()) {
305 return MODE_ONLY_WAKE;
306 } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
307 return MODE_WAKE_AND_UNLOCK_PULSING;
308 } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
309 return MODE_WAKE_AND_UNLOCK;
311 return MODE_SHOW_BOUNCER;
314 if (mStatusBarKeyguardViewManager.isShowing()) {
315 if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) {
316 return MODE_DISMISS_BOUNCER;
317 } else if (unlockingAllowed) {
319 } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
320 return MODE_SHOW_BOUNCER;
327 public void onFingerprintAuthFailed() {
332 public void onFingerprintError(int msgId, String errString) {
336 private void cleanup() {
337 releaseFingerprintWakeLock();
340 public void startKeyguardFadingAway() {
342 // Disable brightness override when the ambient contents are fully invisible.
343 mHandler.postDelayed(new Runnable() {
346 mStatusBarWindowManager.setForceDozeBrightness(false);
348 }, StatusBar.FADE_KEYGUARD_DURATION_PULSING);
351 public void finishKeyguardFadingAway() {
355 private void resetMode() {
357 mStatusBarWindowManager.setForceDozeBrightness(false);
358 if (mStatusBar.getNavigationBarView() != null) {
359 mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
361 mStatusBar.notifyFpAuthModeChanged();
364 private final WakefulnessLifecycle.Observer mWakefulnessObserver =
365 new WakefulnessLifecycle.Observer() {
367 public void onFinishedWakingUp() {
368 if (mPendingShowBouncer) {
369 FingerprintUnlockController.this.showBouncer();
374 private final ScreenLifecycle.Observer mScreenObserver =
375 new ScreenLifecycle.Observer() {
377 public void onScreenTurnedOn() {
378 mHasScreenTurnedOnSinceAuthenticating = true;
382 public boolean hasScreenTurnedOnSinceAuthenticating() {
383 return mHasScreenTurnedOnSinceAuthenticating;
386 public void dump(PrintWriter pw) {
387 pw.println(" FingerprintUnlockController:");
388 pw.print(" mMode="); pw.println(mMode);
389 pw.print(" mWakeLock="); pw.println(mWakeLock);