• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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