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