Migrate settings UI to use async security check

Bug: 20697812
Change-Id: Ieb0090ddb61198a60abb1e34ff9c6e8476c33789
diff --git a/src/com/android/settings/ChooseLockPassword.java b/src/com/android/settings/ChooseLockPassword.java
index 0817eeb..1338ac7 100644
--- a/src/com/android/settings/ChooseLockPassword.java
+++ b/src/com/android/settings/ChooseLockPassword.java
@@ -17,6 +17,7 @@
 package com.android.settings;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.PasswordEntryKeyboardHelper;
 import com.android.internal.widget.PasswordEntryKeyboardView;
@@ -28,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.inputmethodservice.KeyboardView;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -134,6 +136,7 @@
         private int mPasswordMinNumeric = 0;
         private int mPasswordMinNonLetter = 0;
         private LockPatternUtils mLockPatternUtils;
+        private AsyncTask<?, ?, ?> mPendingLockCheck;
         private int mRequestedQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
         private ChooseLockSettingsHelper mChooseLockSettingsHelper;
         private Stage mUiStage = Stage.Introduction;
@@ -312,12 +315,17 @@
         public void onResume() {
             super.onResume();
             updateStage(mUiStage);
+            mPasswordEntry.setEnabled(true);
             mKeyboardView.requestFocus();
         }
 
         @Override
         public void onPause() {
             mHandler.removeMessages(MSG_SHOW_ERROR);
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+                mPendingLockCheck = null;
+            }
 
             super.onPause();
         }
@@ -489,19 +497,12 @@
                             UserHandle.myUserId());
 
                     if (mHasChallenge) {
-                        Intent intent = new Intent();
-                        byte[] token = mLockPatternUtils.verifyPassword(pin, mChallenge,
-                                UserHandle.myUserId());
-                        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
-                        getActivity().setResult(RESULT_FINISHED, intent);
+                        startVerifyPassword(pin, wasSecureBefore);
+                        return;
                     } else {
                         getActivity().setResult(RESULT_FINISHED);
                     }
-                    getActivity().finish();
-                    mDone = true;
-                    if (!wasSecureBefore) {
-                        startActivity(getRedactionInterstitialIntent(getActivity()));
-                    }
+                    finishConfirmStage(wasSecureBefore);
                 } else {
                     CharSequence tmp = mPasswordEntry.getText();
                     if (tmp != null) {
@@ -515,6 +516,43 @@
             }
         }
 
+        private void startVerifyPassword(final String pin, final boolean wasSecureBefore) {
+            mPasswordEntry.setEnabled(false);
+            setNextEnabled(false);
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+            }
+
+            mPendingLockCheck = LockPatternChecker.verifyPassword(
+                    mLockPatternUtils,
+                    pin,
+                    mChallenge,
+                    UserHandle.myUserId(),
+                    new LockPatternChecker.OnVerifyCallback() {
+                        @Override
+                        public void onVerified(byte[] token) {
+                            mPasswordEntry.setEnabled(true);
+                            setNextEnabled(true);
+                            mPendingLockCheck = null;
+
+                            Intent intent = new Intent();
+                            intent.putExtra(
+                                    ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
+                                    token);
+                            getActivity().setResult(RESULT_FINISHED, intent);
+                            finishConfirmStage(wasSecureBefore);
+                        }
+                    });
+        }
+
+        private void finishConfirmStage(boolean wasSecureBefore) {
+            getActivity().finish();
+            mDone = true;
+            if (!wasSecureBefore) {
+                startActivity(getRedactionInterstitialIntent(getActivity()));
+            }
+        }
+
         protected void setNextEnabled(boolean enabled) {
             mNextButton.setEnabled(enabled);
         }
diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java
index 99e8d24..5d24449 100644
--- a/src/com/android/settings/ChooseLockPattern.java
+++ b/src/com/android/settings/ChooseLockPattern.java
@@ -19,6 +19,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.google.android.collect.Lists;
 import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
 import com.android.internal.widget.LockPatternView.Cell;
