Moved biometric sensor selected check into LPKV
This change moves all of the mBiometricUnlock.installedAndSelected() checks from inside the biometric sensor implementation to LockPatternKeyguardView. There are several reasons for this change: 1) Instead of constructing a BiometricUnlock object and asking it if it's enabled, LPKV can check this for itself and not even bother constructing it if it's not enabled. 2) Since mBiometricUnlock will not be constructed if biometric unlock isn't enabled, LPKV can simply do null checks to see if it should call biometric unlock functions. So it serves the dual-purpose of ensuring there will be no null-pointer exceptions with regards to using the biometric unlock. 3) This greatly reduces the chance of bugs being introduced into non-biometric unlock methods because no biometric unlock calls will be attempted if biometric unlock is not enabled. Previously, the calls would be made and then the biometric unlock would check if it was enabled and return, which was not only bug-prone, but also inefficient. 4) This simplifies the biometric unlock interface by removing an unnecessary function call. 5) The biometric unlock implementations do not have to check if they are installed every time they do something, which greatly cleans up biometric unlock implementations. It makes much more sense for the biometric unlock functions to be able to assume that they aren't being called unless they should be. 6) Eventually when there is more than one possible biometric unlock method, it will make much more sense for LPKV to be in charge of what is constructed and what isn't. Change-Id: I5437ac05d8ceb2b182fe372cd6c75ad944ade28f
This commit is contained in:
@@ -19,9 +19,6 @@ 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();
|
||||
|
||||
@@ -77,12 +77,6 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
mHandler = new Handler(this);
|
||||
}
|
||||
|
||||
// Indicates whether FaceLock is in use
|
||||
public boolean installedAndSelected() {
|
||||
return (mLockPatternUtils.usingBiometricWeak() &&
|
||||
mLockPatternUtils.isBiometricWeakInstalled());
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return mServiceRunning;
|
||||
}
|
||||
@@ -106,28 +100,26 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
// Tells FaceLock to stop and then unbinds from the FaceLock service
|
||||
public boolean stop() {
|
||||
boolean wasRunning = false;
|
||||
if (installedAndSelected()) {
|
||||
stopUi();
|
||||
stopUi();
|
||||
|
||||
if (mBoundToService) {
|
||||
wasRunning = true;
|
||||
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
|
||||
}
|
||||
if (mBoundToService) {
|
||||
wasRunning = true;
|
||||
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");
|
||||
}
|
||||
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;
|
||||
@@ -145,7 +137,6 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
(failedBackupAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT);
|
||||
if (tooManyFaceUnlockTries) Log.i(TAG, "tooManyFaceUnlockTries: " + tooManyFaceUnlockTries);
|
||||
if (mUpdateMonitor.getPhoneState() == TelephonyManager.CALL_STATE_IDLE
|
||||
&& installedAndSelected()
|
||||
&& !suppressBiometricUnlock
|
||||
&& !tooManyFaceUnlockTries
|
||||
&& !backupIsTimedOut) {
|
||||
@@ -170,15 +161,11 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
|
||||
// Takes care of FaceLock area when layout is created
|
||||
public void initializeAreaView(View topView) {
|
||||
if (installedAndSelected()) {
|
||||
mAreaView = topView.findViewById(R.id.faceLockAreaView);
|
||||
if (mAreaView == null) {
|
||||
Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
|
||||
} else {
|
||||
show(0);
|
||||
}
|
||||
mAreaView = topView.findViewById(R.id.faceLockAreaView);
|
||||
if (mAreaView == null) {
|
||||
Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
|
||||
} else {
|
||||
mAreaView = null; // Set to null if not using FaceLock
|
||||
show(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,18 +223,16 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
// 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.
|
||||
private void bind() {
|
||||
if (installedAndSelected()) {
|
||||
if (!mBoundToService) {
|
||||
if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
|
||||
mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
|
||||
mConnection,
|
||||
Context.BIND_AUTO_CREATE,
|
||||
mLockPatternUtils.getCurrentUser());
|
||||
if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
|
||||
mBoundToService = true;
|
||||
} else {
|
||||
Log.w(TAG, "Attempt to bind to FaceLock when already bound");
|
||||
}
|
||||
if (!mBoundToService) {
|
||||
if (DEBUG) Log.d(TAG, "before bind to FaceLock service");
|
||||
mContext.bindService(new Intent(IFaceLockInterface.class.getName()),
|
||||
mConnection,
|
||||
Context.BIND_AUTO_CREATE,
|
||||
mLockPatternUtils.getCurrentUser());
|
||||
if (DEBUG) Log.d(TAG, "after bind to FaceLock service");
|
||||
mBoundToService = true;
|
||||
} else {
|
||||
Log.w(TAG, "Attempt to bind to FaceLock when already bound");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,41 +274,37 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback {
|
||||
|
||||
// Tells the FaceLock service to start displaying its UI and perform recognition
|
||||
private void startUi(IBinder windowToken, int x, int y, int w, int h) {
|
||||
if (installedAndSelected()) {
|
||||
synchronized (mServiceRunningLock) {
|
||||
if (!mServiceRunning) {
|
||||
if (DEBUG) Log.d(TAG, "Starting FaceLock");
|
||||
try {
|
||||
mService.startUi(windowToken, x, y, w, h,
|
||||
mLockPatternUtils.isBiometricWeakLivelinessEnabled());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
|
||||
return;
|
||||
}
|
||||
mServiceRunning = true;
|
||||
} else {
|
||||
if (DEBUG) Log.w(TAG, "startUi() attempted while running");
|
||||
synchronized (mServiceRunningLock) {
|
||||
if (!mServiceRunning) {
|
||||
if (DEBUG) Log.d(TAG, "Starting FaceLock");
|
||||
try {
|
||||
mService.startUi(windowToken, x, y, w, h,
|
||||
mLockPatternUtils.isBiometricWeakLivelinessEnabled());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Caught exception starting FaceLock: " + e.toString());
|
||||
return;
|
||||
}
|
||||
mServiceRunning = true;
|
||||
} else {
|
||||
if (DEBUG) Log.w(TAG, "startUi() attempted while running");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tells the FaceLock service to stop displaying its UI and stop recognition
|
||||
private void stopUi() {
|
||||
if (installedAndSelected()) {
|
||||
// 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
|
||||
// screen is turned off. That's why we check.
|
||||
synchronized (mServiceRunningLock) {
|
||||
if (mServiceRunning) {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "Stopping FaceLock");
|
||||
mService.stopUi();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString());
|
||||
}
|
||||
mServiceRunning = false;
|
||||
// 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
|
||||
// screen is turned off. That's why we check.
|
||||
synchronized (mServiceRunningLock) {
|
||||
if (mServiceRunning) {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "Stopping FaceLock");
|
||||
mService.stopUi();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Caught exception stopping FaceLock: " + e.toString());
|
||||
}
|
||||
mServiceRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
private boolean mRequiresSim;
|
||||
// True if the biometric unlock should not be displayed. For example, if there is an overlay on
|
||||
// lockscreen or the user is plugging in / unplugging the device.
|
||||
private boolean mSupressBiometricUnlock;
|
||||
private boolean mSuppressBiometricUnlock;
|
||||
//True if a dialog is currently displaying on top of this window
|
||||
//Unlike other overlays, this does not close with a power button cycle
|
||||
private boolean mHasDialog = false;
|
||||
@@ -310,16 +310,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
}
|
||||
|
||||
public void takeEmergencyCallAction() {
|
||||
mSupressBiometricUnlock = true;
|
||||
mSuppressBiometricUnlock = true;
|
||||
|
||||
if (mBiometricUnlock.installedAndSelected() && mBiometricUnlock.isRunning()) {
|
||||
// Continue covering backup lock until dialer comes up or call is resumed
|
||||
mBiometricUnlock.show(BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT);
|
||||
if (mBiometricUnlock != null) {
|
||||
if (mBiometricUnlock.isRunning()) {
|
||||
// Continue covering backup lock until dialer comes up or call is resumed
|
||||
mBiometricUnlock.show(BIOMETRIC_AREA_EMERGENCY_DIALER_TIMEOUT);
|
||||
}
|
||||
|
||||
// We must ensure the biometric unlock is stopped when emergency call is pressed
|
||||
mBiometricUnlock.stop();
|
||||
}
|
||||
|
||||
// The biometric unlock must be stopped if it is running when emergency call is pressed
|
||||
mBiometricUnlock.stop();
|
||||
|
||||
pokeWakelock(EMERGENCY_CALL_TIMEOUT);
|
||||
if (TelephonyManager.getDefault().getCallState()
|
||||
== TelephonyManager.CALL_STATE_OFFHOOK) {
|
||||
@@ -410,6 +412,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
}
|
||||
};
|
||||
|
||||
// Indicates whether a biometric unlock method is in use
|
||||
private boolean isBiometricUnlockInstalledAndSelected() {
|
||||
return (mLockPatternUtils.usingBiometricWeak() &&
|
||||
mLockPatternUtils.isBiometricWeakInstalled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context Used to inflate, and create views.
|
||||
* @param callback Keyguard callback object for pokewakelock(), etc.
|
||||
@@ -423,18 +431,23 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
|
||||
super(context, callback);
|
||||
|
||||
mBiometricUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
|
||||
mKeyguardScreenCallback);
|
||||
mConfiguration = context.getResources().getConfiguration();
|
||||
mEnableFallback = false;
|
||||
mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
|
||||
mUpdateMonitor = updateMonitor;
|
||||
mLockPatternUtils = lockPatternUtils;
|
||||
mWindowController = controller;
|
||||
mSupressBiometricUnlock = false;
|
||||
mSuppressBiometricUnlock = false;
|
||||
mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
|
||||
mScreenOn = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)).isScreenOn();
|
||||
|
||||
// If the biometric unlock is not being used, we don't bother constructing it. Then we can
|
||||
// simply check if it is null when deciding whether we should make calls to it.
|
||||
if (isBiometricUnlockInstalledAndSelected()) {
|
||||
mBiometricUnlock = new FaceUnlock(context, updateMonitor, lockPatternUtils,
|
||||
mKeyguardScreenCallback);
|
||||
}
|
||||
|
||||
mUpdateMonitor.registerInfoCallback(mInfoCallback);
|
||||
|
||||
/**
|
||||
@@ -530,8 +543,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
if (DEBUG) Log.d(TAG, "screen off");
|
||||
mScreenOn = false;
|
||||
mForgotPattern = false;
|
||||
mSupressBiometricUnlock =
|
||||
mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE || mHasDialog;
|
||||
if (mBiometricUnlock != null) {
|
||||
mSuppressBiometricUnlock =
|
||||
mUpdateMonitor.getPhoneState() != TelephonyManager.CALL_STATE_IDLE
|
||||
|| mHasDialog;
|
||||
}
|
||||
|
||||
// Emulate activity life-cycle for both lock and unlock screen.
|
||||
if (mLockScreen != null) {
|
||||
@@ -543,8 +559,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
|
||||
saveWidgetState();
|
||||
|
||||
// The biometric unlock must stop when screen turns off.
|
||||
mBiometricUnlock.stop();
|
||||
if (mBiometricUnlock != null) {
|
||||
// The biometric unlock must stop when screen turns off.
|
||||
mBiometricUnlock.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -561,7 +579,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
|
||||
restoreWidgetState();
|
||||
|
||||
if (startBiometricUnlock) mBiometricUnlock.start(mSupressBiometricUnlock);
|
||||
if (mBiometricUnlock != null && startBiometricUnlock) {
|
||||
mBiometricUnlock.start(mSuppressBiometricUnlock);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveWidgetState() {
|
||||
@@ -587,6 +607,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
@Override
|
||||
public void onWindowFocusChanged (boolean hasWindowFocus) {
|
||||
if (DEBUG) Log.d(TAG, hasWindowFocus ? "focused" : "unfocused");
|
||||
|
||||
boolean startBiometricUnlock = false;
|
||||
// Start the biometric unlock if and only if the screen is both on and focused
|
||||
synchronized(mBiometricUnlockStartupLock) {
|
||||
@@ -594,12 +615,16 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
mWindowFocused = hasWindowFocus;
|
||||
}
|
||||
if (!hasWindowFocus) {
|
||||
mSupressBiometricUnlock = true;
|
||||
mBiometricUnlock.stop();
|
||||
mBiometricUnlock.hide();
|
||||
if (mBiometricUnlock != null) {
|
||||
mSuppressBiometricUnlock = true;
|
||||
mBiometricUnlock.stop();
|
||||
mBiometricUnlock.hide();
|
||||
}
|
||||
} else {
|
||||
mHasDialog = false;
|
||||
if (startBiometricUnlock) mBiometricUnlock.start(mSupressBiometricUnlock);
|
||||
if (mBiometricUnlock != null && startBiometricUnlock) {
|
||||
mBiometricUnlock.start(mSuppressBiometricUnlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +638,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
((KeyguardScreen) mUnlockScreen).onResume();
|
||||
}
|
||||
|
||||
if (!mBiometricUnlock.installedAndSelected() || mSupressBiometricUnlock) {
|
||||
if (mBiometricUnlock != null && mSuppressBiometricUnlock) {
|
||||
mBiometricUnlock.hide();
|
||||
}
|
||||
}
|
||||
@@ -648,9 +673,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
|
||||
removeCallbacks(mRecreateRunnable);
|
||||
|
||||
// When view is hidden, we need to stop the biometric unlock
|
||||
// e.g., when device becomes unlocked
|
||||
mBiometricUnlock.stop();
|
||||
if (mBiometricUnlock != null) {
|
||||
// When view is hidden, we need to stop the biometric unlock
|
||||
// e.g., when device becomes unlocked
|
||||
mBiometricUnlock.stop();
|
||||
}
|
||||
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
@@ -676,10 +703,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
// suppressed.
|
||||
//
|
||||
// However, if the biometric unlock is already running, we do not want to interrupt it.
|
||||
if (mPluggedIn != pluggedIn && !mBiometricUnlock.isRunning()) {
|
||||
if (mBiometricUnlock != null && mPluggedIn != pluggedIn
|
||||
&& !mBiometricUnlock.isRunning()) {
|
||||
mBiometricUnlock.stop();
|
||||
mBiometricUnlock.hide();
|
||||
mSupressBiometricUnlock = true;
|
||||
mSuppressBiometricUnlock = true;
|
||||
}
|
||||
mPluggedIn = pluggedIn;
|
||||
}
|
||||
@@ -695,8 +723,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
@Override
|
||||
public void onPhoneStateChanged(int phoneState) {
|
||||
if (DEBUG) Log.d(TAG, "phone state: " + phoneState);
|
||||
if(phoneState == TelephonyManager.CALL_STATE_RINGING) {
|
||||
mSupressBiometricUnlock = true;
|
||||
if (mBiometricUnlock != null && phoneState == TelephonyManager.CALL_STATE_RINGING) {
|
||||
mSuppressBiometricUnlock = true;
|
||||
mBiometricUnlock.stop();
|
||||
mBiometricUnlock.hide();
|
||||
}
|
||||
@@ -704,7 +732,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
|
||||
@Override
|
||||
public void onUserChanged(int userId) {
|
||||
mBiometricUnlock.stop();
|
||||
if (mBiometricUnlock != null) {
|
||||
mBiometricUnlock.stop();
|
||||
}
|
||||
mLockPatternUtils.setCurrentUser(userId);
|
||||
updateScreen(getInitialMode(), true);
|
||||
}
|
||||
@@ -767,7 +797,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
mUnlockScreen = null;
|
||||
}
|
||||
mUpdateMonitor.removeCallback(this);
|
||||
mBiometricUnlock.cleanUp();
|
||||
if (mBiometricUnlock != null) {
|
||||
mBiometricUnlock.cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSecure() {
|
||||
@@ -817,10 +849,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
final UnlockMode unlockMode = getUnlockMode();
|
||||
if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
|
||||
if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
|
||||
boolean restartBiometricUnlock = mBiometricUnlock.stop();
|
||||
boolean restartBiometricUnlock = false;
|
||||
if (mBiometricUnlock != null) {
|
||||
restartBiometricUnlock = mBiometricUnlock.stop();
|
||||
}
|
||||
recreateUnlockScreen(unlockMode);
|
||||
if (restartBiometricUnlock) {
|
||||
mBiometricUnlock.start(mSupressBiometricUnlock);
|
||||
if (mBiometricUnlock != null && restartBiometricUnlock) {
|
||||
mBiometricUnlock.start(mSuppressBiometricUnlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -934,8 +969,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
|
||||
throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
|
||||
}
|
||||
initializeTransportControlView(unlockView);
|
||||
// Only shows view if the biometric unlock is enabled
|
||||
mBiometricUnlock.initializeAreaView(unlockView);
|
||||
|
||||
if (mBiometricUnlock != null) {
|
||||
mBiometricUnlock.initializeAreaView(unlockView);
|
||||
}
|
||||
|
||||
mUnlockScreenMode = unlockMode;
|
||||
return unlockView;
|
||||
|
||||
Reference in New Issue
Block a user