diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 5dadd062f15..e59cbc3fcbb 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -32,6 +32,8 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; +import android.hardware.face.Face; +import android.hardware.face.FaceManager; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.RemovalCallback; @@ -145,6 +147,7 @@ public class ChooseLockGeneric extends SettingsActivity { private String mUserPassword; private LockPatternUtils mLockPatternUtils; private FingerprintManager mFingerprintManager; + private FaceManager mFaceManager; private int mUserId; private boolean mHideDrawer = false; private ManagedLockPasswordProvider mManagedPasswordProvider; @@ -166,6 +169,7 @@ public class ChooseLockGeneric extends SettingsActivity { String chooseLockAction = getActivity().getIntent().getAction(); mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity()); + mFaceManager = Utils.getFaceManagerOrNull(getActivity()); mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); mLockPatternUtils = new LockPatternUtils(getActivity()); @@ -636,6 +640,30 @@ public class ChooseLockGeneric extends SettingsActivity { unlockMethodIntent); } + /** + * Keeps track of the biometric removal status. When all biometrics (including managed + * profiles) are removed, finishes the activity. Otherwise, it's possible the UI still + * shows enrolled biometrics due to the async remove. + */ + private class RemovalTracker { + boolean mFingerprintDone; + boolean mFaceDone; + + void onFingerprintDone() { + mFingerprintDone = true; + if (mFingerprintDone && mFaceDone) { + finish(); + } + } + + void onFaceDone() { + mFaceDone = true; + if (mFingerprintDone && mFaceDone) { + finish(); + } + } + } + /** * Invokes an activity to change the user's pattern, password or PIN based on given quality * and minimum quality specified by DevicePolicyManager. If quality is @@ -672,12 +700,18 @@ public class ChooseLockGeneric extends SettingsActivity { mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId); mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId); getActivity().setResult(Activity.RESULT_OK); - removeAllFingerprintForUserAndFinish(mUserId); + removeAllBiometricsForUserAndFinish(mUserId); } else { - removeAllFingerprintForUserAndFinish(mUserId); + removeAllBiometricsForUserAndFinish(mUserId); } } + private void removeAllBiometricsForUserAndFinish(final int userId) { + final RemovalTracker tracker = new RemovalTracker(); + removeAllFingerprintForUserAndFinish(userId, tracker); + removeAllFaceForUserAndFinish(userId, tracker); + } + private Intent getIntentForUnlockMethod(int quality) { Intent intent = null; if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { @@ -693,7 +727,8 @@ public class ChooseLockGeneric extends SettingsActivity { return intent; } - private void removeAllFingerprintForUserAndFinish(final int userId) { + private void removeAllFingerprintForUserAndFinish(final int userId, + RemovalTracker tracker) { if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { if (mFingerprintManager.hasEnrolledFingerprints(userId)) { mFingerprintManager.setActiveUser(userId); @@ -715,25 +750,27 @@ public class ChooseLockGeneric extends SettingsActivity { @Override public void onRemovalSucceeded(Fingerprint fp, int remaining) { if (remaining == 0) { - removeManagedProfileFingerprintsAndFinishIfNecessary(userId); + removeManagedProfileFingerprintsAndFinishIfNecessary(userId, + tracker); } } }); } else { // No fingerprints in this user, we may also want to delete managed profile // fingerprints - removeManagedProfileFingerprintsAndFinishIfNecessary(userId); + removeManagedProfileFingerprintsAndFinishIfNecessary(userId, tracker); } } else { // The removal callback will call finish, once all fingerprints are removed. // We need to wait for that to occur, otherwise, the UI will still show that // fingerprints exist even though they are (about to) be removed depending on // the race condition. - finish(); + tracker.onFingerprintDone(); } } - private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId) { + private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId, + RemovalTracker tracker) { if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { mFingerprintManager.setActiveUser(UserHandle.myUserId()); } @@ -746,14 +783,69 @@ public class ChooseLockGeneric extends SettingsActivity { final UserInfo userInfo = profiles.get(i); if (userInfo.isManagedProfile() && !mLockPatternUtils .isSeparateProfileChallengeEnabled(userInfo.id)) { - removeAllFingerprintForUserAndFinish(userInfo.id); + removeAllFingerprintForUserAndFinish(userInfo.id, tracker); hasChildProfile = true; break; } } } if (!hasChildProfile) { - finish(); + tracker.onFingerprintDone(); + } + } + + // TODO: figure out how to eliminate duplicated code. It's a bit hard due to the async-ness + private void removeAllFaceForUserAndFinish(final int userId, RemovalTracker tracker) { + if (mFaceManager != null && mFaceManager.isHardwareDetected()) { + if (mFaceManager.hasEnrolledFaces(userId)) { + mFaceManager.setActiveUser(userId); + Face face = new Face(null, 0, 0); + mFaceManager.remove(face, userId, + new FaceManager.RemovalCallback() { + @Override + public void onRemovalError(Face face, int errMsgId, CharSequence err) { + Log.e(TAG, String.format("Can't remove face %d. Reason: %s", + face.getBiometricId(), err)); + } + @Override + public void onRemovalSucceeded(Face face, int remaining) { + if (remaining == 0) { + removeManagedProfileFacesAndFinishIfNecessary(userId, tracker); + } + } + }); + } else { + // No faces in this user, we may also want to delete managed profile faces + removeManagedProfileFacesAndFinishIfNecessary(userId, tracker); + } + } else { + tracker.onFaceDone(); + } + } + + // TODO: figure out how to eliminate duplicated code. It's a bit hard due to the async-ness + private void removeManagedProfileFacesAndFinishIfNecessary(final int parentUserId, + RemovalTracker tracker) { + if (mFaceManager != null && mFaceManager.isHardwareDetected()) { + mFaceManager.setActiveUser(UserHandle.myUserId()); + } + boolean hasChildProfile = false; + if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) { + // Current user is primary profile, remove work profile faces if necessary + final List profiles = mUserManager.getProfiles(parentUserId); + final int profilesSize = profiles.size(); + for (int i = 0; i < profilesSize; i++) { + final UserInfo userInfo = profiles.get(i); + if (userInfo.isManagedProfile() && !mLockPatternUtils + .isSeparateProfileChallengeEnabled(userInfo.id)) { + removeAllFaceForUserAndFinish(userInfo.id, tracker); + hasChildProfile = true; + break; + } + } + } + if (!hasChildProfile) { + tracker.onFaceDone(); } }