@@ -30,6 +31,7 @@
 import android.app.Fragment;
 import android.content.Context;
 import android.content.Intent;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.view.KeyEvent;
@@ -350,6 +352,7 @@
         };
 
         private ChooseLockSettingsHelper mChooseLockSettingsHelper;
+        private AsyncTask<?, ?, ?> mPendingLockCheck;
 
         private static final String KEY_UI_STAGE = "uiStage";
         private static final String KEY_PATTERN_CHOICE = "chosenPattern";
@@ -432,6 +435,21 @@
             mDone = false;
         }
 
+        @Override
+        public void onResume() {
+            super.onResume();
+            mLockPatternView.enableInput();
+        }
+
+        @Override
+        public void onPause() {
+            super.onPause();
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+                mPendingLockCheck = null;
+            }
+        }
+
         protected Intent getRedactionInterstitialIntent(Context context) {
             return RedactionInterstitial.createStartIntent(context);
         }
@@ -623,15 +641,42 @@
             }
 
             if (mHasChallenge) {
-                Intent intent = new Intent();
-                byte[] token = utils.verifyPattern(mChosenPattern, mChallenge,
-                        UserHandle.myUserId());
-                intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
-                getActivity().setResult(RESULT_FINISHED, intent);
+                startVerifyPattern(utils);
+                return;
             } else {
                 getActivity().setResult(RESULT_FINISHED);
             }
 
+            doFinish();
+        }
+
+        private void startVerifyPattern(LockPatternUtils utils) {
+            mLockPatternView.disableInput();
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+            }
+
+            mPendingLockCheck = LockPatternChecker.verifyPattern(
+                    utils,
+                    mChosenPattern,
+                    mChallenge,
+                    UserHandle.myUserId(),
+                    new LockPatternChecker.OnVerifyCallback() {
+                        @Override
+                        public void onVerified(byte[] token) {
+                            mLockPatternView.enableInput();
+                            mPendingLockCheck = null;
+
+                            Intent intent = new Intent();
+                            intent.putExtra(
+                                    ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
+                            getActivity().setResult(RESULT_FINISHED, intent);
+                            doFinish();
+                        }
+                    });
+        }
+
+        private void doFinish() {
             getActivity().finish();
             mDone = true;
         }
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 0994086..388fde7 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -20,10 +20,12 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternUtils;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.Intent;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.CountDownTimer;
 import android.os.Handler;
@@ -65,6 +67,7 @@
         private static final long ERROR_MESSAGE_TIMEOUT = 3000;
         private TextView mPasswordEntry;
         private LockPatternUtils mLockPatternUtils;
+        private AsyncTask<?, ?, ?> mPendingLockCheck;
         private TextView mHeaderTextView;
         private TextView mDetailsTextView;
         private TextView mErrorTextView;
@@ -148,6 +151,10 @@
                 mCountdownTimer.cancel();
                 mCountdownTimer = null;
             }
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+                mPendingLockCheck = null;
+            }
         }
 
         @Override
@@ -161,6 +168,8 @@
             long deadline = mLockPatternUtils.getLockoutAttemptDeadline(UserHandle.myUserId());
             if (deadline != 0) {
                 handleAttemptLockout(deadline);
+            } else {
+                mPasswordEntry.setEnabled(true);
             }
         }
 
@@ -178,32 +187,79 @@
         }
 
         private void handleNext() {
+            mPasswordEntry.setEnabled(false);
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+            }
+
             final String pin = mPasswordEntry.getText().toString();
             final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
