Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3223e253 authored by Brian Colonna's avatar Brian Colonna
Browse files

Changed FUL calls to more general biometric sensor calls

This is another step toward fix 5460649 - cleanup
LockPatternKeyguardView (LPKV).

After this change, LPKV has minimal knowledge of FUL.  FUL now
implements a new BiometricSensorUnlock interface and LPKV talks to
that interface.  Other biometric sensors can implement the same
interface such that LPKV doesn't need to know much about what type
of biometric sensor is being used or its implementation.

The new interface has better, more general function names, so some
function names in FaceUnlock.java were changed.  Some of the functions
in FaceUnlock.java were also reordered to match the interface.

This change should not change the behavior of FUL.  There are two
places where code functionality was changed:

1) There was a showArea() function and a showAreaWithTimeout()
function that were both called from LPKV.  To simplify the interface,
only a show() function is provided - it takes a timeout and if the
timeout is 0 it doesn't do the timeout.

2) There was a stopIfRunning() function that did a check to make sure
FUL was running.  If FUL was running, it stopped FUL.  Then it
returned a boolean indicating if it had been running.  LPKV sometimes
needs to know if FUL was running so it knows if it should restart FUL.
To simplify the interface, a single stop() function is provided which
returns whether or not it was running.  I believe the 'if running'
check was redundant and that there was no case where calling stop()
when it wasn't running would cause any badness.

Change-Id: I717268f360aed823e603df8e687cd107aa69ae11
parent 18ec7a95
Loading
Loading
Loading
Loading
+52 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.policy.impl;

import android.view.View;

interface BiometricSensorUnlock {
    // Returns 'true' if the biometric sensor is available and is selected by user.
    public boolean installedAndSelected();

    // Returns 'true' if the biometric sensor has started its unlock procedure but has not yet
    // accepted or rejected the user.
    public boolean isRunning();

    // Show the interface, but don't start the unlock procedure.  The interface should disappear
    // after the specified timeout.  If the timeout is 0, the interface shows until another event,
    // such as calling hide(), causes it to disappear.
    public void show(long timeoutMilliseconds);

    // Hide the interface, if any, exposing the lockscreen.
    public void hide();

    // Stop the unlock procedure if running.  Returns 'true' if it was in fact running.
    public boolean stop();

    // Start the unlock procedure.  Returns ‘false’ if it can’t be started or if the backup should
    // be used.
    public boolean start(boolean suppressBiometricUnlock);

    // Provide a view to work within.
    public void initializeAreaView(View topView);

    // Clean up any resources used by the biometric unlock.
    public void cleanUp();

    // Returns the Device Policy Manager quality (e.g. PASSWORD_QUALITY_BIOMETRIC_WEAK).
    public int getQuality();
}
+89 −92
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import com.android.internal.policy.IFaceLockCallback;
import com.android.internal.policy.IFaceLockInterface;
import com.android.internal.policy.IFaceLockInterface;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils;


import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
@@ -33,7 +34,7 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Log;
import android.view.View;
import android.view.View;


