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 17package com.android.systemui.statusbar.phone; 18 19import android.content.Context; 20import android.os.Handler; 21import android.os.PowerManager; 22import android.os.SystemClock; 23import android.os.Trace; 24import android.util.Log; 25 26import com.android.keyguard.KeyguardConstants; 27import com.android.keyguard.KeyguardUpdateMonitor; 28import com.android.keyguard.KeyguardUpdateMonitorCallback; 29import com.android.keyguard.LatencyTracker; 30import com.android.systemui.Dependency; 31import com.android.systemui.keyguard.KeyguardViewMediator; 32 33/** 34 * Controller which coordinates all the fingerprint unlocking actions with the UI. 35 */ 36public 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 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 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 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 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 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 245 public void onStartedGoingToSleep(int why) { 246 mPendingAuthenticatedUserId = -1; 247 } 248 249 @Override 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 266 public int getMode() { 267 return mMode; 268 } 269 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 296 public void onFingerprintAuthFailed() { 297 cleanup(); 298 } 299 300 @Override 301 public void onFingerprintError(int msgId, String errString) { 302 cleanup(); 303 } 304 305 private void cleanup() { 306 releaseFingerprintWakeLock(); 307 } 308 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 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