-            boolean matched = false;
             Intent intent = new Intent();
             if (verifyChallenge)  {
-                if (getActivity() instanceof ConfirmLockPassword.InternalActivity) {
-                    long challenge = getActivity().getIntent().getLongExtra(
-                            ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
-                    byte[] token = mLockPatternUtils.verifyPassword(pin, challenge,
-                            UserHandle.myUserId());
-                    if (token != null) {
-                        matched = true;
-                        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
-                    }
+                if (isInternalActivity()) {
+                    startVerifyPassword(pin, intent);
+                    return;
                 }
-            } else if (mLockPatternUtils.checkPassword(pin, UserHandle.myUserId())) {
-                matched = true;
-                if (getActivity() instanceof ConfirmLockPassword.InternalActivity) {
-                    intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
-                                    mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
-                                             : StorageManager.CRYPT_TYPE_PIN);
-                    intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
-                }
+            } else {
+                startCheckPassword(pin, intent);
+                return;
             }
 
+            onPasswordChecked(false, intent);
+        }
+
+        private boolean isInternalActivity() {
+            return getActivity() instanceof ConfirmLockPassword.InternalActivity;
+        }
+
+        private void startVerifyPassword(final String pin, final Intent intent) {
+            long challenge = getActivity().getIntent().getLongExtra(
+                    ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
+            mPendingLockCheck = LockPatternChecker.verifyPassword(
+                    mLockPatternUtils,
+                    pin,
+                    challenge,
+                    UserHandle.myUserId(),
+                    new LockPatternChecker.OnVerifyCallback() {
+                        @Override
+                        public void onVerified(byte[] token) {
+                            mPendingLockCheck = null;
+                            boolean matched = false;
+                            if (token != null) {
+                                matched = true;
+                                intent.putExtra(
+                                        ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
+                                        token);
+                            }
+                            onPasswordChecked(matched, intent);
+                        }
+                    });
+        }
+
+        private void startCheckPassword(final String pin, final Intent intent) {
+            mPendingLockCheck = LockPatternChecker.checkPassword(
+                    mLockPatternUtils,
+                    pin,
+                    UserHandle.myUserId(),
+                    new LockPatternChecker.OnCheckCallback() {
+                        @Override
+                        public void onChecked(boolean matched) {
+                            mPendingLockCheck = null;
+                            if (matched && isInternalActivity()) {
+                                intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
+                                                mIsAlpha ? StorageManager.CRYPT_TYPE_PASSWORD
+                                                         : StorageManager.CRYPT_TYPE_PIN);
+                                intent.putExtra(
+                                        ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
+                            }
+                            onPasswordChecked(matched, intent);
+                        }
+                    });
+        }
+
+        private void onPasswordChecked(boolean matched, Intent intent) {
+            mPasswordEntry.setEnabled(true);
             if (matched) {
                 getActivity().setResult(RESULT_OK, intent);
                 getActivity().finish();
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 2d0d117..636c315 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -20,6 +20,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
 import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
+import com.android.internal.widget.LockPatternChecker;
 import com.android.internal.widget.LockPatternView.Cell;
 
 import android.annotation.Nullable;
@@ -27,6 +28,7 @@
 import android.content.Intent;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
@@ -77,6 +79,7 @@
 
         private LockPatternView mLockPatternView;
         private LockPatternUtils mLockPatternUtils;
+        private AsyncTask<?, ?, ?> mPendingLockCheck;
         private int mNumWrongConfirmAttempts;
         private CountDownTimer mCountdownTimer;
 
@@ -157,6 +160,10 @@
             if (mCountdownTimer != null) {
                 mCountdownTimer.cancel();
             }
+            if (mPendingLockCheck != null) {
+                mPendingLockCheck.cancel(false);
+                mPendingLockCheck = null;
+            }
         }
 
         @Override
@@ -173,8 +180,8 @@
             if (deadline != 0) {
                 handleAttemptLockout(deadline);
             } else if (!mLockPatternView.isEnabled()) {
-                // The deadline has passed, but the timer was cancelled...
-                // Need to clean up.
+                // The deadline has passed, but the timer was cancelled. Or the pending lock
+                // check was cancelled. Need to clean up.
                 mNumWrongConfirmAttempts = 0;
                 updateStage(Stage.NeedToUnlock);
             }
@@ -198,6 +205,7 @@
 
                     mLockPatternView.setEnabled(true);
                     mLockPatternView.enableInput();
+                    mLockPatternView.clearPattern();
                     break;
                 case NeedToUnlockWrong:
                     mErrorTextView.setText(R.string.lockpattern_need_to_unlock_wrong);
@@ -269,32 +277,81 @@
             }
 
             public void onPatternDetected(List<LockPatternView.Cell> pattern) {
-                final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
-                        ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
-                boolean matched = false;
-                Intent intent = new Intent();
-                if (verifyChallenge) {
-                    if (getActivity() instanceof ConfirmLockPattern.InternalActivity) {
-                        long challenge = getActivity().getIntent().getLongExtra(
-                            ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
-                        byte[] token = mLockPatternUtils.verifyPattern(pattern, challenge,
-                                UserHandle.myUserId());
-                        if (token != null) {
-                            matched = true;
-                            intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
-                        }
-                    }
-                } else if (mLockPatternUtils.checkPattern(pattern, UserHandle.myUserId())) {
-                    matched = true;
-                    if (getActivity() instanceof ConfirmLockPattern.InternalActivity) {
-                        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
-                                        StorageManager.CRYPT_TYPE_PATTERN);
-                        intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
-                                        LockPatternUtils.patternToString(pattern));
-                    }
-
+                mLockPatternView.setEnabled(false);
+                if (mPendingLockCheck != null) {
+                    mPendingLockCheck.cancel(false);
                 }
 
+                final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
+                        ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
+                Intent intent = new Intent();
+                if (verifyChallenge) {
+                    if (isInternalActivity()) {
+                        startVerifyPattern(pattern, intent);
+                        return;
+                    }
+                } else {
+                    startCheckPattern(pattern, intent);
+                    return;
+                }
+
+                onPatternChecked(pattern, false, intent);
+            }
+
+            private boolean isInternalActivity() {
+                return getActivity() instanceof ConfirmLockPattern.InternalActivity;
+            }
+
+            private void startVerifyPattern(final List<LockPatternView.Cell> pattern,
+                    final Intent intent) {
+                long challenge = getActivity().getIntent().getLongExtra(
+                        ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
+                mPendingLockCheck = LockPatternChecker.verifyPattern(
+                        mLockPatternUtils,
+                        pattern,
+                        challenge,
+                        UserHandle.myUserId(),
+                        new LockPatternChecker.OnVerifyCallback() {
+                            @Override
+                            public void onVerified(byte[] token) {
+                                mPendingLockCheck = null;
+                                boolean matched = false;
+                                if (token != null) {
+                                    matched = true;
+                                    intent.putExtra(
+                                            ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
+                                            token);
+                                }
+                                onPatternChecked(pattern, matched, intent);
+                            }
+                        });
+            }
+
+            private void startCheckPattern(final List<LockPatternView.Cell> pattern,
+                    final Intent intent) {
+                mPendingLockCheck = LockPatternChecker.checkPattern(
+                        mLockPatternUtils,
+                        pattern,
+                        UserHandle.myUserId(),
+                        new LockPatternChecker.OnCheckCallback() {
+                            @Override
+                            public void onChecked(boolean matched) {
+                                mPendingLockCheck = null;
+                                if (matched && isInternalActivity()) {
+                                    intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_TYPE,
+                                                    StorageManager.CRYPT_TYPE_PATTERN);
+                                    intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
+                                                    LockPatternUtils.patternToString(pattern));
+                                }
+                                onPatternChecked(pattern, matched, intent);
+                            }
+                        });
+            }
+
+            private void onPatternChecked(List<LockPatternView.Cell> pattern,
+                    boolean matched,
+                    Intent intent) {
+                mLockPatternView.setEnabled(true);
                 if (matched) {
                     getActivity().setResult(Activity.RESULT_OK, intent);
                     getActivity().finish();