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

Commit 0b95687f authored by Kevin Chyn's avatar Kevin Chyn
Browse files

3/n: Remove all faces when Pin/Pattern/Pass is removed

Bug: 110589286

Test: set up fingerprint + pass, change lock screen to swipe
      no regression, fingerprints are all removed, activity is finished()

Change-Id: Ie5e586b2f9d2c982d929e5c5b80911897889e7a4
parent 81dc0295
Loading
Loading
Loading
Loading
+101 −9
Original line number Diff line number Diff line
@@ -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<UserInfo> 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();
            }
        }