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:
Jim Miller
2012-08-31 13:57:26 -07:00
committed by Android (Google) Code Review
16 changed files with 356 additions and 82 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -17,5 +17,5 @@
*/
-->
<resources>
<integer name="flip_duration">300</integer>
<integer name="kg_security_flip_duration">150</integer>
</resources>

View File

@ -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" />

View File

@ -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"> &lt; </string> <!-- TODO: remove this -->
</resources>

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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
}
}

View File

@ -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++;
}

View File

@ -986,7 +986,7 @@ public class KeyguardViewMediator {
mHandler.sendMessage(msg);
if (authenticated) {
mUpdateMonitor.clearFailedAttempts();
mUpdateMonitor.clearFailedUnlockAttempts();
}
if (mExitSecureCallback != null) {

View File

@ -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);
}