• 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.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.systemui.keyguard.KeyguardViewMediator;
30 
31 /**
32  * Controller which coordinates all the fingerprint unlocking actions with the UI.
33  */
34 public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
35 
36     private static final String TAG = "FingerprintController";
37     private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
38     private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
39     private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
40 
41     /**
42      * Mode in which we don't need to wake up the device when we get a fingerprint.
43      */
44     public static final int MODE_NONE = 0;
45 
46     /**
47      * Mode in which we wake up the device, and directly dismiss Keyguard. Active when we acquire
48      * a fingerprint while the screen is off and the device was sleeping.
49      */
50     public static final int MODE_WAKE_AND_UNLOCK = 1;
51 
52     /**
53      * Mode in which we wake the device up, and fade out the Keyguard contents because they were
54      * already visible while pulsing in doze mode.
55      */
56     public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2;
57 
58     /**
59      * Mode in which we wake up the device, but play the normal dismiss animation. Active when we
60      * acquire a fingerprint pulsing in doze mode.
61      */
62     public static final int MODE_SHOW_BOUNCER = 3;
63 
64     /**
65      * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
66      * fingerprint.
67      * */
68     public static final int MODE_ONLY_WAKE = 4;
69 
70     /**
71      * Mode in which fingerprint unlocks the device.
72      */
73     public static final int MODE_UNLOCK = 5;
74 
75     /**
76      * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
77      * not allowed.
78      */
79     public static final int MODE_DISMISS_BOUNCER = 6;
80 
81     /**
82      * How much faster we collapse the lockscreen when authenticating with fingerprint.
83      */
84     private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f;
85 
86     private PowerManager mPowerManager;
87     private Handler mHandler = new Handler();
88     private PowerManager.WakeLock mWakeLock;
89     private KeyguardUpdateMonitor mUpdateMonitor;
90     private int mMode;
91     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
92     private StatusBarWindowManager mStatusBarWindowManager;
93     private DozeScrimController mDozeScrimController;
94     private KeyguardViewMediator mKeyguardViewMediator;
95     private ScrimController mScrimController;
96     private PhoneStatusBar mPhoneStatusBar;
97     private boolean mGoingToSleep;
98     private int mPendingAuthenticatedUserId = -1;
99 
FingerprintUnlockController(Context context, StatusBarWindowManager statusBarWindowManager, DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator, ScrimController scrimController, PhoneStatusBar phoneStatusBar)100     public FingerprintUnlockController(Context context,
101             StatusBarWindowManager statusBarWindowManager,
102             DozeScrimController dozeScrimController,
103             KeyguardViewMediator keyguardViewMediator,
104             ScrimController scrimController,
105             PhoneStatusBar phoneStatusBar) {
106         mPowerManager = context.getSystemService(PowerManager.class);
107         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
108         mUpdateMonitor.registerCallback(this);
109         mStatusBarWindowManager = statusBarWindowManager;
110         mDozeScrimController = dozeScrimController;
111         mKeyguardViewMediator = keyguardViewMediator;
112         mScrimController = scrimController;
113         mPhoneStatusBar = phoneStatusBar;
114     }
115 
setStatusBarKeyguardViewManager( StatusBarKeyguardViewManager statusBarKeyguardViewManager)116     public void setStatusBarKeyguardViewManager(
117             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
118         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
119     }
120 
121     private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
122         @Override
123         public void run() {
124             if (DEBUG_FP_WAKELOCK) {
125                 Log.i(TAG, "fp wakelock: TIMEOUT!!");
126             }
127             releaseFingerprintWakeLock();
128         }
129     };
130 
releaseFingerprintWakeLock()131     private void releaseFingerprintWakeLock() {
132         if (mWakeLock != null) {
133             mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
134             if (DEBUG_FP_WAKELOCK) {
135                 Log.i(TAG, "releasing fp wakelock");
136             }
137             mWakeLock.release();
138             mWakeLock = null;
139         }
140     }
141 
142     @Override
onFingerprintAcquired()143     public void onFingerprintAcquired() {
144         Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
145         releaseFingerprintWakeLock();
146         if (!mUpdateMonitor.isDeviceInteractive()) {
147             mWakeLock = mPowerManager.newWakeLock(
148                     PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
149             Trace.beginSection("acquiring wake-and-unlock");
150             mWakeLock.acquire();
151             Trace.endSection();
152             if (DEBUG_FP_WAKELOCK) {
153                 Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
154             }
155             mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
156                     FINGERPRINT_WAKELOCK_TIMEOUT_MS);
157             if (mDozeScrimController.isPulsing()) {
158 
159                 // If we are waking the device up while we are pulsing the clock and the
160                 // notifications would light up first, creating an unpleasant animation.
161                 // Defer changing the screen brightness by forcing doze brightness on our window
162                 // until the clock and the notifications are faded out.
163                 mStatusBarWindowManager.setForceDozeBrightness(true);
164             }
165         }
166         Trace.endSection();
167     }
168 
169     @Override
onFingerprintAuthenticated(int userId)170     public void onFingerprintAuthenticated(int userId) {
171         Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated");
172         if (mUpdateMonitor.isGoingToSleep()) {
173             mPendingAuthenticatedUserId = userId;
174             Trace.endSection();
175             return;
176         }
177         boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
178         mMode = calculateMode();
179         if (!wasDeviceInteractive) {
180             if (DEBUG_FP_WAKELOCK) {
181                 Log.i(TAG, "fp wakelock: Authenticated, waking up...");
182             }
183             mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
184         }
185         Trace.beginSection("release wake-and-unlock");
186         releaseFingerprintWakeLock();
187         Trace.endSection();
188         switch (mMode) {
189             case MODE_DISMISS_BOUNCER:
190                 Trace.beginSection("MODE_DISMISS");
191                 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
192                         false /* strongAuth */);
193                 Trace.endSection();
194                 break;
195             case MODE_UNLOCK:
196             case MODE_SHOW_BOUNCER:
197                 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
198                 if (!wasDeviceInteractive) {
199                     mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
200                 }
201                 mStatusBarKeyguardViewManager.animateCollapsePanels(
202                         FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
203                 Trace.endSection();
204                 break;
205             case MODE_WAKE_AND_UNLOCK_PULSING:
206                 Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
207                 mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */,
208                         true /* allowEnterAnimation */);
209                 // Fall through.
210                 Trace.endSection();
211             case MODE_WAKE_AND_UNLOCK:
212                 Trace.beginSection("MODE_WAKE_AND_UNLOCK");
213                 mStatusBarWindowManager.setStatusBarFocusable(false);
214                 mDozeScrimController.abortPulsing();
215                 mKeyguardViewMediator.onWakeAndUnlocking();
216                 mScrimController.setWakeAndUnlocking();
217                 if (mPhoneStatusBar.getNavigationBarView() != null) {
218                     mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
219                 }
220                 Trace.endSection();
221                 break;
222             case MODE_ONLY_WAKE:
223             case MODE_NONE:
224                 break;
225         }
226         if (mMode != MODE_WAKE_AND_UNLOCK_PULSING) {
227             mStatusBarWindowManager.setForceDozeBrightness(false);
228         }
229         mPhoneStatusBar.notifyFpAuthModeChanged();
230         Trace.endSection();
231     }
232 
233     @Override
onStartedGoingToSleep(int why)234     public void onStartedGoingToSleep(int why) {
235         mPendingAuthenticatedUserId = -1;
236     }
237 
238     @Override
onFinishedGoingToSleep(int why)239     public void onFinishedGoingToSleep(int why) {
240         Trace.beginSection("FingerprintUnlockController#onFinishedGoingToSleep");
241         if (mPendingAuthenticatedUserId != -1) {
242 
243             // Post this to make sure it's executed after the device is fully locked.
244             mHandler.post(new Runnable() {
245                 @Override
246                 public void run() {
247                     onFingerprintAuthenticated(mPendingAuthenticatedUserId);
248                 }
249             });
250         }
251         mPendingAuthenticatedUserId = -1;
252         Trace.endSection();
253     }
254 
getMode()255     public int getMode() {
256         return mMode;
257     }
258 
calculateMode()259     private int calculateMode() {
260         boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed();
261         if (!mUpdateMonitor.isDeviceInteractive()) {
262             if (!mStatusBarKeyguardViewManager.isShowing()) {
263                 return MODE_ONLY_WAKE;
264             } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
265                 return MODE_WAKE_AND_UNLOCK_PULSING;
266             } else if (unlockingAllowed) {
267                 return MODE_WAKE_AND_UNLOCK;
268             } else {
269                 return MODE_SHOW_BOUNCER;
270             }
271         }
272         if (mStatusBarKeyguardViewManager.isShowing()) {
273             if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) {
274                 return MODE_DISMISS_BOUNCER;
275             } else if (unlockingAllowed) {
276                 return MODE_UNLOCK;
277             } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
278                 return MODE_SHOW_BOUNCER;
279             }
280         }
281         return MODE_NONE;
282     }
283 
284     @Override
onFingerprintAuthFailed()285     public void onFingerprintAuthFailed() {
286         cleanup();
287     }
288 
289     @Override
onFingerprintError(int msgId, String errString)290     public void onFingerprintError(int msgId, String errString) {
291         cleanup();
292     }
293 
cleanup()294     private void cleanup() {
295         mMode = MODE_NONE;
296         releaseFingerprintWakeLock();
297         mStatusBarWindowManager.setForceDozeBrightness(false);
298         mPhoneStatusBar.notifyFpAuthModeChanged();
299     }
300 
startKeyguardFadingAway()301     public void startKeyguardFadingAway() {
302 
303         // Disable brightness override when the ambient contents are fully invisible.
304         mHandler.postDelayed(new Runnable() {
305             @Override
306             public void run() {
307                 mStatusBarWindowManager.setForceDozeBrightness(false);
308             }
309         }, PhoneStatusBar.FADE_KEYGUARD_DURATION_PULSING);
310     }
311 
finishKeyguardFadingAway()312     public void finishKeyguardFadingAway() {
313         mMode = MODE_NONE;
314         if (mPhoneStatusBar.getNavigationBarView() != null) {
315             mPhoneStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
316         }
317         mPhoneStatusBar.notifyFpAuthModeChanged();
318     }
319 }
320