FileDocCategorySizeDatePackage
FaceUnlock.javaAPI DocAndroid 5.1 API17327Thu Mar 12 22:22:42 GMT 2015com.android.keyguard

FaceUnlock

public class FaceUnlock extends Object implements BiometricSensorUnlock, Handler.Callback

Fields Summary
private static final boolean
DEBUG
private static final String
TAG
private static final String
FACE_LOCK_PACKAGE
private final android.content.Context
mContext
private final com.android.internal.widget.LockPatternUtils
mLockPatternUtils
private boolean
mServiceRunning
private final Object
mServiceRunningLock
private com.android.internal.policy.IFaceLockInterface
mService
private boolean
mBoundToService
private android.view.View
mFaceUnlockView
private android.os.Handler
mHandler
private final int
MSG_SERVICE_CONNECTED
private final int
MSG_SERVICE_DISCONNECTED
private final int
MSG_UNLOCK
private final int
MSG_CANCEL
private final int
MSG_REPORT_FAILED_ATTEMPT
private final int
MSG_POKE_WAKELOCK
private volatile boolean
mIsRunning
KeyguardSecurityCallback
mKeyguardScreenCallback
private android.content.ServiceConnection
mConnection
Implements service connection methods.
private final com.android.internal.policy.IFaceLockCallback
mFaceUnlockCallback
Implements the AIDL biometric unlock service callback interface.
Constructors Summary
public FaceUnlock(android.content.Context context)
Stores some of the structures that Face Unlock will need to access and creates the handler will be used to execute messages on the UI thread.


                                   
       
        mContext = context;
        mLockPatternUtils = new LockPatternUtils(context);
        mHandler = new Handler(this);
    
Methods Summary
public voidcleanUp()
Frees up resources used by Face Unlock and stops it if it is still running.

        if (DEBUG) Log.d(TAG, "cleanUp()");
        if (mService != null) {
            try {
                mService.unregisterCallback(mFaceUnlockCallback);
            } catch (RemoteException e) {
                // Not much we can do
            }
            stopUi();
            mService = null;
        }
    
public intgetQuality()
Returns the Device Policy Manager quality for Face Unlock, which is BIOMETRIC_WEAK.

        return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
    
voidhandleCancel()
Stops the Face Unlock service and goes to the backup lock.

        if (DEBUG) Log.d(TAG, "handleCancel()");
        // We are going to the backup method, so we don't want to see Face Unlock again until the
        // next time the user visits keyguard.
        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);

        mKeyguardScreenCallback.showBackupSecurity();
        stop();
        mKeyguardScreenCallback.userActivity();
    
public booleanhandleMessage(android.os.Message msg)
Handles messages such that everything happens on the UI thread in a deterministic order. Calls from the Face Unlock service come from binder threads. Calls from lockscreen typically come from the UI thread. This makes sure there are no race conditions between those calls.

        switch (msg.what) {
            case MSG_SERVICE_CONNECTED:
                handleServiceConnected();
                break;
            case MSG_SERVICE_DISCONNECTED:
                handleServiceDisconnected();
                break;
            case MSG_UNLOCK:
                handleUnlock(msg.arg1);
                break;
            case MSG_CANCEL:
                handleCancel();
                break;
            case MSG_REPORT_FAILED_ATTEMPT:
                handleReportFailedAttempt();
                break;
            case MSG_POKE_WAKELOCK:
                handlePokeWakelock(msg.arg1);
                break;
            default:
                Log.e(TAG, "Unhandled message");
                return false;
        }
        return true;
    
voidhandlePokeWakelock(int millis)
If the screen is on, pokes the wakelock to keep the screen alive and active for a specific amount of time.

      PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
      if (powerManager.isScreenOn()) {
        mKeyguardScreenCallback.userActivity();
      }
    
voidhandleReportFailedAttempt()
Increments the number of failed Face Unlock attempts.

        if (DEBUG) Log.d(TAG, "handleReportFailedAttempt()");
        // We are going to the backup method, so we don't want to see Face Unlock again until the
        // next time the user visits keyguard.
        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false);

        mKeyguardScreenCallback.reportUnlockAttempt(false);
    
voidhandleServiceConnected()
Tells the service to start its UI via an AIDL interface. Called when the onServiceConnected() callback is received.

        Log.d(TAG, "handleServiceConnected()");

        // It is possible that an unbind has occurred in the time between the bind and when this
        // function is reached.  If an unbind has already occurred, proceeding on to call startUi()
        // can result in a fatal error.  Note that the onServiceConnected() callback is
        // asynchronous, so this possibility would still exist if we executed this directly in
        // onServiceConnected() rather than using a handler.
        if (!mBoundToService) {
            Log.d(TAG, "Dropping startUi() in handleServiceConnected() because no longer bound");
            return;
        }

        try {
            mService.registerCallback(mFaceUnlockCallback);
        } catch (RemoteException e) {
            Log.e(TAG, "Caught exception connecting to Face Unlock: " + e.toString());
            mService = null;
            mBoundToService = false;
            mIsRunning = false;
            return;
        }

        if (mFaceUnlockView != null) {
            IBinder windowToken = mFaceUnlockView.getWindowToken();
            if (windowToken != null) {
                // When switching between portrait and landscape view while Face Unlock is running,
                // the screen will eventually go dark unless we poke the wakelock when Face Unlock
                // is restarted.
                mKeyguardScreenCallback.userActivity();

                int[] position;
                position = new int[2];
                mFaceUnlockView.getLocationInWindow(position);
                startUi(windowToken, position[0], position[1], mFaceUnlockView.getWidth(),
                        mFaceUnlockView.getHeight());
            } else {
                Log.e(TAG, "windowToken is null in handleServiceConnected()");
            }
        }
    