public class FaceUnlock implements Handler.Callback {
public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {


    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;
    private static final String TAG = "FULLockscreen";
    private static final String TAG = "FULLockscreen";
@@ -52,10 +53,6 @@ public class FaceUnlock implements Handler.Callback {
    private boolean mServiceRunning = false;
    private boolean mServiceRunning = false;
    private final Object mServiceRunningLock = new Object();
    private final Object mServiceRunningLock = new Object();


    // Long enough to stay visible while dialer comes up
    // Short enough to not be visible if the user goes back immediately
    private final int VIEW_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;

    // Long enough to stay visible while the service starts
    // Long enough to stay visible while the service starts
    // Short enough to not have to wait long for backup if service fails to start or crashes
    // Short enough to not have to wait long for backup if service fails to start or crashes
    // The service can take a couple of seconds to start on the first try after boot
    // The service can take a couple of seconds to start on the first try after boot
@@ -80,22 +77,65 @@ public class FaceUnlock implements Handler.Callback {
        mHandler = new Handler(this);
        mHandler = new Handler(this);
    }
    }


    public void cleanUp() {
    // Indicates whether FaceLock is in use
    public boolean installedAndSelected() {
        return (mLockPatternUtils.usingBiometricWeak() &&
                mLockPatternUtils.isBiometricWeakInstalled());
    }

    public boolean isRunning() {
        return mServiceRunning;
    }

    // Shows the FaceLock area for a period of time
    public void show(long timeoutMillis) {
        showArea();
        if (timeoutMillis > 0)
            mHandler.sendEmptyMessageDelayed(MSG_HIDE_AREA_VIEW, timeoutMillis);
    }

    // Hides the FaceLock area immediately
    public void hide() {
        // Remove messages to prevent a delayed show message from undo-ing the hide
        removeAreaDisplayMessages();
        mHandler.sendEmptyMessage(MSG_HIDE_AREA_VIEW);
    }

    // Tells FaceLock to stop and then unbinds from the FaceLock service
    public boolean stop() {
        boolean wasRunning = false;
        if (installedAndSelected()) {
            stopUi();

            if (mBoundToService) {
                wasRunning = true;
                if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
                if (mService != null) {
                if (mService != null) {
                    try {
                    try {
                        mService.unregisterCallback(mFaceLockCallback);
                        mService.unregisterCallback(mFaceLockCallback);
                    } catch (RemoteException e) {
                    } catch (RemoteException e) {
                        // Not much we can do
                        // Not much we can do
                    }
                    }
            stop();
            mService = null;
                }
                }
                mContext.unbindService(mConnection);
                if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
                mBoundToService = false;
            } else {
                // This is usually not an error when this happens.  Sometimes we will tell it to
                // unbind multiple times because it's called from both onWindowFocusChanged and
                // onDetachedFromWindow.
                if (DEBUG) Log.d(TAG, "Attempt to unbind from FaceLock when not bound");
            }
        }

        return wasRunning;
    }
    }


    /** When screen is turned on and focused, need to bind to FaceLock service if we are using
    /**
     * When screen is turned on and focused, need to bind to FaceLock service if we are using
     * FaceLock, but only if we're not dealing with a call
     * FaceLock, but only if we're not dealing with a call
     */
     */
    public void activateIfAble(boolean hasOverlay) {
    public boolean start(boolean suppressBiometricUnlock) {
        final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
        final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
        final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts();
        final int failedBackupAttempts = mUpdateMonitor.getFailedAttempts();
        final boolean backupIsTimedOut =
        final boolean backupIsTimedOut =
@@ -103,42 +143,31 @@ public class FaceUnlock implements Handler.Callback {
        if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries);
        if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries);
        if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
        if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
                && installedAndSelected()
                && installedAndSelected()
                && !hasOverlay
                && !suppressBiometricUnlock
                && !tooManyFaceUnlockTries
                && !tooManyFaceUnlockTries
                && !backupIsTimedOut) {
                && !backupIsTimedOut) {
            bind();
            bind();


            // Show FaceLock area, but only for a little bit so lockpattern will become visible if
            // Show FaceLock area, but only for a little bit so lockpattern will become visible if
            // FaceLock fails to start or crashes
            // FaceLock fails to start or crashes
            showAreaWithTimeout(VIEW_AREA_SERVICE_TIMEOUT);
            show(VIEW_AREA_SERVICE_TIMEOUT);


            // When switching between portrait and landscape view while FaceLock is running, the
            // When switching between portrait and landscape view while FaceLock is running, the
            // screen will eventually go dark unless we poke the wakelock when FaceLock is
            // screen will eventually go dark unless we poke the wakelock when FaceLock is
            // restarted
            // restarted
            mKeyguardScreenCallback.pokeWakelock();
            mKeyguardScreenCallback.pokeWakelock();
        } else {
        } else {
            hideArea();
            hide();
        }
            return false;
    }

    public boolean isServiceRunning() {
        return mServiceRunning;
    }

