Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2007 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.internal.policy.impl;
     18 
     19 import com.android.internal.R;
     20 import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallback;
     21 import com.android.internal.policy.impl.KeyguardUpdateMonitor.InfoCallbackImpl;
     22 import com.android.internal.policy.impl.LockPatternKeyguardView.UnlockMode;
     23 import com.android.internal.telephony.IccCard;
     24 import com.android.internal.widget.LockPatternUtils;
     25 import com.android.internal.widget.LockScreenWidgetCallback;
     26 import com.android.internal.widget.LockScreenWidgetInterface;
     27 import com.android.internal.widget.TransportControlView;
     28 
     29 import android.accounts.Account;
     30 import android.accounts.AccountManager;
     31 import android.accounts.AccountManagerCallback;
     32 import android.accounts.AccountManagerFuture;
     33 import android.accounts.AuthenticatorException;
     34 import android.accounts.OperationCanceledException;
     35 import android.app.AlertDialog;
     36 import android.app.admin.DevicePolicyManager;
     37 import android.content.Context;
     38 import android.content.Intent;
     39 import android.content.res.Configuration;
     40 import android.content.res.Resources;
     41 import android.graphics.Bitmap;
     42 import android.graphics.Canvas;
     43 import android.graphics.Color;
     44 import android.graphics.ColorFilter;
     45 import android.graphics.PixelFormat;
     46 import android.graphics.drawable.ColorDrawable;
     47 import android.graphics.drawable.Drawable;
     48 import android.os.Bundle;
     49 import android.os.Parcelable;
     50 import android.os.PowerManager;
     51 import android.os.SystemClock;
     52 import android.os.SystemProperties;
     53 import android.telephony.TelephonyManager;
     54 import android.text.TextUtils;
     55 import android.util.Log;
     56 import android.util.Slog;
     57 import android.view.KeyEvent;
     58 import android.view.MotionEvent;
     59 import android.view.View;
     60 import android.view.WindowManager;
     61 import android.view.accessibility.AccessibilityManager;
     62 
     63 import java.io.IOException;
     64 
     65 
     66 /**
     67  * The host view for all of the screens of the pattern unlock screen.  There are
     68  * two {@link Mode}s of operation, lock and unlock.  This will show the appropriate
     69  * screen, and listen for callbacks via
     70  * {@link com.android.internal.policy.impl.KeyguardScreenCallback}
     71  * from the current screen.
     72  *
     73  * This view, in turn, communicates back to
     74  * {@link com.android.internal.policy.impl.KeyguardViewManager}
     75  * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
     76  */
     77 public class LockPatternKeyguardView extends KeyguardViewBase {
     78 
     79     private static final int TRANSPORT_USERACTIVITY_TIMEOUT = 10000;
     80 
     81     static final boolean DEBUG_CONFIGURATION = false;
     82 
     83     // time after launching EmergencyDialer before the screen goes blank.
     84     private static final int EMERGENCY_CALL_TIMEOUT = 10000;
     85 
     86     // intent action for launching emergency dialer activity.
     87     static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
     88 
     89     private static final boolean DEBUG = false;
     90     private static final String TAG = "LockPatternKeyguardView";
     91 
     92     private final KeyguardUpdateMonitor mUpdateMonitor;
     93     private final KeyguardWindowController mWindowController;
     94 
     95     private View mLockScreen;
     96     private View mUnlockScreen;
     97 
     98     private boolean mScreenOn;
     99     private boolean mWindowFocused = false;
    100     private boolean mEnableFallback = false; // assume no fallback UI until we know better
    101 
    102     private boolean mShowLockBeforeUnlock = false;
    103 
    104     // Interface to a biometric sensor that can optionally be used to unlock the device
    105     private BiometricSensorUnlock mBiometricUnlock;
    106     private final Object mBiometricUnlockStartupLock = new Object();
    107     // Long enough to stay visible while dialer comes up
    108     // Short enough to not be visible if the user goes back immediately
    109     private final int BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;
    110 
    111     private boolean mRequiresSim;
    112     // True if the biometric unlock should not be displayed.  For example, if there is an overlay on
    113     // lockscreen or the user is plugging in / unplugging the device.
    114     private boolean mSuppressBiometricUnlock;
    115     //True if a dialog is currently displaying on top of this window
    116     //Unlike other overlays, this does not close with a power button cycle
    117     private boolean mHasDialog = false;
    118     //True if this device is currently plugged in
    119     private boolean mPluggedIn;
    120     // True the first time lockscreen is showing after boot
    121     private static boolean sIsFirstAppearanceAfterBoot = true;
    122 
    123     // The music control widget
    124     private TransportControlView mTransportControlView;
    125 
    126     private Parcelable mSavedState;
    127 
    128     /**
    129      * Either a lock screen (an informational keyguard screen), or an unlock
    130      * screen (a means for unlocking the device) is shown at any given time.
    131      */
    132     enum Mode {
    133         LockScreen,
    134         UnlockScreen
    135     }
    136 
    137     /**
    138      * The different types screens available for {@link Mode#UnlockScreen}.
    139      * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode()
    140      */
    141     enum UnlockMode {
    142 
    143         /**
    144          * Unlock by drawing a pattern.
    145          */
    146         Pattern,
    147 
    148         /**
    149          * Unlock by entering a sim pin.
    150          */
    151         SimPin,
    152 
    153         /**
    154          * Unlock by entering a sim puk.
    155          */
    156         SimPuk,
    157 
    158         /**
    159          * Unlock by entering an account's login and password.
    160          */
    161         Account,
    162 
    163         /**
    164          * Unlock by entering a password or PIN
    165          */
    166         Password,
    167 
    168         /**
    169          * Unknown (uninitialized) value
    170          */
    171         Unknown
    172     }
    173 
    174     /**
    175      * The current mode.
    176      */
    177     private Mode mMode = Mode.LockScreen;
    178 
    179     /**
    180      * Keeps track of what mode the current unlock screen is (cached from most recent computation in
    181      * {@link #getUnlockMode}).
    182      */
    183     private UnlockMode mUnlockScreenMode = UnlockMode.Unknown;
    184 
    185     private boolean mForgotPattern;
    186 
    187     /**
    188      * If true, it means we are in the process of verifying that the user
    189      * can get past the lock screen per {@link #verifyUnlock()}
    190      */
    191     private boolean mIsVerifyUnlockOnly = false;
    192 
    193     /**
    194      * Used to lookup the state of the lock pattern
    195      */
    196     private final LockPatternUtils mLockPatternUtils;
    197 
    198     /**
    199      * The current configuration.
    200      */
    201     private Configuration mConfiguration;
    202 
    203     private Runnable mRecreateRunnable = new Runnable() {
    204         public void run() {
    205             Mode mode = mMode;
    206             // If we were previously in a locked state but now it's Unknown, it means the phone
    207             // was previously locked because of SIM state and has since been resolved. This
    208             // bit of code checks this condition and dismisses keyguard.
    209             boolean dismissAfterCreation = false;
    210             if (mode == Mode.UnlockScreen && getUnlockMode() == UnlockMode.Unknown) {
    211                 if (DEBUG) Log.v(TAG, "Switch to Mode.LockScreen because SIM unlocked");
    212                 mode = Mode.LockScreen;
    213                 dismissAfterCreation = true;
    214             }
    215             updateScreen(mode, true);
    216             restoreWidgetState();
    217             if (dismissAfterCreation) {
    218                 mKeyguardScreenCallback.keyguardDone(false);
    219             }
    220         }
    221     };
    222 
    223     private LockScreenWidgetCallback mWidgetCallback = new LockScreenWidgetCallback() {
    224         public void userActivity(View self) {
    225             mKeyguardScreenCallback.pokeWakelock(TRANSPORT_USERACTIVITY_TIMEOUT);
    226         }
    227 
    228         public void requestShow(View view) {
    229             if (DEBUG) Log.v(TAG, "View " + view + " requested show transports");
    230             view.setVisibility(View.VISIBLE);
    231 
    232             // TODO: examine all widgets to derive clock status
    233             mUpdateMonitor.reportClockVisible(false);
    234 
    235             // If there's not a bg protection view containing the transport, then show a black
    236             // background. Otherwise, allow the normal background to show.
    237             if (findViewById(R.id.transport_bg_protect) == null) {
    238                 // TODO: We should disable the wallpaper instead
    239                 setBackgroundColor(0xff000000);
    240             } else {
    241                 resetBackground();
    242             }
    243         }
    244 
    245         public void requestHide(View view) {
    246             if (DEBUG) Log.v(TAG, "View " + view + " requested hide transports");
    247             view.setVisibility(View.GONE);
    248 
    249             // TODO: examine all widgets to derive clock status
    250             mUpdateMonitor.reportClockVisible(true);
    251             resetBackground();
    252         }
    253 
    254         public boolean isVisible(View self) {
    255             // TODO: this should be up to the lockscreen to determine if the view
    256             // is currently showing. The idea is it can be used for the widget to
    257             // avoid doing work if it's not visible. For now just returns the view's
    258             // actual visibility.
    259             return self.getVisibility() == View.VISIBLE;
    260         }
    261     };
    262 
    263     /**
    264      * @return Whether we are stuck on the lock screen because the sim is
    265      *   missing.
    266      */
    267     private boolean stuckOnLockScreenBecauseSimMissing() {
    268         return mRequiresSim
    269                 && (!mUpdateMonitor.isDeviceProvisioned())
    270                 && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT ||
    271                     mUpdateMonitor.getSimState() == IccCard.State.PERM_DISABLED);
    272     }
    273 
    274     /**
    275      * The current {@link KeyguardScreen} will use this to communicate back to us.
    276      */
    277     KeyguardScreenCallback mKeyguardScreenCallback = new KeyguardScreenCallback() {
    278 
    279         public void goToLockScreen() {
    280             mForgotPattern = false;
    281             if (mIsVerifyUnlockOnly) {
    282                 // navigating away from unlock screen during verify mode means
    283                 // we are done and the user failed to authenticate.
    284                 mIsVerifyUnlockOnly = false;
    285                 getCallback().keyguardDone(false);
    286             } else {
    287                 updateScreen(Mode.LockScreen, false);
    288             }
    289         }
    290 
    291         public void goToUnlockScreen() {
    292             final IccCard.State simState = mUpdateMonitor.getSimState();
    293             if (stuckOnLockScreenBecauseSimMissing()
    294                      || (simState == IccCard.State.PUK_REQUIRED
    295                          && !mLockPatternUtils.isPukUnlockScreenEnable())){
    296                 // stuck on lock screen when sim missing or
    297                 // puk'd but puk unlock screen is disabled
    298                 return;
    299             }
    300             if (!isSecure()) {
    301                 getCallback().keyguardDone(true);
    302             } else {
    303                 updateScreen(Mode.UnlockScreen, false);
    304             }
    305         }
    306 
    307         public void forgotPattern(boolean isForgotten) {
    308             if (mEnableFallback) {
    309                 mForgotPattern = isForgotten;
    310                 updateScreen(Mode.UnlockScreen, false);
    311             }
    312         }
    313 
    314         public boolean isSecure() {
    315             return LockPatternKeyguardView.this.isSecure();
    316         }
    317 
    318         public boolean isVerifyUnlockOnly() {
    319             return mIsVerifyUnlockOnly;
    320         }
    321 
    322         public void recreateMe(Configuration config) {
    323             if (DEBUG) Log.v(TAG, "recreateMe()");
    324             removeCallbacks(mRecreateRunnable);
    325             post(mRecreateRunnable);
    326         }
    327 
    328         public void takeEmergencyCallAction() {
    329             mSuppressBiometricUnlock = true;
    330 
    331             if (mBiometricUnlock != null) {
    332                 if (mBiometricUnlock.isRunning()) {
    333                     // Continue covering backup lock until dialer comes up or call is resumed
    334                     mBiometricUnlock.show(BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT);
    335                 }
    336 
    337                 // We must ensure the biometric unlock is stopped when emergency call is pressed
    338                 mBiometricUnlock.stop();
    339             }
    340 
    341             pokeWakelock(EMERGENCY_CALL_TIMEOUT);
    342             if (TelephonyManager.getDefault().getCallState()
    343                     == TelephonyManager.CALL_STATE_OFFHOOK) {
    344                 mLockPatternUtils.resumeCall();
    345             } else {
    346                 Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
    347                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
    348                         | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    349                 getContext().startActivity(intent);
    350             }
    351         }
    352 
    353         public void pokeWakelock() {
    354             getCallback().pokeWakelock();
    355         }
    356 
    357         public void pokeWakelock(int millis) {
    358             getCallback().pokeWakelock(millis);
    359         }
    360 
    361         public void keyguardDone(boolean authenticated) {
    362             getCallback().keyguardDone(authenticated);
    363             mSavedState = null; // clear state so we re-establish when locked again
    364         }
    365 
    366         public void keyguardDoneDrawing() {
    367             // irrelevant to keyguard screen, they shouldn't be calling this
    368         }
    369 
    370         public void reportFailedUnlockAttempt() {
    371             mUpdateMonitor.reportFailedAttempt();
    372             final int failedAttempts = mUpdateMonitor.getFailedAttempts();
    373             if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts +
    374                 " (enableFallback=" + mEnableFallback + ")");
    375 
    376             final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
    377                     == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
    378 
    379             final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
    380                     .getMaximumFailedPasswordsForWipe(null);
    381 
    382             final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
    383                     - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
    384 
    385             final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
    386                     (failedAttemptsBeforeWipe - failedAttempts)
    387                     : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
    388 
    389             if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
    390                 // If we reach this code, it means the user has installed a DevicePolicyManager
    391                 // that requests device wipe after N attempts.  Once we get below the grace
    392                 // period, we'll post this dialog every time as a clear warning until the
    393                 // bombshell hits and the device is wiped.
    394                 if (remainingBeforeWipe > 0) {
    395                     showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
    396                 } else {
    397                     // Too many attempts. The device will be wiped shortly.
    398                     Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
    399                     showWipeDialog(failedAttempts);
    400                 }
    401             } else {
    402                 boolean showTimeout =
    403                     (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
    404                 if (usingPattern && mEnableFallback) {
    405                     if (failedAttempts == failedAttemptWarning) {
    406                         showAlmostAtAccountLoginDialog();
    407                         showTimeout = false; // don't show both dialogs
    408                     } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
    409                         mLockPatternUtils.setPermanentlyLocked(true);
    410                         updateScreen(mMode, false);
    411                         // don't show timeout dialog because we show account unlock screen next
    412                         showTimeout = false;
    413                     }
    414                 }
    415                 if (showTimeout) {
    416                     showTimeoutDialog();
    417                 }
    418             }
    419             mLockPatternUtils.reportFailedPasswordAttempt();
    420         }
    421 
    422         public boolean doesFallbackUnlockScreenExist() {
    423             return mEnableFallback;
    424         }
    425 
    426         public void reportSuccessfulUnlockAttempt() {
    427             mLockPatternUtils.reportSuccessfulPasswordAttempt();
    428         }
    429     };
    430 
    431     /**
    432      * @param context Used to inflate, and create views.
    433      * @param callback Keyguard callback object for pokewakelock(), etc.
    434      * @param updateMonitor Knows the state of the world, and passed along to each
    435      *   screen so they can use the knowledge, and also register for callbacks
    436      *   on dynamic information.
    437      * @param lockPatternUtils Used to look up state of lock pattern.
    438      */
    439     public LockPatternKeyguardView(
    440             Context context, KeyguardViewCallback callback, KeyguardUpdateMonitor updateMonitor,
    441             LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
    442         super(context, callback);
    443 
    444         mConfiguration = context.getResources().getConfiguration();
    445         mEnableFallback = false;
    446         mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
    447         mUpdateMonitor = updateMonitor;
    448         mLockPatternUtils = lockPatternUtils;
    449         mWindowController = controller;
    450         mSuppressBiometricUnlock = sIsFirstAppearanceAfterBoot;
    451         sIsFirstAppearanceAfterBoot = false;
    452         mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
    453         mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
    454         mUpdateMonitor.registerInfoCallback(mInfoCallback);
    455 
    456         /**
    457          * We'll get key events the current screen doesn't use. see
    458          * {@link KeyguardViewBase#onKeyDown(int, android.view.KeyEvent)}
    459          */
    460         setFocusableInTouchMode(true);
    461         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
    462 
    463         updateScreen(getInitialMode(), false);
    464         maybeEnableFallback(context);
    465     }
    466 
    467     private class AccountAnalyzer implements AccountManagerCallback<Bundle> {
    468         private final AccountManager mAccountManager;
    469         private final Account[] mAccounts;
    470         private int mAccountIndex;
    471 
    472         private AccountAnalyzer(AccountManager accountManager) {
    473             mAccountManager = accountManager;
    474             mAccounts = accountManager.getAccountsByType("com.google");
    475         }
    476 
    477         private void next() {
    478             // if we are ready to enable the fallback or if we depleted the list of accounts
    479             // then finish and get out
    480             if (mEnableFallback || mAccountIndex >= mAccounts.length) {
    481                 if (mUnlockScreen == null) {
    482                     if (DEBUG) Log.w(TAG, "no unlock screen when trying to enable fallback");
    483                 } else if (mUnlockScreen instanceof PatternUnlockScreen) {
    484                     ((PatternUnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback);
    485                 }
    486                 return;
    487             }
    488 
    489             // lookup the confirmCredentials intent for the current account
    490             mAccountManager.confirmCredentials(mAccounts[mAccountIndex], null, null, this, null);
    491         }
    492 
    493         public void start() {
    494             mEnableFallback = false;
    495             mAccountIndex = 0;
    496             next();
    497         }
    498 
    499         public void run(AccountManagerFuture<Bundle> future) {
    500             try {
    501                 Bundle result = future.getResult();
    502                 if (result.getParcelable(AccountManager.KEY_INTENT) != null) {
    503                     mEnableFallback = true;
    504                 }
    505             } catch (OperationCanceledException e) {
    506                 // just skip the account if we are unable to query it
    507             } catch (IOException e) {
    508                 // just skip the account if we are unable to query it
    509             } catch (AuthenticatorException e) {
    510                 // just skip the account if we are unable to query it
    511             } finally {
    512                 mAccountIndex++;
    513                 next();
    514             }
    515         }
    516     }
    517 
    518     private void maybeEnableFallback(Context context) {
    519         // Ask the account manager if we have an account that can be used as a
    520         // fallback in case the user forgets his pattern.
    521         AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context));
    522         accountAnalyzer.start();
    523     }
    524 
    525 
    526     // TODO:
    527     // This overloaded method was added to workaround a race condition in the framework between
    528     // notification for orientation changed, layout() and switching resources.  This code attempts
    529     // to avoid drawing the incorrect layout while things are in transition.  The method can just
    530     // be removed once the race condition is fixed. See bugs 2262578 and 2292713.
    531     @Override
    532     protected void dispatchDraw(Canvas canvas) {
    533         if (DEBUG) Log.v(TAG, "*** dispatchDraw() time: " + SystemClock.elapsedRealtime());
    534         super.dispatchDraw(canvas);
    535     }
    536 
    537     @Override
    538     public void reset() {
    539         mIsVerifyUnlockOnly = false;
    540         mForgotPattern = false;
    541         if (DEBUG) Log.v(TAG, "reset()");
    542         post(mRecreateRunnable);
    543     }
    544 
    545     @Override
    546     public void onScreenTurnedOff() {
    547         if (DEBUG) Log.d(TAG, "screen off");
    548         mScreenOn = false;
    549         mForgotPattern = false;
    550 
    551         // Emulate activity life-cycle for both lock and unlock screen.
    552         if (mLockScreen != null) {
    553             ((KeyguardScreen) mLockScreen).onPause();
    554         }
    555         if (mUnlockScreen != null) {
    556             ((KeyguardScreen) mUnlockScreen).onPause();
    557         }
    558 
    559         saveWidgetState();
    560 
    561         if (mBiometricUnlock != null) {
    562             // The biometric unlock must stop when screen turns off.
    563             mBiometricUnlock.stop();
    564         }
    565     }
    566 
    567     @Override
    568     public void onScreenTurnedOn() {
    569         if (DEBUG) Log.d(TAG, "screen on");
    570         boolean startBiometricUnlock = false;
    571         // Start the biometric unlock if and only if the screen is both on and focused
    572         synchronized(mBiometricUnlockStartupLock) {
    573             mScreenOn = true;
    574             startBiometricUnlock = mWindowFocused;
    575         }
    576 
    577         show();
    578 
    579         restoreWidgetState();
    580 
    581         if (mBiometricUnlock != null && startBiometricUnlock) {
    582             maybeStartBiometricUnlock();
    583         }
    584     }
    585 
    586     private void saveWidgetState() {
    587         if (mTransportControlView != null) {
    588             if (DEBUG) Log.v(TAG, "Saving widget state");
    589             mSavedState = mTransportControlView.onSaveInstanceState();
    590         }
    591     }
    592 
    593     private void restoreWidgetState() {
    594         if (mTransportControlView != null) {
    595             if (DEBUG) Log.v(TAG, "Restoring widget state");
    596             if (mSavedState != null) {
    597                 mTransportControlView.onRestoreInstanceState(mSavedState);
    598             }
    599         }
    600     }
    601 
    602     /**
    603      * Stop the biometric unlock if something covers this window (such as an alarm)
    604      * Start the biometric unlock if the lockscreen window just came into focus and the screen is on
    605      */
    606     @Override
    607     public void onWindowFocusChanged (boolean hasWindowFocus) {
    608         if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused");
    609 
    610         boolean startBiometricUnlock = false;
    611         // Start the biometric unlock if and only if the screen is both on and focused
    612         synchronized(mBiometricUnlockStartupLock) {
    613             if (mScreenOn && !mWindowFocused) startBiometricUnlock = hasWindowFocus;
    614             mWindowFocused = hasWindowFocus;
    615         }
    616         if (!hasWindowFocus) {
    617             if (mBiometricUnlock != null) {
    618                 mSuppressBiometricUnlock = true;
    619                 mBiometricUnlock.stop();
    620                 mBiometricUnlock.hide();
    621             }
    622         } else {
    623             mHasDialog = false;
    624             if (mBiometricUnlock != null && startBiometricUnlock) {
    625                 maybeStartBiometricUnlock();
    626             }
    627         }
    628     }
    629 
    630     @Override
    631     public void show() {
    632         // Emulate activity life-cycle for both lock and unlock screen.
    633         if (mLockScreen != null) {
    634             ((KeyguardScreen) mLockScreen).onResume();
    635         }
    636         if (mUnlockScreen != null) {
    637             ((KeyguardScreen) mUnlockScreen).onResume();
    638         }
    639 
    640         if (mBiometricUnlock != null && mSuppressBiometricUnlock) {
    641             mBiometricUnlock.hide();
    642         }
    643     }
    644 
    645     private void recreateLockScreen() {
    646         if (mLockScreen != null) {
    647             ((KeyguardScreen) mLockScreen).onPause();
    648             ((KeyguardScreen) mLockScreen).cleanUp();
    649             removeView(mLockScreen);
    650         }
    651 
    652         mLockScreen = createLockScreen();
    653         mLockScreen.setVisibility(View.INVISIBLE);
    654         addView(mLockScreen);
    655     }
    656 
    657     private void recreateUnlockScreen(UnlockMode unlockMode) {
    658         if (mUnlockScreen != null) {
    659             ((KeyguardScreen) mUnlockScreen).onPause();
    660             ((KeyguardScreen) mUnlockScreen).cleanUp();
    661             removeView(mUnlockScreen);
    662         }
    663 
    664         mUnlockScreen = createUnlockScreenFor(unlockMode);
    665         mUnlockScreen.setVisibility(View.INVISIBLE);
    666         addView(mUnlockScreen);
    667     }
    668 
    669     @Override
    670     protected void onDetachedFromWindow() {
    671         mUpdateMonitor.removeCallback(mInfoCallback);
    672 
    673         removeCallbacks(mRecreateRunnable);
    674 
    675         if (mBiometricUnlock != null) {
    676             // When view is hidden, we need to stop the biometric unlock
    677             // e.g., when device becomes unlocked
    678             mBiometricUnlock.stop();
    679         }
    680 
    681         super.onDetachedFromWindow();
    682     }
    683 
    684     protected void onConfigurationChanged(Configuration newConfig) {
    685         Resources resources = getResources();
    686         mShowLockBeforeUnlock = resources.getBoolean(R.bool.config_enableLockBeforeUnlockScreen);
    687         mConfiguration = newConfig;
    688         if (DEBUG_CONFIGURATION) Log.v(TAG, "**** re-creating lock screen since config changed");
    689         saveWidgetState();
    690         removeCallbacks(mRecreateRunnable);
    691         if (DEBUG) Log.v(TAG, "recreating lockscreen because config changed");
    692         post(mRecreateRunnable);
    693     }
    694 
    695     InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
    696 
    697         @Override
    698         public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
    699                 int batteryLevel) {
    700             // When someone plugs in or unplugs the device, we hide the biometric sensor area and
    701             // suppress its startup for the next onScreenTurnedOn().  Since plugging/unplugging
    702             // causes the screen to turn on, the biometric unlock would start if it wasn't
    703             // suppressed.
    704             //
    705             // However, if the biometric unlock is already running, we do not want to interrupt it.
    706             if (mBiometricUnlock != null && mPluggedIn != pluggedIn
    707                     && !mBiometricUnlock.isRunning()) {
    708                 mBiometricUnlock.stop();
    709                 mBiometricUnlock.hide();
    710                 mSuppressBiometricUnlock = true;
    711             }
    712             mPluggedIn = pluggedIn;
    713         }
    714 
    715         @Override
    716         public void onClockVisibilityChanged() {
    717             int visFlags = (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK)
    718                     | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0);
    719             Log.v(TAG, "Set visibility on " + this + " to " + visFlags);
    720             setSystemUiVisibility(visFlags);
    721         }
    722 
    723         // We need to stop the biometric unlock when a phone call comes in
    724         @Override
    725         public void onPhoneStateChanged(int phoneState) {
    726             if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
    727             if (mBiometricUnlock != null && phoneState == TelephonyManager.CALL_STATE_RINGING) {
    728                 mSuppressBiometricUnlock = true;
    729                 mBiometricUnlock.stop();
    730                 mBiometricUnlock.hide();
    731             }
    732         }
    733 
    734         @Override
    735         public void onUserChanged(int userId) {
    736             if (mBiometricUnlock != null) {
    737                 mBiometricUnlock.stop();
    738             }
    739             mLockPatternUtils.setCurrentUser(userId);
    740             updateScreen(getInitialMode(), true);
    741         }
    742     };
    743 
    744     @Override
    745     protected boolean dispatchHoverEvent(MotionEvent event) {
    746         // Do not let the screen to get locked while the user is disabled and touch
    747         // exploring. A blind user will need significantly more time to find and
    748         // interact with the lock screen views.
    749         AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
    750         if (accessibilityManager.isEnabled() && accessibilityManager.isTouchExplorationEnabled()) {
    751             getCallback().pokeWakelock();
    752         }
    753         return super.dispatchHoverEvent(event);
    754     }
    755 
    756     @Override
    757     public void wakeWhenReadyTq(int keyCode) {
    758         if (DEBUG) Log.d(TAG, "onWakeKey");
    759         if (keyCode == KeyEvent.KEYCODE_MENU && isSecure() && (mMode == Mode.LockScreen)
    760                 && (mUpdateMonitor.getSimState() != IccCard.State.PUK_REQUIRED)) {
    761             if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
    762             updateScreen(Mode.UnlockScreen, false);
    763             getCallback().pokeWakelock();
    764         } else {
    765             if (DEBUG) Log.d(TAG, "poking wake lock immediately");
    766             getCallback().pokeWakelock();
    767         }
    768     }
    769 
    770     @Override
    771     public void verifyUnlock() {
    772         if (!isSecure()) {
    773             // non-secure keyguard screens are successfull by default
    774             getCallback().keyguardDone(true);
    775         } else if (mUnlockScreenMode != UnlockMode.Pattern
    776                 && mUnlockScreenMode != UnlockMode.Password) {
    777             // can only verify unlock when in pattern/password mode
    778             getCallback().keyguardDone(false);
    779         } else {
    780             // otherwise, go to the unlock screen, see if they can verify it
    781             mIsVerifyUnlockOnly = true;
    782             updateScreen(Mode.UnlockScreen, false);
    783         }
    784     }
    785 
    786     @Override
    787     public void cleanUp() {
    788         if (mLockScreen != null) {
    789             ((KeyguardScreen) mLockScreen).onPause();
    790             ((KeyguardScreen) mLockScreen).cleanUp();
    791             this.removeView(mLockScreen);
    792             mLockScreen = null;
    793         }
    794         if (mUnlockScreen != null) {
    795             ((KeyguardScreen) mUnlockScreen).onPause();
    796             ((KeyguardScreen) mUnlockScreen).cleanUp();
    797             this.removeView(mUnlockScreen);
    798             mUnlockScreen = null;
    799         }
    800         mUpdateMonitor.removeCallback(this);
    801         if (mBiometricUnlock != null) {
    802             mBiometricUnlock.cleanUp();
    803         }
    804     }
    805 
    806     private boolean isSecure() {
    807         UnlockMode unlockMode = getUnlockMode();
    808         boolean secure = false;
    809         switch (unlockMode) {
    810             case Pattern:
    811                 secure = mLockPatternUtils.isLockPatternEnabled();
    812                 break;
    813             case SimPin:
    814                 secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED;
    815                 break;
    816             case SimPuk:
    817                 secure = mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED;
    818                 break;
    819             case Account:
    820                 secure = true;
    821                 break;
    822             case Password:
    823                 secure = mLockPatternUtils.isLockPasswordEnabled();
    824                 break;
    825             case Unknown:
    826                 // This means no security is set up
    827                 break;
    828             default:
    829                 throw new IllegalStateException("unknown unlock mode " + unlockMode);
    830         }
    831         return secure;
    832     }
    833 
    834     private void updateScreen(Mode mode, boolean force) {
    835 
    836         if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode
    837                 + " last mode=" + mMode + ", force = " + force, new RuntimeException());
    838 
    839         mMode = mode;
    840 
    841         // Re-create the lock screen if necessary
    842         if (mode == Mode.LockScreen || mShowLockBeforeUnlock) {
    843             if (force || mLockScreen == null) {
    844                 recreateLockScreen();
    845             }
    846         }
    847 
    848         // Re-create the unlock screen if necessary.
    849         final UnlockMode unlockMode = getUnlockMode();
    850         if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
    851             if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
    852                 recreateUnlockScreen(unlockMode);
    853             }
    854         }
    855 
    856         // visibleScreen should never be null
    857         final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
    858         final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;
    859 
    860         // do this before changing visibility so focus isn't requested before the input
    861         // flag is set
    862         mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
    863 
    864         if (DEBUG_CONFIGURATION) {
    865             Log.v(TAG, "Gone=" + goneScreen);
    866             Log.v(TAG, "Visible=" + visibleScreen);
    867         }
    868 
    869         if (mScreenOn) {
    870             if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) {
    871                 ((KeyguardScreen) goneScreen).onPause();
    872             }
    873             if (visibleScreen.getVisibility() != View.VISIBLE) {
    874                 ((KeyguardScreen) visibleScreen).onResume();
    875             }
    876         }
    877 
    878         if (goneScreen != null) {
    879             goneScreen.setVisibility(View.GONE);
    880         }
    881         visibleScreen.setVisibility(View.VISIBLE);
    882         requestLayout();
    883 
    884         if (!visibleScreen.requestFocus()) {
    885             throw new IllegalStateException("keyguard screen must be able to take "
    886                     + "focus when shown " + visibleScreen.getClass().getCanonicalName());
    887         }
    888     }
    889 
    890     View createLockScreen() {
    891         View lockView = new LockScreen(
    892                 mContext,
    893                 mConfiguration,
    894                 mLockPatternUtils,
    895                 mUpdateMonitor,
    896                 mKeyguardScreenCallback);
    897         initializeTransportControlView(lockView);
    898         return lockView;
    899     }
    900 
    901     View createUnlockScreenFor(UnlockMode unlockMode) {
    902         View unlockView = null;
    903 
    904         if (DEBUG) Log.d(TAG,
    905                 "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
    906 
    907         if (unlockMode == UnlockMode.Pattern) {
    908             PatternUnlockScreen view = new PatternUnlockScreen(
    909                     mContext,
    910                     mConfiguration,
    911                     mLockPatternUtils,
    912                     mUpdateMonitor,
    913                     mKeyguardScreenCallback,
    914                     mUpdateMonitor.getFailedAttempts());
    915             view.setEnableFallback(mEnableFallback);
    916             unlockView = view;
    917         } else if (unlockMode == UnlockMode.SimPuk) {
    918             unlockView = new SimPukUnlockScreen(
    919                     mContext,
    920                     mConfiguration,
    921                     mUpdateMonitor,
    922                     mKeyguardScreenCallback,
    923                     mLockPatternUtils);
    924         } else if (unlockMode == UnlockMode.SimPin) {
    925             unlockView = new SimUnlockScreen(
    926                     mContext,
    927                     mConfiguration,
    928                     mUpdateMonitor,
    929                     mKeyguardScreenCallback,
    930                     mLockPatternUtils);
    931         } else if (unlockMode == UnlockMode.Account) {
    932             try {
    933                 unlockView = new AccountUnlockScreen(
    934                         mContext,
    935                         mConfiguration,
    936                         mUpdateMonitor,
    937                         mKeyguardScreenCallback,
    938                         mLockPatternUtils);
    939             } catch (IllegalStateException e) {
    940                 Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
    941                       + " (IAccountsService isn't available)");
    942                 // TODO: Need a more general way to provide a
    943                 // platform-specific fallback UI here.
    944                 // For now, if we can't display the account login
    945                 // unlock UI, just bring back the regular "Pattern" unlock mode.
    946 
    947                 // (We do this by simply returning a regular UnlockScreen
    948                 // here.  This means that the user will still see the
    949                 // regular pattern unlock UI, regardless of the value of
    950                 // mUnlockScreenMode or whether or not we're in the
    951                 // "permanently locked" state.)
    952                 return createUnlockScreenFor(UnlockMode.Pattern);
    953             }
    954         } else if (unlockMode == UnlockMode.Password) {
    955             unlockView = new PasswordUnlockScreen(
    956                     mContext,
    957                     mConfiguration,
    958                     mLockPatternUtils,
    959                     mUpdateMonitor,
    960                     mKeyguardScreenCallback);
    961         } else {
    962             throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
    963         }
    964         initializeTransportControlView(unlockView);
    965         initializeBiometricUnlockView(unlockView);
    966 
    967         mUnlockScreenMode = unlockMode;
    968         return unlockView;
    969     }
    970 
    971     private void initializeTransportControlView(View view) {
    972         mTransportControlView = (TransportControlView) view.findViewById(R.id.transport);
    973         if (mTransportControlView == null) {
    974             if (DEBUG) Log.w(TAG, "Couldn't find transport control widget");
    975         } else {
    976             mUpdateMonitor.reportClockVisible(true);
    977             mTransportControlView.setVisibility(View.GONE); // hide until it requests being shown.
    978             mTransportControlView.setCallback(mWidgetCallback);
    979         }
    980     }
    981 
    982     /**
    983      * This returns false if there is any condition that indicates that the biometric unlock should
    984      * not be used before the next time the unlock screen is recreated.  In other words, if this
    985      * returns false there is no need to even construct the biometric unlock.
    986      */
    987     private boolean useBiometricUnlock() {
    988         final UnlockMode unlockMode = getUnlockMode();
    989         final boolean backupIsTimedOut = (mUpdateMonitor.getFailedAttempts() >=
    990                 LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
    991         return (mLockPatternUtils.usingBiometricWeak() &&
    992                 mLockPatternUtils.isBiometricWeakInstalled() &&
    993                 !mUpdateMonitor.getMaxBiometricUnlockAttemptsReached() &&
    994                 !backupIsTimedOut &&
    995                 (unlockMode == UnlockMode.Pattern || unlockMode == UnlockMode.Password));
    996     }
    997 
    998     private void initializeBiometricUnlockView(View view) {
    999         boolean restartBiometricUnlock = false;
   1000 
   1001         if (mBiometricUnlock != null) {
   1002             restartBiometricUnlock = mBiometricUnlock.stop();
   1003         }
   1004 
   1005         // Prevents biometric unlock from coming up immediately after a phone call or if there
   1006         // is a dialog on top of lockscreen. It is only updated if the screen is off because if the
   1007         // screen is on it's either because of an orientation change, or when it first boots.
   1008         // In both those cases, we don't want to override the current value of
   1009         // mSuppressBiometricUnlock and instead want to use the previous value.
   1010         if (!mScreenOn) {
   1011             mSuppressBiometricUnlock =
   1012                     mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE
   1013                     || mHasDialog;
   1014         }
   1015 
   1016         // If the biometric unlock is not being used, we don't bother constructing it.  Then we can
   1017         // simply check if it is null when deciding whether we should make calls to it.
   1018         mBiometricUnlock = null;
   1019         if (useBiometricUnlock()) {
   1020             // TODO: make faceLockAreaView a more general biometricUnlockView
   1021             // We will need to add our Face Unlock specific child views programmatically in
   1022             // initializeView rather than having them in the XML files.
   1023             View biometricUnlockView = view.findViewById(R.id.faceLockAreaView);
   1024             if (biometricUnlockView != null) {
   1025                 mBiometricUnlock = new FaceUnlock(mContext, mUpdateMonitor, mLockPatternUtils,
   1026                         mKeyguardScreenCallback);
   1027                 mBiometricUnlock.initializeView(biometricUnlockView);
   1028 
   1029                 // If this is being called because the screen turned off, we want to cover the
   1030                 // backup lock so it is covered when the screen turns back on.
   1031                 if (!mScreenOn) mBiometricUnlock.show(0);
   1032             } else {
   1033                 Log.w(TAG, "Couldn't find biometric unlock view");
   1034             }
   1035         }
   1036 
   1037         if (mBiometricUnlock != null && restartBiometricUnlock) {
   1038             maybeStartBiometricUnlock();
   1039         }
   1040     }
   1041 
   1042     /**
   1043      * Given the current state of things, what should be the initial mode of
   1044      * the lock screen (lock or unlock).
   1045      */
   1046     private Mode getInitialMode() {
   1047         final IccCard.State simState = mUpdateMonitor.getSimState();
   1048         if (stuckOnLockScreenBecauseSimMissing() ||
   1049                 (simState == IccCard.State.PUK_REQUIRED &&
   1050                         !mLockPatternUtils.isPukUnlockScreenEnable())) {
   1051             return Mode.LockScreen;
   1052         } else {
   1053             if (!isSecure() || mShowLockBeforeUnlock) {
   1054                 return Mode.LockScreen;
   1055             } else {
   1056                 return Mode.UnlockScreen;
   1057             }
   1058         }
   1059     }
   1060 
   1061     /**
   1062      * Given the current state of things, what should the unlock screen be?
   1063      */
   1064     private UnlockMode getUnlockMode() {
   1065         final IccCard.State simState = mUpdateMonitor.getSimState();
   1066         UnlockMode currentMode;
   1067         if (simState == IccCard.State.PIN_REQUIRED) {
   1068             currentMode = UnlockMode.SimPin;
   1069         } else if (simState == IccCard.State.PUK_REQUIRED) {
   1070             currentMode = UnlockMode.SimPuk;
   1071         } else {
   1072             final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality();
   1073             switch (mode) {
   1074                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
   1075                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
   1076                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
   1077                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
   1078                     currentMode = UnlockMode.Password;
   1079                     break;
   1080                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
   1081                 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
   1082                     if (mLockPatternUtils.isLockPatternEnabled()) {
   1083                         // "forgot pattern" button is only available in the pattern mode...
   1084                         if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
   1085                             currentMode = UnlockMode.Account;
   1086                         } else {
   1087                             currentMode = UnlockMode.Pattern;
   1088                         }
   1089                     } else {
   1090                         currentMode = UnlockMode.Unknown;
   1091                     }
   1092                     break;
   1093                 default:
   1094                    throw new IllegalStateException("Unknown unlock mode:" + mode);
   1095             }
   1096         }
   1097         return currentMode;
   1098     }
   1099 
   1100     private void showDialog(String title, String message) {
   1101         mHasDialog = true;
   1102         final AlertDialog dialog = new AlertDialog.Builder(mContext)
   1103             .setTitle(title)
   1104             .setMessage(message)
   1105             .setNeutralButton(R.string.ok, null)
   1106             .create();
   1107         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
   1108         dialog.show();
   1109     }
   1110 
   1111     private void showTimeoutDialog() {
   1112         int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
   1113         int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message;
   1114         if (getUnlockMode() == UnlockMode.Password) {
   1115             if(mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
   1116                 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
   1117                 messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message;
   1118             } else {
   1119                 messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message;
   1120             }
   1121         }
   1122         String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(),
   1123                 timeoutInSeconds);
   1124 
   1125         showDialog(null, message);
   1126     }
   1127 
   1128     private void showAlmostAtAccountLoginDialog() {
   1129         final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
   1130         final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
   1131                 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
   1132         String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin,
   1133                 count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
   1134         showDialog(null, message);
   1135     }
   1136 
   1137     private void showAlmostAtWipeDialog(int attempts, int remaining) {
   1138         int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
   1139         String message = mContext.getString(
   1140                 R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining);
   1141         showDialog(null, message);
   1142     }
   1143 
   1144     private void showWipeDialog(int attempts) {
   1145         String message = mContext.getString(
   1146                 R.string.lockscreen_failed_attempts_now_wiping, attempts);
   1147         showDialog(null, message);
   1148     }
   1149 
   1150     /**
   1151      * Used to put wallpaper on the background of the lock screen.  Centers it
   1152      * Horizontally and pins the bottom (assuming that the lock screen is aligned
   1153      * with the bottom, so the wallpaper should extend above the top into the
   1154      * status bar).
   1155      */
   1156     static private class FastBitmapDrawable extends Drawable {
   1157         private Bitmap mBitmap;
   1158         private int mOpacity;
   1159 
   1160         private FastBitmapDrawable(Bitmap bitmap) {
   1161             mBitmap = bitmap;
   1162             mOpacity = mBitmap.hasAlpha() ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
   1163         }
   1164 
   1165         @Override
   1166         public void draw(Canvas canvas) {
   1167             canvas.drawBitmap(
   1168                     mBitmap,
   1169                     (getBounds().width() - mBitmap.getWidth()) / 2,
   1170                     (getBounds().height() - mBitmap.getHeight()),
   1171                     null);
   1172         }
   1173 
   1174         @Override
   1175         public int getOpacity() {
   1176             return mOpacity;
   1177         }
   1178 
   1179         @Override
   1180         public void setAlpha(int alpha) {
   1181         }
   1182 
   1183         @Override
   1184         public void setColorFilter(ColorFilter cf) {
   1185         }
   1186 
   1187         @Override
   1188         public int getIntrinsicWidth() {
   1189             return mBitmap.getWidth();
   1190         }
   1191 
   1192         @Override
   1193         public int getIntrinsicHeight() {
   1194             return mBitmap.getHeight();
   1195         }
   1196 
   1197         @Override
   1198         public int getMinimumWidth() {
   1199             return mBitmap.getWidth();
   1200         }
   1201 
   1202         @Override
   1203         public int getMinimumHeight() {
   1204             return mBitmap.getHeight();
   1205         }
   1206     }
   1207 
   1208     /**
   1209      * Starts the biometric unlock if it should be started based on a number of factors including
   1210      * the mSuppressBiometricUnlock flag.  If it should not be started, it hides the biometric
   1211      * unlock area.
   1212      */
   1213     private void maybeStartBiometricUnlock() {
   1214         if (mBiometricUnlock != null) {
   1215             final boolean backupIsTimedOut = (mUpdateMonitor.getFailedAttempts() >=
   1216                     LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
   1217             if (!mSuppressBiometricUnlock
   1218                     && mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
   1219                     && !mUpdateMonitor.getMaxBiometricUnlockAttemptsReached()
   1220                     && !backupIsTimedOut) {
   1221                 mBiometricUnlock.start();
   1222             } else {
   1223                 mBiometricUnlock.hide();
   1224             }
   1225         }
   1226     }
   1227 }
   1228