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

@@ -1300,8 +1300,8 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_writeApnSettings">change/intercept network settings and traffic</string> <string name="permlab_writeApnSettings">change/intercept network settings and traffic</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_writeApnSettings">Allows an application to change network settings and to intercept and inspect all network traffic, <string name="permdesc_writeApnSettings">Allows an application to change network settings and to intercept and inspect all network traffic,
for example to change the proxy and port of any APN. Malicious applications could monitor, redirect, or modify network for example to change the proxy and port of any APN. Malicious applications could monitor, redirect, or modify network
packets without your knowledge.</string> packets without your knowledge.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -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;