Merge "Lots of keyguard improvements - Fix "too many attempts" dialogs - Fix account unlock mechanism so the user can use email account as backup for pattern unlock - Add mechanism to support future account recovery from non-pattern screen - Tune animation timing for flipping security view. - Move password field to the top of the security view - Add padding and visual feedback to navigation area button" into jb-mr1-dev
This commit is contained in:
@ -26,8 +26,8 @@
|
||||
android:pivotY="50%"
|
||||
android:fillEnabled="true"
|
||||
android:fillAfter="true"
|
||||
android:duration="@integer/flip_duration"
|
||||
android:startOffset="@integer/flip_duration" />
|
||||
android:duration="@integer/kg_security_flip_duration"
|
||||
android:startOffset="@integer/kg_security_flip_duration" />
|
||||
|
||||
</set>
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
android:pivotY="50%"
|
||||
android:fillEnabled="true"
|
||||
android:fillAfter="true"
|
||||
android:duration="@integer/flip_duration" />
|
||||
android:duration="@integer/kg_security_flip_duration" />
|
||||
|
||||
</set>
|
||||
|
||||
|
@ -23,12 +23,15 @@
|
||||
android:gravity="left">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/keyguard_click_area"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:padding="10dip"
|
||||
android:clickable="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="20dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="28dp"
|
||||
@ -36,7 +39,7 @@
|
||||
|
||||
<!-- message area for security screen -->
|
||||
<TextView
|
||||
android:id="@+id/message_area"
|
||||
android:id="@+id/keyguard_message_area"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
@ -48,14 +51,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- This is currently only uses for pattern unlock -->
|
||||
<Button android:id="@+id/forgot_password_button"
|
||||
android:layout_gravity="right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
|
||||
android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
|
||||
android:drawablePadding="0dip"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -26,11 +26,6 @@
|
||||
|
||||
<include layout="@layout/keyguard_navigation"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<!-- Password entry field -->
|
||||
<!-- Note: the entire container is styled to look like the edit field,
|
||||
since the backspace/IME switcher looks better inside -->
|
||||
@ -84,6 +79,11 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<!-- Numeric keyboard -->
|
||||
<com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -36,6 +36,15 @@
|
||||
|
||||
<Space android:layout_gravity="fill" />
|
||||
|
||||
<Button android:id="@+id/forgot_password_button"
|
||||
android:layout_gravity="right"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="@*android:dimen/keyguard_lockscreen_status_line_font_size"
|
||||
android:drawableLeft="@*android:drawable/lockscreen_forgot_password_button"
|
||||
android:drawablePadding="0dip"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!-- We need MATCH_PARENT here only to force the size of the parent to be passed to
|
||||
the pattern view for it to compute its size. This is an unusual case, caused by
|
||||
LockPatternView's requirement to maintain a square aspect ratio based on the width
|
||||
|
@ -17,5 +17,5 @@
|
||||
*/
|
||||
-->
|
||||
<resources>
|
||||
<integer name="flip_duration">300</integer>
|
||||
<integer name="kg_security_flip_duration">150</integer>
|
||||
</resources>
|
||||
|
@ -1309,7 +1309,8 @@
|
||||
<java-symbol type="id" name="two" />
|
||||
<java-symbol type="id" name="unlock_widget" />
|
||||
<java-symbol type="id" name="zero" />
|
||||
<java-symbol type="id" name="message_area" />
|
||||
<java-symbol type="id" name="keyguard_message_area" />
|
||||
<java-symbol type="id" name="keyguard_click_area" />
|
||||
<java-symbol type="id" name="keyguard_selector_view" />
|
||||
<java-symbol type="id" name="keyguard_pattern_view" />
|
||||
<java-symbol type="id" name="keyguard_password_view" />
|
||||
@ -1338,6 +1339,7 @@
|
||||
<java-symbol type="integer" name="config_lidNavigationAccessibility" />
|
||||
<java-symbol type="integer" name="config_lidOpenRotation" />
|
||||
<java-symbol type="integer" name="config_longPressOnHomeBehavior" />
|
||||
<java-symbol type="integer" name="kg_security_flip_duration" />
|
||||
<java-symbol type="layout" name="global_actions_item" />
|
||||
<java-symbol type="layout" name="global_actions_silent_mode" />
|
||||
<java-symbol type="layout" name="keyguard_screen_glogin_unlock" />
|
||||
@ -1440,7 +1442,12 @@
|
||||
<java-symbol type="string" name="kg_login_invalid_input" />
|
||||
<java-symbol type="string" name="kg_login_account_recovery_hint" />
|
||||
<java-symbol type="string" name="kg_login_checking_password" />
|
||||
|
||||
<java-symbol type="string" name="kg_too_many_failed_pin_attempts_dialog_message" />
|
||||
<java-symbol type="string" name="kg_too_many_failed_pattern_attempts_dialog_message" />
|
||||
<java-symbol type="string" name="kg_too_many_failed_password_attempts_dialog_message" />
|
||||
<java-symbol type="string" name="kg_failed_attempts_almost_at_wipe" />
|
||||
<java-symbol type="string" name="kg_failed_attempts_now_wiping" />
|
||||
<java-symbol type="string" name="kg_failed_attempts_almost_at_login" />
|
||||
|
||||
<!-- From services -->
|
||||
<java-symbol type="anim" name="screen_rotate_0_enter" />
|
||||
|
@ -3665,33 +3665,111 @@
|
||||
<string name="display_manager_overlay_display_title">Overlay #<xliff:g id="id">%1$d</xliff:g>: <xliff:g id="width">%2$d</xliff:g>x<xliff:g id="height">%3$d</xliff:g>, <xliff:g id="dpi">%4$d</xliff:g> dpi</string>
|
||||
|
||||
<!-- Keyguard strings -->
|
||||
<!-- Label shown on emergency call button in keyguard -->
|
||||
<string name="kg_emergency_call_label">Emergency call</string>
|
||||
<!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
|
||||
<string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
|
||||
<!-- Message shown when user enters wrong pattern -->
|
||||
<string name="kg_wrong_pattern">Wrong Pattern</string>
|
||||
<!-- Message shown when user enters wrong password -->
|
||||
<string name="kg_wrong_password">Wrong Password</string>
|
||||
<!-- Message shown when user enters wrong PIN -->
|
||||
<string name="kg_wrong_pin">Wrong PIN</string>
|
||||
<string name="kg_too_many_failed_attempts_countdown">Too many attempts</string>
|
||||
<!-- Countdown message shown after too many failed unlock attempts -->
|
||||
<string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
|
||||
<!-- Instructions for using the pattern unlock screen -->
|
||||
<string name="kg_pattern_instructions">Draw your pattern</string>
|
||||
<!-- Instructions for using the SIM PIN unlock screen -->
|
||||
<string name="kg_sim_pin_instructions">Enter SIM PIN</string>
|
||||
<!-- Instructions for using the PIN unlock screen -->
|
||||
<string name="kg_pin_instructions">Enter PIN</string>
|
||||
<!-- Instructions for using the password unlock screen -->
|
||||
<string name="kg_password_instructions">Enter Password</string>
|
||||
<!-- Hint shown in the PUK unlock screen PUK TextView -->
|
||||
<string name="kg_puk_enter_puk_hint">PUK code</string>
|
||||
<!-- Hint shown in the PUK unlock screen PIN TextView -->
|
||||
<string name="kg_puk_enter_pin_hint">New PIN code</string>
|
||||
<!-- Message shown in dialog while the device is unlocking the SIM card -->
|
||||
<string name="kg_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
|
||||
<!-- Message shown when the user enters the wrong PIN code -->
|
||||
<string name="kg_password_wrong_pin_code">Incorrect PIN code.</string>
|
||||
<!-- Message shown when the user enters an invalid SIM pin password in PUK screen -->
|
||||
<string name="kg_invalid_sim_pin_hint">Type a PIN that is 4 to 8 numbers.</string>
|
||||
<!-- Message shown when the user enters an invalid PUK code in the PUK screen -->
|
||||
<string name="kg_invalid_sim_puk_hint">Type a PUK that is 8 numbers or longer.</string>
|
||||
<!-- Instructions for PUK unlock screen -->
|
||||
<string name="kg_sim_puk_recovery_hint">Type PUK and new PIN code</string>
|
||||
<!-- Message shown when the user enters an invalid PUK code -->
|
||||
<string name="kg_invalid_puk">The PUK you typed isn\'t correct.</string>
|
||||
|
||||
<!-- Message shown when the user exceeds the maximum number of pattern attempts -->
|
||||
<string name="kg_login_too_many_attempts">Too many pattern attempts</string>
|
||||
<!-- Instructions show in account unlock screen allowing user to enter their email password -->
|
||||
<string name="kg_login_instructions">To unlock, sign in with your Google account.</string>
|
||||
<!-- Hint shown in TextView in account unlock screen of keyguard -->
|
||||
<string name="kg_login_username_hint">Username (email)</string>
|
||||
<!-- Hint shown in TextView in account unlock screen of keyguard -->
|
||||
<string name="kg_login_password_hint">Password</string>
|
||||
<!-- Label shown on sign in button on account unlock screen of keyguard -->
|
||||
<string name="kg_login_submit_button">Sign in</string>
|
||||
<!-- Message shown when the user enters an invalid username/password combination in account unlock screen of keyguard -->
|
||||
<string name="kg_login_invalid_input">Invalid username or password.</string>
|
||||
<!-- Hint text shown when user has too many failed password attempts in account unlock screen of keyguard -->
|
||||
<string name="kg_login_account_recovery_hint">Forgot your username or password\?\nVisit <b>google.com/accounts/recovery</b>.</string>
|
||||
<!-- Message shown while device checks username/password in account unlock screen of keyguard -->
|
||||
<string name="kg_login_checking_password">Checking\u2026</string>
|
||||
<!-- Message shown in dialog when max number of attempts are reached for PIN screen of keyguard -->
|
||||
<string name="kg_too_many_failed_pin_attempts_dialog_message">
|
||||
You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
|
||||
\n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
|
||||
</string>
|
||||
<!-- Message shown in dialog when max number of attempts are reached for password screen of keyguard -->
|
||||
<string name="kg_too_many_failed_password_attempts_dialog_message">
|
||||
You have incorrectly typed your password <xliff:g id="number">%d</xliff:g> times.
|
||||
\n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
|
||||
</string>
|
||||
<string name="kg_too_many_failed_pattern_attempts_dialog_message">
|
||||
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
|
||||
\n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
|
||||
</string>
|
||||
<!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
|
||||
<string name="kg_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>
|
||||
<!-- Message shown when user is almost at the limit of password attempts where the device will be wiped. -->
|
||||
<string name="kg_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>
|
||||
<!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
|
||||
<string name="kg_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>
|
||||
<!-- Message shown in dialog when user has exceeded the maximum attempts and the device will now be wiped -->
|
||||
<string name="kg_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>
|
||||
<!-- 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 -->
|
||||
<string name="kg_failed_attempts_almost_at_login" product="tablet">
|
||||
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
|
||||
After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
|
||||
you will be asked to unlock your tablet using an email account.\n\n
|
||||
Try again in <xliff:g id="number">%d</xliff:g> seconds.
|
||||
</string>
|
||||
<!-- 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 -->
|
||||
<string name="kg_failed_attempts_almost_at_login" product="default">
|
||||
You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
|
||||
After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
|
||||
you will be asked to unlock your phone using an email account.\n\n
|
||||
Try again in <xliff:g id="number">%d</xliff:g> seconds.
|
||||
</string>
|
||||
|
||||
<string name="kg_temp_back_string"> < </string> <!-- TODO: remove this -->
|
||||
|
||||
</resources>
|
||||
|
@ -16,8 +16,11 @@
|
||||
|
||||
package com.android.internal.policy.impl.keyguard;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.appwidget.AppWidgetHost;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
@ -31,9 +34,10 @@ import android.graphics.Canvas;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.ViewFlipper;
|
||||
@ -74,8 +78,8 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
private ViewFlipper mViewFlipper;
|
||||
private Button mEmergencyDialerButton;
|
||||
private boolean mEnableMenuKey;
|
||||
private boolean mScreenOn;
|
||||
private boolean mIsVerifyUnlockOnly;
|
||||
private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
|
||||
private int mCurrentSecurityId = SECURITY_SELECTOR_ID;
|
||||
|
||||
// KeyguardSecurityViews
|
||||
@ -116,7 +120,7 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
mCallback.keyguardDoneDrawing();
|
||||
mViewMediatorCallback.keyguardDoneDrawing();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -196,29 +200,25 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
}
|
||||
|
||||
public boolean isVerifyUnlockOnly() {
|
||||
// TODO
|
||||
return false;
|
||||
return mIsVerifyUnlockOnly;
|
||||
}
|
||||
|
||||
public void reportSuccessfulUnlockAttempt() {
|
||||
KeyguardUpdateMonitor.getInstance(mContext).clearFailedAttempts();
|
||||
KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts();
|
||||
}
|
||||
|
||||
public void reportFailedUnlockAttempt() {
|
||||
// TODO: handle biometric attempt differently.
|
||||
KeyguardUpdateMonitor.getInstance(mContext).reportFailedAttempt();
|
||||
KeyguardHostView.this.reportFailedUnlockAttempt();
|
||||
}
|
||||
|
||||
public int getFailedAttempts() {
|
||||
return KeyguardUpdateMonitor.getInstance(mContext).getFailedAttempts();
|
||||
return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
|
||||
}
|
||||
|
||||
public void showBackupUnlock() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void keyguardDoneDrawing() {
|
||||
mViewMediatorCallback.keyguardDoneDrawing();
|
||||
@Override
|
||||
public void showBackupSecurity() {
|
||||
KeyguardHostView.this.showBackupSecurity();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -228,6 +228,9 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows the emergency dialer or returns the user to the existing call.
|
||||
*/
|
||||
public void takeEmergencyCallAction() {
|
||||
mCallback.userActivity(EMERGENCY_CALL_TIMEOUT);
|
||||
if (TelephonyManager.getDefault().getCallState()
|
||||
@ -241,19 +244,147 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
}
|
||||
}
|
||||
|
||||
protected void showNextSecurityScreenOrFinish(boolean authenticated) {
|
||||
private void showDialog(String title, String message) {
|
||||
final AlertDialog dialog = new AlertDialog.Builder(mContext)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setNeutralButton(com.android.internal.R.string.ok, null)
|
||||
.create();
|
||||
if (!(mContext instanceof Activity)) {
|
||||
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void showTimeoutDialog() {
|
||||
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
|
||||
int messageId = 0;
|
||||
|
||||
switch (mSecurityModel.getSecurityMode()) {
|
||||
case Pattern:
|
||||
messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
|
||||
break;
|
||||
|
||||
case Password: {
|
||||
final boolean isPin = mLockPatternUtils.getKeyguardStoredPasswordQuality() ==
|
||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
messageId = isPin ? R.string.kg_too_many_failed_pin_attempts_dialog_message
|
||||
: R.string.kg_too_many_failed_password_attempts_dialog_message;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (messageId != 0) {
|
||||
final String message = mContext.getString(messageId,
|
||||
KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
|
||||
timeoutInSeconds);
|
||||
showDialog(null, message);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAlmostAtWipeDialog(int attempts, int remaining) {
|
||||
int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
|
||||
String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
|
||||
attempts, remaining);
|
||||
showDialog(null, message);
|
||||
}
|
||||
|
||||
private void showWipeDialog(int attempts) {
|
||||
String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts);
|
||||
showDialog(null, message);
|
||||
}
|
||||
|
||||
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.kg_failed_attempts_almost_at_login,
|
||||
count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
|
||||
showDialog(null, message);
|
||||
}
|
||||
|
||||
private void reportFailedUnlockAttempt() {
|
||||
final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
|
||||
final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
|
||||
|
||||
if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
|
||||
|
||||
SecurityMode mode = mSecurityModel.getSecurityMode();
|
||||
final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
|
||||
|
||||
final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
|
||||
.getMaximumFailedPasswordsForWipe(null);
|
||||
|
||||
final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
|
||||
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
|
||||
|
||||
final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
|
||||
(failedAttemptsBeforeWipe - failedAttempts)
|
||||
: Integer.MAX_VALUE; // because DPM returns 0 if no restriction
|
||||
|
||||
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 {
|
||||
boolean showTimeout =
|
||||
(failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
|
||||
if (usingPattern && mEnableFallback) {
|
||||
if (failedAttempts == failedAttemptWarning) {
|
||||
showAlmostAtAccountLoginDialog();
|
||||
showTimeout = false; // don't show both dialogs
|
||||
} else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
|
||||
mLockPatternUtils.setPermanentlyLocked(true);
|
||||
showSecurityScreen(SECURITY_ACCOUNT_ID);
|
||||
// don't show timeout dialog because we show account unlock screen next
|
||||
showTimeout = false;
|
||||
}
|
||||
}
|
||||
if (showTimeout) {
|
||||
showTimeoutDialog();
|
||||
}
|
||||
}
|
||||
monitor.reportFailedUnlockAttempt();
|
||||
mLockPatternUtils.reportFailedPasswordAttempt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the backup security screen for the current security mode. This could be used for
|
||||
* password recovery screens but is currently only used for pattern unlock to show the
|
||||
* account unlock screen and biometric unlock to show the user's normal unlock.
|
||||
*/
|
||||
private void showBackupSecurity() {
|
||||
SecurityMode currentMode = mSecurityModel.getSecurityMode();
|
||||
SecurityMode backup = mSecurityModel.getBackupFor(currentMode);
|
||||
showSecurityScreen(getSecurityViewIdForMode(backup));
|
||||
}
|
||||
|
||||
private void showNextSecurityScreenOrFinish(boolean authenticated) {
|
||||
boolean finish = false;
|
||||
if (SECURITY_SELECTOR_ID == mCurrentSecurityId) {
|
||||
int realSecurityId = getSecurityViewIdForMode(mSecurityModel.getSecurityMode());
|
||||
if (realSecurityId == mCurrentSecurityId) {
|
||||
SecurityMode securityMode = mSecurityModel.getSecurityMode();
|
||||
// Allow an alternate, such as biometric unlock
|
||||
// TODO: un-comment when face unlock is working again:
|
||||
// securityMode = mSecurityModel.getAlternateFor(securityMode);
|
||||
int realSecurityId = getSecurityViewIdForMode(securityMode);
|
||||
if (SECURITY_SELECTOR_ID == realSecurityId) {
|
||||
finish = true; // no security required
|
||||
} else {
|
||||
showSecurityScreen(realSecurityId); // switch to the "real" security view
|
||||
}
|
||||
} else if (authenticated) {
|
||||
if ((mCurrentSecurityId == SECURITY_PATTERN_ID
|
||||
if (mCurrentSecurityId == SECURITY_PATTERN_ID
|
||||
|| mCurrentSecurityId == SECURITY_PASSWORD_ID
|
||||
|| mCurrentSecurityId == SECURITY_ACCOUNT_ID)) {
|
||||
|| mCurrentSecurityId == SECURITY_ACCOUNT_ID
|
||||
|| mCurrentSecurityId == SECURITY_BIOMETRIC_ID) {
|
||||
finish = true;
|
||||
}
|
||||
} else {
|
||||
@ -309,6 +440,7 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
mIsVerifyUnlockOnly = false;
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
@ -330,6 +462,12 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches to the given security view unless it's already being shown, in which case
|
||||
* this is a no-op.
|
||||
*
|
||||
* @param securityViewId
|
||||
*/
|
||||
private void showSecurityScreen(int securityViewId) {
|
||||
|
||||
if (securityViewId == mCurrentSecurityId) return;
|
||||
@ -352,19 +490,22 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Discard current runnable if we're switching back to the selector view
|
||||
if (securityViewId == SECURITY_SELECTOR_ID) {
|
||||
setOnDismissRunnable(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScreenTurnedOn() {
|
||||
if (DEBUG) Log.d(TAG, "screen on");
|
||||
mScreenOn = true;
|
||||
showSecurityScreen(mCurrentSecurityId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScreenTurnedOff() {
|
||||
if (DEBUG) Log.d(TAG, "screen off");
|
||||
mScreenOn = false;
|
||||
showSecurityScreen(SECURITY_SELECTOR_ID);
|
||||
}
|
||||
|
||||
@ -469,7 +610,8 @@ public class KeyguardHostView extends KeyguardViewBase {
|
||||
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
|
||||
private boolean shouldEnableMenuKey() {
|
||||
final Resources res = getResources();
|
||||
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
|
||||
final boolean configDisabled = res.getBoolean(
|
||||
com.android.internal.R.bool.config_disableMenuKeyInLockScreen);
|
||||
final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
|
||||
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
|
||||
return !configDisabled || isTestHarness || fileOverride;
|
||||
|
@ -25,12 +25,15 @@ public class KeyguardNavigationManager {
|
||||
|
||||
private TextView mMessageArea;
|
||||
private KeyguardSecurityView mKeyguardSecurityView;
|
||||
private View mClickArea;
|
||||
|
||||
public KeyguardNavigationManager(KeyguardSecurityView view) {
|
||||
mKeyguardSecurityView = view;
|
||||
mMessageArea = (TextView) ((View) view).findViewById(R.id.message_area);
|
||||
mMessageArea = (TextView) ((View) view).findViewById(R.id.keyguard_message_area);
|
||||
mMessageArea.setSelected(true); // Make marquee work
|
||||
mMessageArea.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
mClickArea = ((View) view).findViewById(R.id.keyguard_click_area);
|
||||
mClickArea.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mKeyguardSecurityView.getCallback().dismiss(false);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
|
||||
mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text);
|
||||
mForgotPatternButton.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mCallback.showBackupUnlock();
|
||||
mCallback.showBackupSecurity();
|
||||
}
|
||||
});
|
||||
|
||||
@ -233,6 +233,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
|
||||
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
|
||||
mCallback.dismiss(true); // keyguardDone(true)
|
||||
KeyStore.getInstance().password(LockPatternUtils.patternToString(pattern));
|
||||
mTotalFailedPatternAttempts = 0;
|
||||
} else {
|
||||
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
|
||||
mCallback.userActivity(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
|
||||
@ -313,13 +314,15 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
|
||||
mLockPatternView.clearPattern();
|
||||
mLockPatternView.setEnabled(false);
|
||||
final long elapsedRealtime = SystemClock.elapsedRealtime();
|
||||
updateFooter(FooterMode.ForgotLockPattern);
|
||||
|
||||
mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
|
||||
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
final int secondsRemaining = (int) (millisUntilFinished / 1000);
|
||||
mNavigationManager.setMessage(
|
||||
R.string.kg_too_many_failed_attempts_countdown,secondsRemaining);
|
||||
R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,17 +53,12 @@ public interface KeyguardSecurityCallback {
|
||||
int getFailedAttempts();
|
||||
|
||||
/**
|
||||
* Shows the backup unlock for the current method. If none available, this call is a NOP.
|
||||
* Shows the backup security for the current method. If none available, this call is a no-op.
|
||||
*/
|
||||
void showBackupUnlock();
|
||||
void showBackupSecurity();
|
||||
|
||||
/**
|
||||
* Used to inform keyguard when the current view is done drawing.
|
||||
*/
|
||||
void keyguardDoneDrawing();
|
||||
|
||||
/**
|
||||
* Sets a runnable to launch after the user enters their
|
||||
* Sets a runnable to launch after the user successfully enters their credentials.
|
||||
* @param runnable
|
||||
*/
|
||||
void setOnDismissRunnable(Runnable runnable);
|
||||
|
@ -48,38 +48,85 @@ public class KeyguardSecurityModel {
|
||||
mLockPatternUtils = utils;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns false if there is any condition that indicates that the biometric unlock should
|
||||
* not be used before the next time the unlock screen is recreated. In other words, if this
|
||||
* returns false there is no need to even construct the biometric unlock.
|
||||
*/
|
||||
private boolean isBiometricUnlockEnabled() {
|
||||
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
|
||||
final boolean backupIsTimedOut =
|
||||
monitor.getFailedUnlockAttempts() >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
|
||||
return mLockPatternUtils.usingBiometricWeak()
|
||||
&& mLockPatternUtils.isBiometricWeakInstalled()
|
||||
&& !monitor.getMaxBiometricUnlockAttemptsReached()
|
||||
&& !backupIsTimedOut;
|
||||
}
|
||||
|
||||
SecurityMode getSecurityMode() {
|
||||
KeyguardUpdateMonitor mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
|
||||
final IccCardConstants.State simState = mUpdateMonitor.getSimState();
|
||||
SecurityMode mode = SecurityMode.None;
|
||||
if (simState == IccCardConstants.State.PIN_REQUIRED) {
|
||||
return SecurityMode.SimPin;
|
||||
mode = SecurityMode.SimPin;
|
||||
} else if (simState == IccCardConstants.State.PUK_REQUIRED) {
|
||||
return SecurityMode.SimPuk;
|
||||
mode = SecurityMode.SimPuk;
|
||||
} else {
|
||||
final int mode = mLockPatternUtils.getKeyguardStoredPasswordQuality();
|
||||
switch (mode) {
|
||||
final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
|
||||
switch (security) {
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
|
||||
return mLockPatternUtils.isLockPasswordEnabled() ?
|
||||
mode = mLockPatternUtils.isLockPasswordEnabled() ?
|
||||
SecurityMode.Password : SecurityMode.None;
|
||||
break;
|
||||
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
|
||||
if (mLockPatternUtils.isLockPatternEnabled()) {
|
||||
return mLockPatternUtils.isPermanentlyLocked() ?
|
||||
mode = mLockPatternUtils.isPermanentlyLocked() ?
|
||||
SecurityMode.Account : SecurityMode.Pattern;
|
||||
} else {
|
||||
return SecurityMode.None;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unknown unlock mode:" + mode);
|
||||
throw new IllegalStateException("Unknown unlock mode:" + mode);
|
||||
}
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some unlock methods can have an alternate, such as biometric unlocks (e.g. face unlock).
|
||||
* This function decides if an alternate unlock is available and returns it. Otherwise,
|
||||
* returns @param mode.
|
||||
*
|
||||
* @param mode the mode we want the alternate for
|
||||
* @return alternate or the given mode
|
||||
*/
|
||||
SecurityMode getAlternateFor(SecurityMode mode) {
|
||||
if (isBiometricUnlockEnabled()
|
||||
&& (mode == SecurityMode.Password || mode == SecurityMode.Pattern)) {
|
||||
return SecurityMode.Biometric;
|
||||
}
|
||||
return mode; // no alternate, return what was given
|
||||
}
|
||||
|
||||
/**
|
||||
* Some unlock methods can have a backup which gives the user another way to get into
|
||||
* the device. This is currently only supported for Biometric and Pattern unlock.
|
||||
*
|
||||
* @param mode the mode we want the backup for
|
||||
* @return backup method or given mode
|
||||
*/
|
||||
SecurityMode getBackupFor(SecurityMode mode) {
|
||||
return SecurityMode.None; // TODO: handle biometric unlock, etc.
|
||||
switch(mode) {
|
||||
case Biometric:
|
||||
return getSecurityMode();
|
||||
case Pattern:
|
||||
return SecurityMode.Account;
|
||||
}
|
||||
return mode; // no backup, return what was given
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ import java.util.ArrayList;
|
||||
*
|
||||
* Note: under time crunch, this has been extended to include some stuff that
|
||||
* doesn't really belong here. see {@link #handleBatteryUpdate} where it shutdowns
|
||||
* the device, and {@link #getFailedAttempts()}, {@link #reportFailedAttempt()}
|
||||
* and {@link #clearFailedAttempts()}. Maybe we should rename this 'KeyguardContext'...
|
||||
* the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
|
||||
* and {@link #clearFailedUnlockAttempts()}. Maybe we should rename this 'KeyguardContext'...
|
||||
*/
|
||||
public class KeyguardUpdateMonitor {
|
||||
|
||||
@ -658,16 +658,16 @@ public class KeyguardUpdateMonitor {
|
||||
return mDeviceProvisioned;
|
||||
}
|
||||
|
||||
public int getFailedAttempts() {
|
||||
public int getFailedUnlockAttempts() {
|
||||
return mFailedAttempts;
|
||||
}
|
||||
|
||||
public void clearFailedAttempts() {
|
||||
public void clearFailedUnlockAttempts() {
|
||||
mFailedAttempts = 0;
|
||||
mFailedBiometricUnlockAttempts = 0;
|
||||
}
|
||||
|
||||
public void reportFailedAttempt() {
|
||||
public void reportFailedUnlockAttempt() {
|
||||
mFailedAttempts++;
|
||||
}
|
||||
|
||||
|
@ -986,7 +986,7 @@ public class KeyguardViewMediator {
|
||||
mHandler.sendMessage(msg);
|
||||
|
||||
if (authenticated) {
|
||||
mUpdateMonitor.clearFailedAttempts();
|
||||
mUpdateMonitor.clearFailedUnlockAttempts();
|
||||
}
|
||||
|
||||
if (mExitSecureCallback != null) {
|
||||
|
@ -53,12 +53,9 @@ public class KeyguardWidgetFrame extends FrameLayout {
|
||||
super(context, attrs, defStyle);
|
||||
if (sLeftOverscrollDrawable == null) {
|
||||
Resources res = context.getResources();
|
||||
sLeftOverscrollDrawable = res.getDrawable(
|
||||
com.android.internal.R.drawable.kg_widget_overscroll_layer_left);
|
||||
sRightOverscrollDrawable = res.getDrawable(
|
||||
com.android.internal.R.drawable.kg_widget_overscroll_layer_right);
|
||||
sWidgetPagePadding =
|
||||
res.getDimensionPixelSize(com.android.internal.R.dimen.kg_widget_page_padding);
|
||||
sLeftOverscrollDrawable = res.getDrawable(R.drawable.kg_widget_overscroll_layer_left);
|
||||
sRightOverscrollDrawable = res.getDrawable(R.drawable.kg_widget_overscroll_layer_right);
|
||||
sWidgetPagePadding = res.getDimensionPixelSize(R.dimen.kg_widget_page_padding);
|
||||
}
|
||||
setPadding(sWidgetPagePadding, sWidgetPagePadding, sWidgetPagePadding, sWidgetPagePadding);
|
||||
}
|
||||
|
Reference in New Issue
Block a user