Home | History | Annotate | Download | only in phone
      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.internal.util.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;
     34 
     35 import java.io.PrintWriter;
     36 
     37 /**
     38  * Controller which coordinates all the fingerprint unlocking actions with the UI.
     39  */
     40 public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
     41 
     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";
     46 
     47     /**
     48      * Mode in which we don't need to wake up the device when we get a fingerprint.
     49      */
     50     public static final int MODE_NONE = 0;
     51 
     52     /**
     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.
     55      */
     56     public static final int MODE_WAKE_AND_UNLOCK = 1;
     57 
     58     /**
     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.
     61      */
     62     public static final int MODE_WAKE_AND_UNLOCK_PULSING = 2;
     63 
     64     /**
     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.
     67      */
     68     public static final int MODE_SHOW_BOUNCER = 3;
     69 
     70     /**
     71      * Mode in which we only wake up the device, and keyguard was not showing when we acquired a
     72      * fingerprint.
     73      * */
     74     public static final int MODE_ONLY_WAKE = 4;
     75 
     76     /**
     77      * Mode in which fingerprint unlocks the device.
     78      */
     79     public static final int MODE_UNLOCK = 5;
     80 
     81     /**
     82      * Mode in which fingerprint brings up the bouncer because fingerprint unlocking is currently
     83      * not allowed.
     84      */
     85     public static final int MODE_DISMISS_BOUNCER = 6;
     86 
     87     /**
     88      * Mode in which fingerprint wakes and unlocks the device from a dream.
     89      */
     90     public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 7;
     91 
     92     /**
     93      * How much faster we collapse the lockscreen when authenticating with fingerprint.
     94      */
     95     private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
     96 
     97     private PowerManager mPowerManager;
     98     private Handler mHandler = new Handler();
     99     private PowerManager.WakeLock mWakeLock;
    100     private KeyguardUpdateMonitor mUpdateMonitor;
    101     private int mMode;
    102     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
    103     private StatusBarWindowManager mStatusBarWindowManager;
    104     private DozeScrimController mDozeScrimController;
    105     private KeyguardViewMediator mKeyguardViewMediator;
    106     private ScrimController mScrimController;
    107     private StatusBar mStatusBar;
    108     private final UnlockMethodCache mUnlockMethodCache;
    109     private final Context mContext;
    110     private int mPendingAuthenticatedUserId = -1;
    111     private boolean mPendingShowBouncer;
    112     private boolean mHasScreenTurnedOnSinceAuthenticating;
    113 
    114     public FingerprintUnlockController(Context context,
    115             DozeScrimController dozeScrimController,
    116             KeyguardViewMediator keyguardViewMediator,
    117             ScrimController scrimController,
    118             StatusBar statusBar,
    119             UnlockMethodCache unlockMethodCache) {
    120         mContext = context;
    121         mPowerManager = context.getSystemService(PowerManager.class);
    122         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
    123         mUpdateMonitor.registerCallback(this);
    124         Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
    125         Dependency.get(ScreenLifecycle.class).addObserver(mScreenObserver);
    126         mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
    127         mDozeScrimController = dozeScrimController;
    128         mKeyguardViewMediator = keyguardViewMediator;
    129         mScrimController = scrimController;
    130         mStatusBar = statusBar;
    131         mUnlockMethodCache = unlockMethodCache;
    132     }
    133 
    134     public void setStatusBarKeyguardViewManager(
    135             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
    136         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
    137     }
    138 
    139     private final Runnable mReleaseFingerprintWakeLockRunnable = new Runnable() {
    140         @Override
    141         public void run() {
    142             if (DEBUG_FP_WAKELOCK) {
    143                 Log.i(TAG, "fp wakelock: TIMEOUT!!");
    144             }
    145             releaseFingerprintWakeLock();
    146         }
    147     };
    148 
    149     private void releaseFingerprintWakeLock() {
    150         if (mWakeLock != null) {
    151             mHandler.removeCallbacks(mReleaseFingerprintWakeLockRunnable);
    152             if (DEBUG_FP_WAKELOCK) {
    153                 Log.i(TAG, "releasing fp wakelock");
    154             }
    155             mWakeLock.release();
    156             mWakeLock = null;
    157         }
    158     }
    159 
    160     @Override
    161     public void onFingerprintAcquired() {
    162         Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
    163         releaseFingerprintWakeLock();
    164         if (!mUpdateMonitor.isDeviceInteractive()) {
    165             if (LatencyTracker.isEnabled(mContext)) {
    166                 LatencyTracker.getInstance(mContext).onActionStart(
    167                         LatencyTracker.ACTION_FINGERPRINT_WAKE_AND_UNLOCK);
    168             }
    169             mWakeLock = mPowerManager.newWakeLock(
    170                     PowerManager.PARTIAL_WAKE_LOCK, FINGERPRINT_WAKE_LOCK_NAME);
    171             Trace.beginSection("acquiring wake-and-unlock");
    172             mWakeLock.acquire();
    173             Trace.endSection();
    174             if (DEBUG_FP_WAKELOCK) {
    175                 Log.i(TAG, "fingerprint acquired, grabbing fp wakelock");
    176             }
    177             mHandler.postDelayed(mReleaseFingerprintWakeLockRunnable,
    178                     FINGERPRINT_WAKELOCK_TIMEOUT_MS);
    179         }
    180         Trace.endSection();
    181     }
    182 
    183     private boolean pulsingOrAod() {
    184         final ScrimState scrimState = mScrimController.getState();
    185         return scrimState == ScrimState.AOD
    186                 || scrimState == ScrimState.PULSING;
    187     }
    188 
    189     @Override
    190     public void onFingerprintAuthenticated(int userId) {
    191         Trace.beginSection("FingerprintUnlockController#onFingerprintAuthenticated");
    192         if (mUpdateMonitor.isGoingToSleep()) {
    193             mPendingAuthenticatedUserId = userId;
    194             Trace.endSection();
    195             return;
    196         }
    197         startWakeAndUnlock(calculateMode());
    198     }
    199 
    200     public void startWakeAndUnlock(int mode) {
    201         // TODO(b/62444020): remove when this bug is fixed
    202         Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
    203         boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
    204         mMode = mode;
    205         mHasScreenTurnedOnSinceAuthenticating = false;
    206         if (mMode == MODE_WAKE_AND_UNLOCK_PULSING && pulsingOrAod()) {
    207             // If we are waking the device up while we are pulsing the clock and the
    208             // notifications would light up first, creating an unpleasant animation.
    209             // Defer changing the screen brightness by forcing doze brightness on our window
    210             // until the clock and the notifications are faded out.
    211             mStatusBarWindowManager.setForceDozeBrightness(true);
    212         }
    213         if (!wasDeviceInteractive) {
    214             if (DEBUG_FP_WAKELOCK) {
    215                 Log.i(TAG, "fp wakelock: Authenticated, waking up...");
    216             }
    217             mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:FINGERPRINT");
    218         }
    219         Trace.beginSection("release wake-and-unlock");
    220         releaseFingerprintWakeLock();
    221         Trace.endSection();
    222         switch (mMode) {
    223             case MODE_DISMISS_BOUNCER:
    224                 Trace.beginSection("MODE_DISMISS");
    225                 mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
    226                         false /* strongAuth */);
    227                 Trace.endSection();
    228                 break;
    229             case MODE_UNLOCK:
    230             case MODE_SHOW_BOUNCER:
    231                 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
    232                 if (!wasDeviceInteractive) {
    233                     mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
    234                     mPendingShowBouncer = true;
    235                 } else {
    236                     showBouncer();
    237                 }
    238                 Trace.endSection();
    239                 break;
    240             case MODE_WAKE_AND_UNLOCK_FROM_DREAM:
    241             case MODE_WAKE_AND_UNLOCK_PULSING:
    242             case MODE_WAKE_AND_UNLOCK:
    243                 if (mMode == MODE_WAKE_AND_UNLOCK_PULSING) {
    244                     Trace.beginSection("MODE_WAKE_AND_UNLOCK_PULSING");
    245                     mStatusBar.updateMediaMetaData(false /* metaDataChanged */,
    246                             true /* allowEnterAnimation */);
    247                 } else if (mMode == MODE_WAKE_AND_UNLOCK){
    248                     Trace.beginSection("MODE_WAKE_AND_UNLOCK");
    249                 } else {
    250                     Trace.beginSection("MODE_WAKE_AND_UNLOCK_FROM_DREAM");
    251                     mUpdateMonitor.awakenFromDream();
    252                 }
    253                 mStatusBarWindowManager.setStatusBarFocusable(false);
    254                 mKeyguardViewMediator.onWakeAndUnlocking();
    255                 if (mStatusBar.getNavigationBarView() != null) {
    256                     mStatusBar.getNavigationBarView().setWakeAndUnlocking(true);
    257                 }
    258                 Trace.endSection();
    259                 break;
    260             case MODE_ONLY_WAKE:
    261             case MODE_NONE:
    262                 break;
    263         }
    264         mStatusBar.notifyFpAuthModeChanged();
    265         Trace.endSection();
    266     }
    267 
    268     private void showBouncer() {
    269         if (calculateMode() == MODE_SHOW_BOUNCER) {
    270             mStatusBarKeyguardViewManager.showBouncer(false);
    271         }
    272         mStatusBarKeyguardViewManager.animateCollapsePanels(
    273                 FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
    274         mPendingShowBouncer = false;
    275     }
    276 
    277     @Override
    278     public void onStartedGoingToSleep(int why) {
    279         resetMode();
    280         mPendingAuthenticatedUserId = -1;
    281     }
    282 
    283     @Override
    284     public void onFinishedGoingToSleep(int why) {
    285         Trace.beginSection("FingerprintUnlockController#onFinishedGoingToSleep");
    286         if (mPendingAuthenticatedUserId != -1) {
    287 
    288             // Post this to make sure it's executed after the device is fully locked.
    289             mHandler.post(new Runnable() {
    290                 @Override
    291                 public void run() {
    292                     onFingerprintAuthenticated(mPendingAuthenticatedUserId);
    293                 }
    294             });
    295         }
    296         mPendingAuthenticatedUserId = -1;
    297         Trace.endSection();
    298     }
    299 
    300     public boolean hasPendingAuthentication() {
    301         return mPendingAuthenticatedUserId != -1
    302                 && mUpdateMonitor.isUnlockingWithFingerprintAllowed()
    303                 && mPendingAuthenticatedUserId == KeyguardUpdateMonitor.getCurrentUser();
    304     }
    305 
    306     public int getMode() {
    307         return mMode;
    308     }
    309 
    310     private int calculateMode() {
    311         boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithFingerprintAllowed();
    312         boolean deviceDreaming = mUpdateMonitor.isDreaming();
    313 
    314         if (!mUpdateMonitor.isDeviceInteractive()) {
    315             if (!mStatusBarKeyguardViewManager.isShowing()) {
    316                 return MODE_ONLY_WAKE;
    317             } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
    318                 return MODE_WAKE_AND_UNLOCK_PULSING;
    319             } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
    320                 return MODE_WAKE_AND_UNLOCK;
    321             } else {
    322                 return MODE_SHOW_BOUNCER;
    323             }
    324         }
    325         if (unlockingAllowed && deviceDreaming) {
    326             return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
    327         }
    328         if (mStatusBarKeyguardViewManager.isShowing()) {
    329             if (mStatusBarKeyguardViewManager.isBouncerShowing() && unlockingAllowed) {
    330                 return MODE_DISMISS_BOUNCER;
    331             } else if (unlockingAllowed) {
    332                 return MODE_UNLOCK;
    333             } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
    334                 return MODE_SHOW_BOUNCER;
    335             }
    336         }
    337         return MODE_NONE;
    338     }
    339 
    340     @Override
    341     public void onFingerprintAuthFailed() {
    342         cleanup();
    343     }
    344 
    345     @Override
    346     public void onFingerprintError(int msgId, String errString) {
    347         cleanup();
    348     }
    349 
    350     private void cleanup() {
    351         releaseFingerprintWakeLock();
    352     }
    353 
    354     public void startKeyguardFadingAway() {
    355 
    356         // Disable brightness override when the ambient contents are fully invisible.
    357         mHandler.postDelayed(new Runnable() {
    358             @Override
    359             public void run() {
    360                 mStatusBarWindowManager.setForceDozeBrightness(false);
    361             }
    362         }, StatusBar.FADE_KEYGUARD_DURATION_PULSING);
    363     }
    364 
    365     public void finishKeyguardFadingAway() {
    366         resetMode();
    367     }
    368 
    369     private void resetMode() {
    370         mMode = MODE_NONE;
    371         mStatusBarWindowManager.setForceDozeBrightness(false);
    372         if (mStatusBar.getNavigationBarView() != null) {
    373             mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
    374         }
    375         mStatusBar.notifyFpAuthModeChanged();
    376     }
    377 
    378     private final WakefulnessLifecycle.Observer mWakefulnessObserver =
    379             new WakefulnessLifecycle.Observer() {
    380         @Override
    381         public void onFinishedWakingUp() {
    382             if (mPendingShowBouncer) {
    383                 FingerprintUnlockController.this.showBouncer();
    384             }
    385         }
    386     };
    387 
    388     private final ScreenLifecycle.Observer mScreenObserver =
    389             new ScreenLifecycle.Observer() {
    390                 @Override
    391                 public void onScreenTurnedOn() {
    392                     mHasScreenTurnedOnSinceAuthenticating = true;
    393                 }
    394             };
    395 
    396     public boolean hasScreenTurnedOnSinceAuthenticating() {
    397         return mHasScreenTurnedOnSinceAuthenticating;
    398     }
    399 
    400     public void dump(PrintWriter pw) {
    401         pw.println(" FingerprintUnlockController:");
    402         pw.print("   mMode="); pw.println(mMode);
    403         pw.print("   mWakeLock="); pw.println(mWakeLock);
    404     }
    405 
    406     /**
    407      * Successful authentication with fingerprint that wakes up the device.
    408      */
    409     public boolean isWakeAndUnlock() {
    410         return mMode == MODE_WAKE_AND_UNLOCK
    411                 || mMode == MODE_WAKE_AND_UNLOCK_PULSING
    412                 || mMode == MODE_WAKE_AND_UNLOCK_FROM_DREAM;
    413     }
    414 
    415     /**
    416      * Successful authentication with fingerprint when the screen was either on or off.
    417      */
    418     public boolean isFingerprintUnlock() {
    419         return isWakeAndUnlock() || mMode == MODE_UNLOCK;
    420     }
    421 }
    422