    public int viewAreaEmergencyDialerTimeout() {
        return VIEW_AREA_EMERGENCY_DIALER_TIMEOUT;
        }
        }


    // Indicates whether FaceLock is in use
        return true;
    public boolean installedAndSelected() {
        return (mLockPatternUtils.usingBiometricWeak() &&
                mLockPatternUtils.isBiometricWeakInstalled());
    }
    }


    // Takes care of FaceLock area when layout is created
    // Takes care of FaceLock area when layout is created
    public void initializeAreaView(View view) {
    public void initializeAreaView(View topView) {
        if (installedAndSelected()) {
        if (installedAndSelected()) {
            mAreaView = view.findViewById(R.id.faceLockAreaView);
            mAreaView = topView.findViewById(R.id.faceLockAreaView);
            if (mAreaView == null) {
            if (mAreaView == null) {
                Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
                Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
            }
            }
@@ -147,13 +176,20 @@ public class FaceUnlock implements Handler.Callback {
        }
        }
    }
    }


    // Stops FaceLock if it is running and reports back whether it was running or not
    public void cleanUp() {
    public boolean stopIfRunning() {
        if (mService != null) {
        if (installedAndSelected() && mBoundToService) {
            try {
            stopAndUnbind();
                mService.unregisterCallback(mFaceLockCallback);
            return true;
            } catch (RemoteException e) {
                // Not much we can do
            }
            }
        return false;
            stopUi();
            mService = null;
        }
    }

    public int getQuality() {
        return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    }
    }


    // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
    // Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
@@ -186,28 +222,15 @@ public class FaceUnlock implements Handler.Callback {
    }
    }


    // Shows the FaceLock area immediately
    // Shows the FaceLock area immediately
    public void showArea() {
    private void showArea() {
        // Remove messages to prevent a delayed hide message from undo-ing the show
        // Remove messages to prevent a delayed hide message from undo-ing the show
        removeAreaDisplayMessages();
        removeAreaDisplayMessages();
        mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
        mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
    }
    }


    // Hides the FaceLock area immediately
    public void hideArea() {
        // Remove messages to prevent a delayed show message from undo-ing the hide
        removeAreaDisplayMessages();
        mHandler.sendEmptyMessage(MSG_HIDE_AREA_VIEW);
    }

    // Shows the FaceLock area for a period of time
    public void showAreaWithTimeout(long timeoutMillis) {
        showArea();
        mHandler.sendEmptyMessageDelayed(MSG_HIDE_AREA_VIEW, timeoutMillis);
    }

    // Binds to FaceLock service.  This call does not tell it to start, but it causes the service
    // Binds to FaceLock service.  This call does not tell it to start, but it causes the service
    // to call the onServiceConnected callback, which then starts FaceLock.
    // to call the onServiceConnected callback, which then starts FaceLock.
    public void bind() {
    private void bind() {
        if (installedAndSelected()) {
        if (installedAndSelected()) {
            if (!mBoundToService) {
            if (!mBoundToService) {
                if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
                if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
@@ -223,32 +246,6 @@ public class FaceUnlock implements Handler.Callback {
        }
        }
    }
    }


    // Tells FaceLock to stop and then unbinds from the FaceLock service
    public void stopAndUnbind() {
        if (installedAndSelected()) {
            stop();

            if (mBoundToService) {
                if (DEBUG) Log.d(TAG, "before unbind from FaceLock service");
                if (mService != null) {
                    try {
                        mService.unregisterCallback(mFaceLockCallback);
                    } catch (RemoteException e) {
                        // Not much we can do
                    }
                }
                mContext.unbindService(mConnection);
                if (DEBUG) Log.d(TAG, "after unbind from FaceLock service");
                mBoundToService = false;
            } else {
                // This is usually not an error when this happens.  Sometimes we will tell it to
                // unbind multiple times because it's called from both onWindowFocusChanged and
                // onDetachedFromWindow.
                if (DEBUG) Log.d(TAG, "Attempt to unbind from FaceLock when not bound");
            }
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
    private ServiceConnection mConnection = new ServiceConnection() {
        // Completes connection, registers callback and starts FaceLock when service is bound
        // Completes connection, registers callback and starts FaceLock when service is bound
        @Override
        @Override
@@ -268,7 +265,7 @@ public class FaceUnlock implements Handler.Callback {
                int[] position;
                int[] position;
                position = new int[2];
                position = new int[2];
                mAreaView.getLocationInWindow(position);
                mAreaView.getLocationInWindow(position);
                start(mAreaView.getWindowToken(), position[0], position[1],
                startUi(mAreaView.getWindowToken(), position[0], position[1],
                        mAreaView.getWidth(), mAreaView.getHeight());
                        mAreaView.getWidth(), mAreaView.getHeight());
            }
            }
        }
        }
@@ -286,7 +283,7 @@ public class FaceUnlock implements Handler.Callback {
    };
    };


    // Tells the FaceLock service to start displaying its UI and perform recognition
    // Tells the FaceLock service to start displaying its UI and perform recognition
    public void start(IBinder windowToken, int x, int y, int w, int h) {
    private void startUi(IBinder windowToken, int x, int y, int w, int h) {
        if (installedAndSelected()) {
        if (installedAndSelected()) {
            synchronized (mServiceRunningLock) {
            synchronized (mServiceRunningLock) {
                if (!mServiceRunning) {
                if (!mServiceRunning) {
@@ -300,14 +297,14 @@ public class FaceUnlock implements Handler.Callback {
                    }
                    }
                    mServiceRunning = true;
                    mServiceRunning = true;
                } else {
                } else {
                    if (DEBUG) Log.w(TAG, "start() attempted while running");
                    if (DEBUG) Log.w(TAG, "startUi() attempted while running");
                }
                }
            }
            }
        }
        }
    }
    }


    // Tells the FaceLock service to stop displaying its UI and stop recognition
    // Tells the FaceLock service to stop displaying its UI and stop recognition
    public void stop() {
    private void stopUi() {
        if (installedAndSelected()) {
        if (installedAndSelected()) {
            // Note that attempting to stop FaceLock when it's not running is not an issue.
            // Note that attempting to stop FaceLock when it's not running is not an issue.
            // FaceLock can return, which stops it and then we try to stop it when the
            // FaceLock can return, which stops it and then we try to stop it when the
@@ -333,7 +330,7 @@ public class FaceUnlock implements Handler.Callback {
        public void unlock() {
        public void unlock() {
            if (DEBUG) Log.d(TAG, "FaceLock unlock()");
            if (DEBUG) Log.d(TAG, "FaceLock unlock()");
            showArea(); // Keep fallback covered
            showArea(); // Keep fallback covered
            stopAndUnbind();
            stop();


            mKeyguardScreenCallback.keyguardDone(true);
            mKeyguardScreenCallback.keyguardDone(true);
            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
            mKeyguardScreenCallback.reportSuccessfulUnlockAttempt();
@@ -344,8 +341,8 @@ public class FaceUnlock implements Handler.Callback {
        @Override
        @Override
        public void cancel() {
        public void cancel() {
            if (DEBUG) Log.d(TAG, "FaceLock cancel()");
            if (DEBUG) Log.d(TAG, "FaceLock cancel()");
            hideArea(); // Expose fallback
            hide(); // Expose fallback
            stopAndUnbind();
            stop();
            mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
            mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
        }
        }


@@ -355,8 +352,8 @@ public class FaceUnlock implements Handler.Callback {
        public void reportFailedAttempt() {
        public void reportFailedAttempt() {
            if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()");
            if (DEBUG) Log.d(TAG, "FaceLock reportFailedAttempt()");
            mUpdateMonitor.reportFailedFaceUnlockAttempt();
            mUpdateMonitor.reportFailedFaceUnlockAttempt();
            hideArea(); // Expose fallback
            hide(); // Expose fallback
            stopAndUnbind();
            stop();
            mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
            mKeyguardScreenCallback.pokeWakelock(BACKUP_LOCK_TIMEOUT);
        }
        }


@@ -364,7 +361,7 @@ public class FaceUnlock implements Handler.Callback {
        @Override
        @Override
        public void exposeFallback() {
        public void exposeFallback() {
            if (DEBUG) Log.d(TAG, "FaceLock exposeFallback()");
            if (DEBUG) Log.d(TAG, "FaceLock exposeFallback()");
            hideArea(); // Expose fallback
            hide(); // Expose fallback
        }
        }


        // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive
        // Allows the Face Unlock service to poke the wake lock to keep the lockscreen alive
+65 −58
Original line number Original line Diff line number Diff line
@@ -101,15 +101,17 @@ public class LockPatternKeyguardView extends KeyguardViewBase {


    private boolean mShowLockBeforeUnlock = false;
    private boolean mShowLockBeforeUnlock = false;


    // The following were added to support FaceLock
    // Interface to a biometric sensor that can optionally be used to unlock the device
    private FaceUnlock mFaceUnlock;
    private BiometricSensorUnlock mBiometricUnlock;
    private final Object mFaceLockStartupLock = new Object();
    private final Object mBiometricUnlockStartupLock = new Object();
    // Long enough to stay visible while dialer comes up
    // Short enough to not be visible if the user goes back immediately
    private final int BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT = 1000;


    private boolean mRequiresSim;
    private boolean mRequiresSim;
    //True if we have some sort of overlay on top of the Lockscreen
    // True if the biometric unlock should not be displayed.  For example, if there is an overlay on
    //Also true if we've activated a phone call, either emergency dialing or incoming
    // lockscreen or the user is plugging in / unplugging the device.
    //This resets when the phone is turned off with no current call
    private boolean mSupressBiometricUnlock;
    private boolean mHasOverlay;
    //True if a dialog is currently displaying on top of this window
    //True if a dialog is currently displaying on top of this window
    //Unlike other overlays, this does not close with a power button cycle
    //Unlike other overlays, this does not close with a power button cycle
    private boolean mHasDialog = false;
    private boolean mHasDialog = false;
@@ -308,15 +310,15 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        }
        }


        public void takeEmergencyCallAction() {
        public void takeEmergencyCallAction() {
            mHasOverlay = true;
            mSupressBiometricUnlock = true;


            // Continue showing FaceLock area until dialer comes up or call is resumed
            if (mBiometricUnlock.installedAndSelected() && mBiometricUnlock.isRunning()) {
            if (mFaceUnlock.installedAndSelected() && mFaceUnlock.isServiceRunning()) {
                // Continue covering backup lock until dialer comes up or call is resumed
                mFaceUnlock.showAreaWithTimeout(mFaceUnlock.viewAreaEmergencyDialerTimeout());
                mBiometricUnlock.show(BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT);
            }
            }


            // FaceLock must be stopped if it is running when emergency call is pressed
            // The biometric unlock must be stopped if it is running when emergency call is pressed
            mFaceUnlock.stopAndUnbind();
            mBiometricUnlock.stop();


            pokeWakelock(EMERGENCY_CALL_TIMEOUT);
            pokeWakelock(EMERGENCY_CALL_TIMEOUT);
            if (TelephonyManager.getDefault().getCallState()
            if (TelephonyManager.getDefault().getCallState()
@@ -421,7 +423,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
            LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
            LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
        super(context, callback);
        super(context, callback);


        mFaceUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
        mBiometricUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
                mKeyguardScreenCallback);
                mKeyguardScreenCallback);
        mConfiguration = context.getResources().getConfiguration();
        mConfiguration = context.getResources().getConfiguration();
        mEnableFallback = false;
        mEnableFallback = false;
@@ -429,7 +431,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        mUpdateMonitor = updateMonitor;
        mUpdateMonitor = updateMonitor;
        mLockPatternUtils = lockPatternUtils;
        mLockPatternUtils = lockPatternUtils;
        mWindowController = controller;
        mWindowController = controller;
        mHasOverlay = false;
        mSupressBiometricUnlock = false;
        mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
        mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
        mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
        mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();


@@ -528,8 +530,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        if (DEBUG) Log.d(TAG, "screen off");
        if (DEBUG) Log.d(TAG, "screen off");
        mScreenOn = false;
        mScreenOn = false;
        mForgotPattern = false;
        mForgotPattern = false;
        mHasOverlay = mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE ||
        mSupressBiometricUnlock =
                mHasDialog;
                mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE || mHasDialog;


        // Emulate activity life-cycle for both lock and unlock screen.
        // Emulate activity life-cycle for both lock and unlock screen.
        if (mLockScreen != null) {
        if (mLockScreen != null) {
@@ -541,25 +543,25 @@ public class LockPatternKeyguardView extends KeyguardViewBase {


        saveWidgetState();
        saveWidgetState();


        // When screen is turned off, need to unbind from FaceLock service if using FaceLock
        // The biometric unlock must stop when screen turns off.
        mFaceUnlock.stopAndUnbind();
        mBiometricUnlock.stop();
    }
    }


    @Override
    @Override
    public void onScreenTurnedOn() {
    public void onScreenTurnedOn() {
        if (DEBUG) Log.d(TAG, "screen on");
        if (DEBUG) Log.d(TAG, "screen on");
        boolean runFaceLock = false;
        boolean startBiometricUnlock = false;
        //Make sure to start facelock iff the screen is both on and focused
        // Start the biometric unlock if and only if the screen is both on and focused
        synchronized(mFaceLockStartupLock) {
        synchronized(mBiometricUnlockStartupLock) {
            mScreenOn = true;
            mScreenOn = true;
            runFaceLock = mWindowFocused;
            startBiometricUnlock = mWindowFocused;
        }
        }


        show();
        show();


        restoreWidgetState();
        restoreWidgetState();


        if (runFaceLock) mFaceUnlock.activateIfAble(mHasOverlay);
        if (startBiometricUnlock) mBiometricUnlock.start(mSupressBiometricUnlock);
    }
    }


    private void saveWidgetState() {
    private void saveWidgetState() {
@@ -578,25 +580,26 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        }
        }
    }
    }


    /** Unbind from facelock if something covers this window (such as an alarm)
    /**
     * bind to facelock if the lockscreen window just came into focus, and the screen is on
     * Stop the biometric unlock if something covers this window (such as an alarm)
     * Start the biometric unlock if the lockscreen window just came into focus and the screen is on
     */
     */
    @Override
    @Override
    public void onWindowFocusChanged (boolean hasWindowFocus) {
    public void onWindowFocusChanged (boolean hasWindowFocus) {
        if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused");
        if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused");
        boolean runFaceLock = false;
        boolean startBiometricUnlock = false;
        //Make sure to start facelock iff the screen is both on and focused
        // Start the biometric unlock if and only if the screen is both on and focused
        synchronized(mFaceLockStartupLock) {
        synchronized(mBiometricUnlockStartupLock) {
            if(mScreenOn && !mWindowFocused) runFaceLock = hasWindowFocus;
            if (mScreenOn && !mWindowFocused) startBiometricUnlock = hasWindowFocus;
            mWindowFocused = hasWindowFocus;
            mWindowFocused = hasWindowFocus;
        }
        }
        if (!hasWindowFocus) {
        if (!hasWindowFocus) {
            mHasOverlay = true;
            mSupressBiometricUnlock = true;
            mFaceUnlock.stopAndUnbind();
            mBiometricUnlock.stop();
            mFaceUnlock.hideArea();
            mBiometricUnlock.hide();
        } else {
        } else {
            mHasDialog = false;
            mHasDialog = false;
            if (runFaceLock) mFaceUnlock.activateIfAble(mHasOverlay);
            if (startBiometricUnlock) mBiometricUnlock.start(mSupressBiometricUnlock);
        }
        }
    }
    }


@@ -610,14 +613,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
            ((KeyguardScreen) mUnlockScreen).onResume();
            ((KeyguardScreen) mUnlockScreen).onResume();
        }
        }


        if (mFaceUnlock.installedAndSelected() && !mHasOverlay) {
        if (mBiometricUnlock.installedAndSelected() && !mSupressBiometricUnlock) {
            // Note that show() gets called before the screen turns off to set it up for next time
            // Note that show() gets called before the screen turns off to set it up for next time
            // it is turned on.  We don't want to set a timeout on the FaceLock area here because it
            // it is turned on.  We don't want to set a timeout on the biometric unlock here because
            // may be gone by the time the screen is turned on again.  We set the timeout when the
            // it may be gone by the time the screen is turned on again.  We set the timeout when
            // screen turns on instead.
            // the screen turns on instead.
            mFaceUnlock.showArea();
            mBiometricUnlock.show(0);
        } else {
        } else {
            mFaceUnlock.hideArea();
            mBiometricUnlock.hide();
        }
        }
    }
    }


@@ -651,9 +654,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase {


        removeCallbacks(mRecreateRunnable);
        removeCallbacks(mRecreateRunnable);


        // When view is hidden, need to unbind from FaceLock service if we are using FaceLock
        // When view is hidden, we need to stop the biometric unlock
        // e.g., when device becomes unlocked
        // e.g., when device becomes unlocked
        mFaceUnlock.stopAndUnbind();
        mBiometricUnlock.stop();


        super.onDetachedFromWindow();
        super.onDetachedFromWindow();
    }
    }
@@ -670,16 +673,19 @@ public class LockPatternKeyguardView extends KeyguardViewBase {


    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {
    InfoCallbackImpl mInfoCallback = new InfoCallbackImpl() {


        /** When somebody plugs in or unplugs the device, we don't want to display faceunlock */
        /**
         * When somebody plugs in or unplugs the device, we don't want to display the biometric
         * unlock.
         */
        @Override
        @Override
        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
        public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
                int batteryLevel) {
                int batteryLevel) {
            mHasOverlay |= mPluggedIn != pluggedIn;
            mSupressBiometricUnlock |= mPluggedIn != pluggedIn;
            mPluggedIn = pluggedIn;
            mPluggedIn = pluggedIn;
            // If it's already running, don't close it down: the unplug didn't start it
            // If it's already running, don't close it down: the unplug didn't start it
            if (!mFaceUnlock.isServiceRunning()) {
            if (!mBiometricUnlock.isRunning()) {
                mFaceUnlock.stopAndUnbind();
                mBiometricUnlock.stop();
                mFaceUnlock.hideArea();
                mBiometricUnlock.hide();
            }
            }
        }
        }


@@ -690,20 +696,20 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
                    | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0));
                    | (mUpdateMonitor.isClockVisible() ? View.STATUS_BAR_DISABLE_CLOCK : 0));
        }
        }


        //We need to stop faceunlock when a phonecall comes in
        // We need to stop the biometric unlock when a phone call comes in
        @Override
        @Override
        public void onPhoneStateChanged(int phoneState) {
        public void onPhoneStateChanged(int phoneState) {
            if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
            if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
            if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
            if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
                mHasOverlay = true;
                mSupressBiometricUnlock = true;
                mFaceUnlock.stopAndUnbind();
                mBiometricUnlock.stop();
                mFaceUnlock.hideArea();
                mBiometricUnlock.hide();
            }
            }
        }
        }


        @Override
        @Override
        public void onUserChanged(int userId) {
        public void onUserChanged(int userId) {
            mFaceUnlock.stopAndUnbind();
            mBiometricUnlock.stop();
            mLockPatternUtils.setCurrentUser(userId);
            mLockPatternUtils.setCurrentUser(userId);
            updateScreen(getInitialMode(), true);
            updateScreen(getInitialMode(), true);
        }
        }