voidhandleServiceDisconnected()
Called when the onServiceDisconnected() callback is received. This should not happen during normal operation. It indicates an error has occurred.

        Log.e(TAG, "handleServiceDisconnected()");
        // TODO: this lock may no longer be needed now that everything is being called from a
        // handler
        synchronized (mServiceRunningLock) {
            mService = null;
            mServiceRunning = false;
        }
        mBoundToService = false;
        mIsRunning = false;
    
voidhandleUnlock(int authenticatedUserId)
Stops the Face Unlock service and tells the device to grant access to the user.

        if (DEBUG) Log.d(TAG, "handleUnlock()");
        stop();
        int currentUserId = mLockPatternUtils.getCurrentUser();
        if (authenticatedUserId == currentUserId) {
            if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId);
            mKeyguardScreenCallback.reportUnlockAttempt(true);
            mKeyguardScreenCallback.dismiss(true);
        } else {
            Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId +
                    ") because the current user is " + currentUserId);
        }
    
public voidinitializeView(android.view.View biometricUnlockView)
Stores and displays the view that Face Unlock is allowed to draw within. TODO: since the layout object will eventually be shared by multiple biometric unlock methods, we will have to add our other views (background, cancel button) here.

        Log.d(TAG, "initializeView()");
        mFaceUnlockView = biometricUnlockView;
    
public booleanisRunning()
Indicates whether Face Unlock is currently running.

        return mIsRunning;
    
public voidsetKeyguardCallback(KeyguardSecurityCallback keyguardScreenCallback)

        mKeyguardScreenCallback = keyguardScreenCallback;
    
public booleanstart()
Binds to the Face Unlock service. Face Unlock will be started when the bind completes. The Face Unlock view is displayed to hide the backup lock while the service is starting up. Called on the UI thread.

        if (DEBUG) Log.d(TAG, "start()");
        if (mHandler.getLooper() != Looper.myLooper()) {
            Log.e(TAG, "start() called off of the UI thread");
        }

        if (mIsRunning) {
            Log.w(TAG, "start() called when already running");
        }

        if (!mBoundToService) {
            Log.d(TAG, "Binding to Face Unlock service for user="
                    + mLockPatternUtils.getCurrentUser());
            mContext.bindServiceAsUser(
                    new Intent(IFaceLockInterface.class.getName()).setPackage(FACE_LOCK_PACKAGE),
                    mConnection,
                    Context.BIND_AUTO_CREATE,
                    new UserHandle(mLockPatternUtils.getCurrentUser()));
            mBoundToService = true;
        } else {
            Log.w(TAG, "Attempt to bind to Face Unlock when already bound");
        }

        mIsRunning = true;
        return true;
    
private voidstartUi(android.os.IBinder windowToken, int x, int y, int w, int h)
Tells the Face Unlock service to start displaying its UI and start processing.


                      
                
        if (DEBUG) Log.d(TAG, "startUi()");
        synchronized (mServiceRunningLock) {
            if (!mServiceRunning) {
                Log.d(TAG, "Starting Face Unlock");
                try {
                    mService.startUi(windowToken, x, y, w, h,
                            mLockPatternUtils.isBiometricWeakLivelinessEnabled());
                } catch (RemoteException e) {
                    Log.e(TAG, "Caught exception starting Face Unlock: " + e.toString());
                    return;
                }
                mServiceRunning = true;
            } else {
                Log.w(TAG, "startUi() attempted while running");
            }
        }
    
public booleanstop()
Stops Face Unlock and unbinds from the service. Called on the UI thread.

        if (DEBUG) Log.d(TAG, "stop()");
        if (mHandler.getLooper() != Looper.myLooper()) {
            Log.e(TAG, "stop() called from non-UI thread");
        }

        // Clearing any old service connected messages.
        mHandler.removeMessages(MSG_SERVICE_CONNECTED);

        boolean mWasRunning = mIsRunning;

        stopUi();

        if (mBoundToService) {
            if (mService != null) {
                try {
                    mService.unregisterCallback(mFaceUnlockCallback);
                } catch (RemoteException e) {
                    // Not much we can do
                }
            }
            Log.d(TAG, "Unbinding from Face Unlock service");
            mContext.unbindService(mConnection);
            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 Face Unlock when not bound");
        }
        mIsRunning = false;
        return mWasRunning;
    
public voidstopAndShowBackup()
Dismisses face unlock and goes to the backup lock

        if (DEBUG) Log.d(TAG, "stopAndShowBackup()");
        mHandler.sendEmptyMessage(MSG_CANCEL);
    
private voidstopUi()
Tells the Face Unlock service to stop displaying its UI and stop processing.

        if (DEBUG) Log.d(TAG, "stopUi()");
        // Note that attempting to stop Face Unlock when it's not running is not an issue.
        // Face Unlock can return, which stops it and then we try to stop it when the
        // screen is turned off.  That's why we check.
        synchronized (mServiceRunningLock) {
            if (mServiceRunning) {
                Log.d(TAG, "Stopping Face Unlock");
                try {
                    mService.stopUi();
                } catch (RemoteException e) {
                    Log.e(TAG, "Caught exception stopping Face Unlock: " + e.toString());
                }
                mServiceRunning = false;
            } else {
                // This is usually not an error when this happens.  Sometimes we will tell it to
                // stop multiple times because it's called from both onWindowFocusChanged and
                // onDetachedFromWindow.
                if (DEBUG) Log.d(TAG, "stopUi() attempted while not running");
            }
        }