Merge "Fix 5026428: Rework unlock attempt logic with active DPM to show better messages"

This commit is contained in:
Jim Miller
2011-08-22 13:36:07 -07:00
committed by Android (Google) Code Review
4 changed files with 122 additions and 57 deletions

View File

@@ -83,6 +83,13 @@ public class LockPatternUtils {
*/ */
public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L; public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
/**
* This dictates when we start telling the user that continued failed attempts will wipe
* their device.
*/
public static final int FAILED_ATTEMPTS_BEFORE_WIPE_GRACE = 5;
/** /**
* The minimum number of dots in a valid pattern. * The minimum number of dots in a valid pattern.
*/ */
@@ -93,7 +100,7 @@ public class LockPatternUtils {
* attempt for it to be counted against the counts that affect * attempt for it to be counted against the counts that affect
* {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET} * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
*/ */
public static final int MIN_PATTERN_REGISTER_FAIL = 3; public static final int MIN_PATTERN_REGISTER_FAIL = MIN_LOCK_PATTERN_SIZE;
private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently"; private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline"; private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
@@ -112,6 +119,7 @@ public class LockPatternUtils {
private static final AtomicBoolean sHaveNonZeroPatternFile = new AtomicBoolean(false); private static final AtomicBoolean sHaveNonZeroPatternFile = new AtomicBoolean(false);
private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false); private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
private static FileObserver sPasswordObserver; private static FileObserver sPasswordObserver;
private static class PasswordFileObserver extends FileObserver { private static class PasswordFileObserver extends FileObserver {

View File

@@ -1857,7 +1857,7 @@
\n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds. \n\nPlease try again in <xliff:g id="number">%d</xliff:g> seconds.
</string> </string>
<!-- For the unlock screen, Information message shown in dialog when user is almost at the limit <!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
where they will be locked out and may have to enter an alternate username/password to unlock the phone --> where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet"> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet">
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times. You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
@@ -1865,7 +1865,8 @@
you will be asked to unlock your tablet using your Google sign-in.\n\n you will be asked to unlock your tablet using your Google sign-in.\n\n
Please try again in <xliff:g id="number">%d</xliff:g> seconds. Please try again in <xliff:g id="number">%d</xliff:g> seconds.
</string> </string>
<!-- For the unlock screen, Information message shown in dialog when user is almost at the limit
<!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
where they will be locked out and may have to enter an alternate username/password to unlock the phone --> where they will be locked out and may have to enter an alternate username/password to unlock the phone -->
<string name="lockscreen_failed_attempts_almost_glogin" product="default"> <string name="lockscreen_failed_attempts_almost_glogin" product="default">
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times. You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
@@ -1874,6 +1875,36 @@
Please try again in <xliff:g id="number">%d</xliff:g> seconds. Please try again in <xliff:g id="number">%d</xliff:g> seconds.
</string> </string>
<!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
where the device will be wiped. -->
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet">
You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
the tablet will be reset to factory default and all user data will be lost.
</string>
<!-- For the unlock screen, informational message shown in dialog when user is almost at the limit
where the device will be wiped. -->
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default">
You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
the phone will be reset to factory default and all user data will be lost.
</string>
<!-- For the unlock screen, informational message shown in dialog when user has exceeded the
maximum attempts and the device will now be wiped -->
<string name="lockscreen_failed_attempts_now_wiping" product="tablet">
You have incorrectly attempted to unlock the tablet <xliff:g id="number">%d</xliff:g> times.
The tablet will now be reset to factory default.
</string>
<!-- For the unlock screen, informational message shown in dialog when user has exceeded the
maximum attempts and the device will now be wiped -->
<string name="lockscreen_failed_attempts_now_wiping" product="default">
You have incorrectly attempted to unlock the phone <xliff:g id="number">%d</xliff:g> times.
The phone will now be reset to factory default.
</string>
<!-- On the unlock screen, countdown message shown while user is waiting to try again after too many <!-- On the unlock screen, countdown message shown while user is waiting to try again after too many
failed attempts --> failed attempts -->
<string name="lockscreen_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string> <string name="lockscreen_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>

View File

@@ -42,6 +42,7 @@ import android.os.SystemProperties;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.util.Slog;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
@@ -294,22 +295,47 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
public void reportFailedUnlockAttempt() { public void reportFailedUnlockAttempt() {
mUpdateMonitor.reportFailedAttempt(); mUpdateMonitor.reportFailedAttempt();
final int failedAttempts = mUpdateMonitor.getFailedAttempts(); final int failedAttempts = mUpdateMonitor.getFailedAttempts();
if (DEBUG) Log.d(TAG, if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts +
"reportFailedPatternAttempt: #" + failedAttempts +
" (enableFallback=" + mEnableFallback + ")"); " (enableFallback=" + mEnableFallback + ")");
final boolean usingLockPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
final boolean usingPattern = mLockPatternUtils.getKeyguardStoredPasswordQuality()
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
if (usingLockPattern && mEnableFallback && failedAttempts ==
(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { .getMaximumFailedPasswordsForWipe(null);
showAlmostAtAccountLoginDialog();
} else if (usingLockPattern && mEnableFallback final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
&& failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
mLockPatternUtils.setPermanentlyLocked(true);
updateScreen(mMode); final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
} else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) (failedAttemptsBeforeWipe - failedAttempts)
== 0) { : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
showTimeoutDialog();
if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
// If we reach this code, it means the user has installed a DevicePolicyManager
// that requests device wipe after N attempts. Once we get below the grace
// period, we'll post this dialog every time as a clear warning until the
// bombshell hits and the device is wiped.
if (remainingBeforeWipe > 0) {
showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
} else {
// Too many attempts. The device will be wiped shortly.
Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
showWipeDialog(failedAttempts);
}
} else if (usingPattern && mEnableFallback) {
if (failedAttempts == failedAttemptWarning) {
showAlmostAtAccountLoginDialog();
} else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
mLockPatternUtils.setPermanentlyLocked(true);
updateScreen(mMode);
}
} else {
final boolean showTimeout =
(failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
if (showTimeout) {
showTimeoutDialog();
}
} }
mLockPatternUtils.reportFailedPasswordAttempt(); mLockPatternUtils.reportFailedPasswordAttempt();
} }
@@ -727,26 +753,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
return currentMode; return currentMode;
} }
private void showTimeoutDialog() { private void showDialog(String title, String message) {
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message;
if(getUnlockMode() == UnlockMode.Password) {
if(mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message;
} else {
messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message;
}
}
String message = mContext.getString(
messageId,
mUpdateMonitor.getFailedAttempts(),
timeoutInSeconds);
final AlertDialog dialog = new AlertDialog.Builder(mContext) final AlertDialog dialog = new AlertDialog.Builder(mContext)
.setTitle(null) .setTitle(title)
.setMessage(message) .setMessage(message)
.setNeutralButton(R.string.ok, null) .setNeutralButton(R.string.ok, null)
.create(); .create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
if (!mContext.getResources().getBoolean( if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) { com.android.internal.R.bool.config_sf_slowBlur)) {
@@ -757,27 +769,42 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
dialog.show(); dialog.show();
} }
private void showTimeoutDialog() {
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
int messageId = R.string.lockscreen_too_many_failed_attempts_dialog_message;
if (getUnlockMode() == UnlockMode.Password) {
if(mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
messageId = R.string.lockscreen_too_many_failed_pin_attempts_dialog_message;
} else {
messageId = R.string.lockscreen_too_many_failed_password_attempts_dialog_message;
}
}
String message = mContext.getString(messageId, mUpdateMonitor.getFailedAttempts(),
timeoutInSeconds);
showDialog(null, message);
}
private void showAlmostAtAccountLoginDialog() { private void showAlmostAtAccountLoginDialog() {
final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
String message = mContext.getString(R.string.lockscreen_failed_attempts_almost_glogin,
count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
showDialog(null, message);
}
private void showAlmostAtWipeDialog(int attempts, int remaining) {
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000; int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
String message = mContext.getString( String message = mContext.getString(
R.string.lockscreen_failed_attempts_almost_glogin, R.string.lockscreen_failed_attempts_almost_at_wipe, attempts, remaining);
LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET showDialog(null, message);
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, }
LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT,
timeoutInSeconds); private void showWipeDialog(int attempts) {
final AlertDialog dialog = new AlertDialog.Builder(mContext) String message = mContext.getString(
.setTitle(null) R.string.lockscreen_failed_attempts_now_wiping, attempts);
.setMessage(message) showDialog(null, message);
.setNeutralButton(R.string.ok, null)
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
dialog.show();
} }
/** /**

View File

@@ -41,7 +41,6 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype;
import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;