@@ -766,7 +772,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
            mUnlockScreen = null;
            mUnlockScreen = null;
        }
        }
        mUpdateMonitor.removeCallback(this);
        mUpdateMonitor.removeCallback(this);
        mFaceUnlock.cleanUp();
        mBiometricUnlock.cleanUp();
    }
    }


    private boolean isSecure() {
    private boolean isSecure() {
@@ -816,10 +822,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
        final UnlockMode unlockMode = getUnlockMode();
        final UnlockMode unlockMode = getUnlockMode();
        if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
        if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
            if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
            if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
                boolean restartFaceLock = mFaceUnlock.stopIfRunning();
                boolean restartBiometricUnlock = mBiometricUnlock.stop();
                recreateUnlockScreen(unlockMode);
                recreateUnlockScreen(unlockMode);
                if (restartFaceLock) {
                if (restartBiometricUnlock) {
                    mFaceUnlock.activateIfAble(mHasOverlay);
                    mBiometricUnlock.start(mSupressBiometricUnlock);
                }
                }
            }
            }
        }
        }
@@ -933,7 +939,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
            throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
            throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
        }
        }
        initializeTransportControlView(unlockView);
        initializeTransportControlView(unlockView);
        mFaceUnlock.initializeAreaView(unlockView); // Only shows view if FaceLock is enabled
        // Only shows view if the biometric unlock is enabled
        mBiometricUnlock.initializeAreaView(unlockView);


        mUnlockScreenMode = unlockMode;
        mUnlockScreenMode = unlockMode;
        return unlockView;
        return unlockView;