From 9d357ea072d5ebc0c9fb3798e80dc16c5fd78077 Mon Sep 17 00:00:00 2001 From: Clara Bayarri Date: Thu, 28 Jan 2016 17:50:53 +0000 Subject: [PATCH] Call reportFailedPasswordAttempt from Work Challenge Entering the wrong credential in ConfirmDeviceCredentials should also count as failed attempts for the password, after which the DPC have set a restriction to wipe the work profile. Fixed related issues, such as the CredentialChecker re-sending the result after onResume causing additional attempts to be counted. The new error message String is also displayed initially when there are pending attempts to inform the user that they are not starting from fresh. Bug: 26677759 Change-Id: I70cfae4c05e705ad7fe93bc071426459b79e7d0c --- res/values/strings.xml | 15 +++ .../ConfirmDeviceCredentialBaseFragment.java | 97 +++++++++++++++++++ .../android/settings/ConfirmLockPassword.java | 58 +++++------ .../android/settings/ConfirmLockPattern.java | 29 ++++-- .../CredentialCheckResultTracker.java | 6 +- 5 files changed, 162 insertions(+), 43 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index e6831175347..8b5f6339912 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1130,6 +1130,21 @@ Change unlock password + + Try again. Attempt %1$d of %2$d. + + Last try + + If you enter an incorrect work pattern on this attempt, your work profile and associated data will be removed from this device. + + If you enter an incorrect work PIN on this attempt, your work profile and associated data will be removed from this device. + + If you enter an incorrect work password on this attempt, your work profile and associated data will be removed from this device. + + Too many incorrect attempts. Your work profile and associated data will be removed from this device. + + Dismiss + Password must be at least %d characters diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java index 40e3103bf37..ad1d2ebd2d6 100644 --- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java @@ -20,10 +20,13 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityOptions; +import android.app.AlertDialog; import android.app.IActivityManager; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentSender; import android.graphics.Point; @@ -31,7 +34,9 @@ import android.graphics.PorterDuff; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; import android.os.UserManager; import android.view.View; import android.view.ViewGroup; @@ -40,6 +45,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import com.android.internal.widget.LockPatternUtils; import com.android.settings.fingerprint.FingerprintUiHelper; /** @@ -65,6 +71,9 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr protected Button mCancelButton; protected ImageView mFingerprintIcon; protected int mEffectiveUserId; + protected LockPatternUtils mLockPatternUtils; + protected TextView mErrorTextView; + protected final Handler mHandler = new Handler(); @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -74,6 +83,7 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr // Only take this argument into account if it belongs to the current profile. Intent intent = getActivity().getIntent(); mEffectiveUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras()); + mLockPatternUtils = new LockPatternUtils(getActivity()); } @Override @@ -109,6 +119,10 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr if (mAllowFpAuthentication) { mFingerprintHelper.startListening(); } + if (isProfileChallenge()) { + updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts( + mEffectiveUserId)); + } } protected void setAccessibilityTitle(CharSequence suplementalText) { @@ -200,4 +214,87 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr screenSize.y)); } } + + protected boolean isProfileChallenge() { + return UserHandle.myUserId() != mEffectiveUserId; + } + + protected void reportSuccessfullAttempt() { + if (isProfileChallenge()) { + mLockPatternUtils.reportSuccessfulPasswordAttempt(mEffectiveUserId); + } + } + + protected void reportFailedAttempt() { + if (isProfileChallenge()) { + // + 1 for this attempt. + updateErrorMessage( + mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId) + 1); + mLockPatternUtils.reportFailedPasswordAttempt(mEffectiveUserId); + } + } + + protected void updateErrorMessage(int numAttempts) { + final int maxAttempts = + mLockPatternUtils.getMaximumFailedPasswordsForWipe(mEffectiveUserId); + if (maxAttempts > 0 && numAttempts > 0) { + int remainingAttempts = maxAttempts - numAttempts; + if (remainingAttempts == 1) { + // Last try + final String title = getActivity().getString( + R.string.lock_profile_wipe_warning_title); + final String message = getActivity().getString(getLastTryErrorMessage()); + showDialog(title, message, android.R.string.ok, false /* dismiss */); + } else if (remainingAttempts <= 0) { + // Profile is wiped + final String message = getActivity().getString(R.string.lock_profile_wipe_content); + showDialog(null, message, R.string.lock_profile_wipe_dismiss, true /* dismiss */); + } + if (mErrorTextView != null) { + final String message = getActivity().getString(R.string.lock_profile_wipe_attempts, + numAttempts, maxAttempts); + showError(message, 0); + } + } + } + + protected abstract int getLastTryErrorMessage(); + + private final Runnable mResetErrorRunnable = new Runnable() { + @Override + public void run() { + mErrorTextView.setText(""); + } + }; + + protected void showError(CharSequence msg, long timeout) { + mErrorTextView.setText(msg); + onShowError(); + mHandler.removeCallbacks(mResetErrorRunnable); + if (timeout != 0) { + mHandler.postDelayed(mResetErrorRunnable, timeout); + } + } + + protected abstract void onShowError(); + + protected void showError(int msg, long timeout) { + showError(getText(msg), timeout); + } + + private void showDialog(String title, String message, int buttonString, final boolean dismiss) { + final AlertDialog dialog = new AlertDialog.Builder(getActivity()) + .setTitle(title) + .setMessage(message) + .setPositiveButton(buttonString, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (dismiss) { + getActivity().finish(); + } + } + }) + .create(); + dialog.show(); + } } diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java index 8f832210707..c69bb894509 100644 --- a/src/com/android/settings/ConfirmLockPassword.java +++ b/src/com/android/settings/ConfirmLockPassword.java @@ -20,11 +20,9 @@ import android.app.Fragment; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; -import android.content.IntentSender; import android.os.AsyncTask; import android.os.Bundle; import android.os.CountDownTimer; -import android.os.Handler; import android.os.SystemClock; import android.os.UserManager; import android.os.storage.StorageManager; @@ -84,14 +82,11 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result"; private TextView mPasswordEntry; private TextViewInputDisabler mPasswordEntryInputDisabler; - private LockPatternUtils mLockPatternUtils; private AsyncTask mPendingLockCheck; private CredentialCheckResultTracker mCredentialCheckResultTracker; private boolean mDisappearing = false; private TextView mHeaderTextView; private TextView mDetailsTextView; - private TextView mErrorTextView; - private Handler mHandler = new Handler(); private CountDownTimer mCountdownTimer; private boolean mIsAlpha; private InputMethodManager mImm; @@ -108,7 +103,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mLockPatternUtils = new LockPatternUtils(getActivity()); } @Override @@ -193,6 +187,12 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { : R.string.lockpassword_invalid_pin; } + @Override + protected int getLastTryErrorMessage() { + return mIsAlpha ? R.string.lock_profile_wipe_warning_content_password + : R.string.lock_profile_wipe_warning_content_pin; + } + @Override public void prepareEnterAnimation() { super.prepareEnterAnimation(); @@ -406,9 +406,12 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { } private void onPasswordChecked(boolean matched, Intent intent, int timeoutMs, - int effectiveUserId) { + int effectiveUserId, boolean newResult) { mPasswordEntryInputDisabler.setInputEnabled(true); if (matched) { + if (newResult) { + reportSuccessfullAttempt(); + } startDisappearAnimation(intent); checkForPendingIntent(); } else { @@ -417,15 +420,23 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { effectiveUserId, timeoutMs); handleAttemptLockout(deadline); } else { - showError(getErrorMessage()); + showError(getErrorMessage(), ERROR_MESSAGE_TIMEOUT); + } + if (newResult) { + reportFailedAttempt(); } } } @Override public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs, - int effectiveUserId) { - onPasswordChecked(matched, intent, timeoutMs, effectiveUserId); + int effectiveUserId, boolean newResult) { + onPasswordChecked(matched, intent, timeoutMs, effectiveUserId, newResult); + } + + @Override + protected void onShowError() { + mPasswordEntry.setText(null); } private void handleAttemptLockout(long elapsedRealtimeDeadline) { @@ -447,6 +458,10 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { public void onFinish() { resetState(); mErrorTextView.setText(""); + if (isProfileChallenge()) { + updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts( + mEffectiveUserId)); + } } }.start(); } @@ -464,29 +479,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity { } } - private void showError(int msg) { - showError(msg, ERROR_MESSAGE_TIMEOUT); - } - - private final Runnable mResetErrorRunnable = new Runnable() { - public void run() { - mErrorTextView.setText(""); - } - }; - - private void showError(CharSequence msg, long timeout) { - mErrorTextView.setText(msg); - mPasswordEntry.setText(null); - mHandler.removeCallbacks(mResetErrorRunnable); - if (timeout != 0) { - mHandler.postDelayed(mResetErrorRunnable, timeout); - } - } - - private void showError(int msg, long timeout) { - showError(getText(msg), timeout); - } - // {@link OnEditorActionListener} methods. public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { // Check if this was the result of hitting the enter or "done" key diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java index d4b09025693..dbe9ebe9293 100644 --- a/src/com/android/settings/ConfirmLockPattern.java +++ b/src/com/android/settings/ConfirmLockPattern.java @@ -18,7 +18,6 @@ package com.android.settings; import android.app.Activity; import android.content.Intent; -import android.content.IntentSender; import android.os.AsyncTask; import android.os.Bundle; import android.os.CountDownTimer; @@ -85,7 +84,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result"; private LockPatternView mLockPatternView; - private LockPatternUtils mLockPatternUtils; private AsyncTask mPendingLockCheck; private CredentialCheckResultTracker mCredentialCheckResultTracker; private boolean mDisappearing = false; @@ -93,7 +91,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { private TextView mHeaderTextView; private TextView mDetailsTextView; - private TextView mErrorTextView; private View mLeftSpacerLandscape; private View mRightSpacerLandscape; @@ -112,7 +109,6 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mLockPatternUtils = new LockPatternUtils(getActivity()); } @Override @@ -220,6 +216,10 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { mCredentialCheckResultTracker.setListener(this); } + @Override + protected void onShowError() { + } + @Override public void prepareEnterAnimation() { super.prepareEnterAnimation(); @@ -284,6 +284,10 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { R.string.lockpassword_confirm_your_pattern_generic_profile); } mErrorTextView.setText(""); + if (isProfileChallenge()) { + updateErrorMessage(mLockPatternUtils.getCurrentFailedPasswordAttempts( + mEffectiveUserId)); + } mLockPatternView.setEnabled(true); mLockPatternView.enableInput(); @@ -470,9 +474,12 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { }; private void onPatternChecked(boolean matched, Intent intent, int timeoutMs, - int effectiveUserId) { + int effectiveUserId, boolean newResult) { mLockPatternView.setEnabled(true); if (matched) { + if (newResult) { + reportSuccessfullAttempt(); + } startDisappearAnimation(intent); checkForPendingIntent(); } else { @@ -484,13 +491,21 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity { updateStage(Stage.NeedToUnlockWrong); postClearPatternRunnable(); } + if (newResult) { + reportFailedAttempt(); + } } } @Override public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs, - int effectiveUserId) { - onPatternChecked(matched, intent, timeoutMs, effectiveUserId); + int effectiveUserId, boolean newResult) { + onPatternChecked(matched, intent, timeoutMs, effectiveUserId, newResult); + } + + @Override + protected int getLastTryErrorMessage() { + return R.string.lock_profile_wipe_warning_content_pattern; } private void handleAttemptLockout(long elapsedRealtimeDeadline) { diff --git a/src/com/android/settings/CredentialCheckResultTracker.java b/src/com/android/settings/CredentialCheckResultTracker.java index 5c5507344e3..179a93c7ad6 100644 --- a/src/com/android/settings/CredentialCheckResultTracker.java +++ b/src/com/android/settings/CredentialCheckResultTracker.java @@ -47,7 +47,7 @@ public class CredentialCheckResultTracker extends Fragment { mListener = listener; if (mListener != null && mHasResult) { mListener.onCredentialChecked(mResultMatched, mResultData, mResultTimeoutMs, - mResultEffectiveUserId); + mResultEffectiveUserId, false /* newResult */); } } @@ -60,7 +60,7 @@ public class CredentialCheckResultTracker extends Fragment { mHasResult = true; if (mListener != null) { mListener.onCredentialChecked(mResultMatched, mResultData, mResultTimeoutMs, - mResultEffectiveUserId); + mResultEffectiveUserId, true /* newResult */); } } @@ -74,6 +74,6 @@ public class CredentialCheckResultTracker extends Fragment { interface Listener { public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs, - int effectiveUserId); + int effectiveUserId, boolean newResult); } }