diff options
9 files changed, 630 insertions, 577 deletions
diff --git a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java index 689366b..de839c6 100644 --- a/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java +++ b/packages/Keyguard/src/com/android/keyguard/FaceUnlock.java @@ -304,7 +304,7 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { int currentUserId = mLockPatternUtils.getCurrentUser(); if (authenticatedUserId == currentUserId) { if (DEBUG) Log.d(TAG, "Unlocking for user " + authenticatedUserId); - mKeyguardScreenCallback.reportSuccessfulUnlockAttempt(); + mKeyguardScreenCallback.reportUnlockAttempt(true); mKeyguardScreenCallback.dismiss(true); } else { Log.d(TAG, "Ignoring unlock for authenticated user (" + authenticatedUserId + @@ -335,7 +335,7 @@ public class FaceUnlock implements BiometricSensorUnlock, Handler.Callback { // next time the user visits keyguard. KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(false); - mKeyguardScreenCallback.reportFailedUnlockAttempt(); + mKeyguardScreenCallback.reportUnlockAttempt(false); } /** diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 461fd77..3950159 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -154,14 +154,14 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout protected void verifyPasswordAndUnlock() { String entry = mPasswordEntry.getText().toString(); if (mLockPatternUtils.checkPassword(entry)) { - mCallback.reportSuccessfulUnlockAttempt(); + mCallback.reportUnlockAttempt(true); mCallback.dismiss(true); } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. - mCallback.reportFailedUnlockAttempt(); - if (0 == (mCallback.getFailedAttempts() - % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + mCallback.reportUnlockAttempt(false); + int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); + if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); handleAttemptLockout(deadline); } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java index 6b8be69..f69fa5f 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAccountView.java @@ -177,14 +177,14 @@ public class KeyguardAccountView extends LinearLayout implements KeyguardSecurit intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(intent, new UserHandle(mLockPatternUtils.getCurrentUser())); - mCallback.reportSuccessfulUnlockAttempt(); + mCallback.reportUnlockAttempt(true); // dismiss keyguard mCallback.dismiss(true); } else { mSecurityMessageDisplay.setMessage(R.string.kg_login_invalid_input, true); mPassword.setText(""); - mCallback.reportFailedUnlockAttempt(); + mCallback.reportUnlockAttempt(false); } } }); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java index 0a915ea..368a97a 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardActivityLauncher.java @@ -53,10 +53,12 @@ public abstract class KeyguardActivityLauncher { abstract Context getContext(); - abstract KeyguardSecurityCallback getCallback(); - abstract LockPatternUtils getLockPatternUtils(); + abstract void setOnDismissAction(OnDismissAction action); + + abstract void requestDismissKeyguard(); + public static class CameraWidgetInfo { public String contextPackage; public int layoutId; @@ -190,8 +192,7 @@ public abstract class KeyguardActivityLauncher { } else { // Create a runnable to start the activity and ask the user to enter their // credentials. - KeyguardSecurityCallback callback = getCallback(); - callback.setOnDismissAction(new OnDismissAction() { + setOnDismissAction(new OnDismissAction() { @Override public boolean onDismiss() { dismissKeyguardOnNextActivity(); @@ -199,7 +200,7 @@ public abstract class KeyguardActivityLauncher { return true; } }); - callback.dismiss(false); + requestDismissKeyguard(); } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index dfcd8a8..1548dee 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -18,6 +18,7 @@ package com.android.keyguard; import android.nfc.NfcUnlock; import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.KeyguardUpdateMonitor.DisplayClientState; @@ -84,20 +85,12 @@ public class KeyguardHostView extends KeyguardViewBase { private AppWidgetHost mAppWidgetHost; private AppWidgetManager mAppWidgetManager; private KeyguardWidgetPager mAppWidgetContainer; - private KeyguardSecurityViewFlipper mSecurityViewContainer; - private KeyguardSelectorView mKeyguardSelectorView; private KeyguardTransportControlView mTransportControl; - private boolean mIsVerifyUnlockOnly; - private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView - private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; private int mAppWidgetToShow; - protected OnDismissAction mDismissAction; - protected int mFailedAttempts; private LockPatternUtils mLockPatternUtils; - private KeyguardSecurityModel mSecurityModel; private KeyguardViewStateManager mViewStateManager; private Rect mTempRect = new Rect(); @@ -126,6 +119,8 @@ public class KeyguardHostView extends KeyguardViewBase { private Runnable mPostBootCompletedRunnable; + private OnDismissAction mDismissAction; + /*package*/ interface UserSwitcherCallback { void hideSecurityView(int duration); void showSecurityView(); @@ -186,8 +181,6 @@ public class KeyguardHostView extends KeyguardViewBase { mAppWidgetManager = AppWidgetManager.getInstance(userContext); - mSecurityModel = new KeyguardSecurityModel(context); - mViewStateManager = new KeyguardViewStateManager(this); mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(), @@ -207,13 +200,6 @@ public class KeyguardHostView extends KeyguardViewBase { } } - public void announceCurrentSecurityMethod() { - View v = (View) getSecurityView(mCurrentSecuritySelection); - if (v != null) { - v.announceForAccessibility(v.getContentDescription()); - } - } - private void getInitialTransportState() { DisplayClientState dcs = KeyguardUpdateMonitor.getInstance(mContext) .getCachedDisplayClientState(); @@ -300,9 +286,10 @@ public class KeyguardHostView extends KeyguardViewBase { } @Override public void onNfcUnlock() { - if (NfcUnlock.getPropertyEnabled()) mCallback.dismiss(true); + if (NfcUnlock.getPropertyEnabled()) { + dismiss(true); + } } - }; private static final boolean isMusicPlaying(int playbackState) { @@ -322,14 +309,15 @@ public class KeyguardHostView extends KeyguardViewBase { private SlidingChallengeLayout mSlidingChallengeLayout; private MultiPaneChallengeLayout mMultiPaneChallengeLayout; + private KeyguardSecurityContainer mSecurityContainer; @Override public boolean onTouchEvent(MotionEvent ev) { boolean result = super.onTouchEvent(ev); mTempRect.set(0, 0, 0, 0); - offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect); + offsetRectIntoDescendantCoords(mSecurityContainer, mTempRect); ev.offsetLocation(mTempRect.left, mTempRect.top); - result = mSecurityViewContainer.dispatchTouchEvent(ev) || result; + result = mSecurityContainer.dispatchTouchEvent(ev) || result; ev.offsetLocation(-mTempRect.left, -mTempRect.top); return result; } @@ -383,9 +371,48 @@ public class KeyguardHostView extends KeyguardViewBase { mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration()); mViewStateManager.setPagedView(mAppWidgetContainer); mViewStateManager.setChallengeLayout(challenge); - mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper); - mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view); - mViewStateManager.setSecurityViewContainer(mSecurityViewContainer); + + mSecurityContainer = + (KeyguardSecurityContainer) findViewById(R.id.keyguard_security_container); + mSecurityContainer.setLockPatternUtils(mLockPatternUtils); + mSecurityContainer.setSecurityCallback(new SecurityCallback() { + @Override + public void userActivity(long timeout) { + if (mViewMediatorCallback != null) { + mViewMediatorCallback.userActivity(timeout); + } + } + + @Override + public void dismiss(boolean authenticated) { + KeyguardHostView.this.dismiss(authenticated); + } + + @Override + public void finish() { + + // If the alternate unlock was suppressed, it can now be safely + // enabled because the user has left keyguard. + KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); + + // If there's a pending runnable because the user interacted with a widget + // and we're leaving keyguard, then run it. + boolean deferKeyguardDone = false; + if (mDismissAction != null) { + deferKeyguardDone = mDismissAction.onDismiss(); + mDismissAction = null; + } + if (mViewMediatorCallback != null) { + if (deferKeyguardDone) { + mViewMediatorCallback.keyguardDonePending(); + } else { + mViewMediatorCallback.keyguardDone(true); + } + } + } + }); + + mViewStateManager.setSecurityViewContainer(mSecurityContainer); setBackButtonEnabled(false); @@ -402,8 +429,8 @@ public class KeyguardHostView extends KeyguardViewBase { }; } - showPrimarySecurityScreen(false); - updateSecurityViews(); + mSecurityContainer.showPrimarySecurityScreen(false); + mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing()); enableUserSelectorIfNecessary(); } @@ -465,32 +492,10 @@ public class KeyguardHostView extends KeyguardViewBase { || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0; } - private void updateSecurityViews() { - int children = mSecurityViewContainer.getChildCount(); - for (int i = 0; i < children; i++) { - updateSecurityView(mSecurityViewContainer.getChildAt(i)); - } - } - - private void updateSecurityView(View view) { - if (view instanceof KeyguardSecurityView) { - KeyguardSecurityView ksv = (KeyguardSecurityView) view; - ksv.setKeyguardCallback(mCallback); - ksv.setLockPatternUtils(mLockPatternUtils); - if (mViewStateManager.isBouncing()) { - ksv.showBouncer(0); - } else { - ksv.hideBouncer(0); - } - } else { - Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); - } - } - void setLockPatternUtils(LockPatternUtils utils) { - mSecurityModel.setLockPatternUtils(utils); mLockPatternUtils = utils; - updateSecurityViews(); + mSecurityContainer.setLockPatternUtils(utils); + mSecurityContainer.updateSecurityViews(mViewStateManager.isBouncing()); } @Override @@ -577,265 +582,7 @@ public class KeyguardHostView extends KeyguardViewBase { return -1; } - private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { - - public void userActivity(long timeout) { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.userActivity(timeout); - } - } - - public void dismiss(boolean authenticated) { - showNextSecurityScreenOrFinish(authenticated); - } - - public boolean isVerifyUnlockOnly() { - return mIsVerifyUnlockOnly; - } - - public void reportSuccessfulUnlockAttempt() { - KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts(); - mLockPatternUtils.reportSuccessfulPasswordAttempt(); - } - - public void reportFailedUnlockAttempt() { - if (mCurrentSecuritySelection == SecurityMode.Biometric) { - KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt(); - } else { - KeyguardHostView.this.reportFailedUnlockAttempt(); - } - } - - public int getFailedAttempts() { - return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(); - } - - @Override - public void showBackupSecurity() { - KeyguardHostView.this.showBackupSecurityScreen(); - } - @Override - public void setOnDismissAction(OnDismissAction action) { - KeyguardHostView.this.setOnDismissAction(action); - } - - }; - - private void showDialog(String title, String message) { - final AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(title) - .setMessage(message) - .setNeutralButton(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 PIN: - messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; - break; - case Password: - messageId = 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) { - 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, mLockPatternUtils.getCurrentUser()); - - 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 - - boolean showTimeout = false; - 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 { - 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(SecurityMode.Account); - // don't show timeout dialog because we show account unlock screen next - showTimeout = false; - } - } - } - monitor.reportFailedUnlockAttempt(); - mLockPatternUtils.reportFailedPasswordAttempt(); - if (showTimeout) { - showTimeoutDialog(); - } - } - - /** - * Shows the primary security screen for the user. This will be either the multi-selector - * or the user's security method. - * @param turningOff true if the device is being turned off - */ - void showPrimarySecurityScreen(boolean turningOff) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); - if (!turningOff && - KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) { - // If we're not turning off, then allow biometric alternate. - // We'll reload it when the device comes back on. - securityMode = mSecurityModel.getAlternateFor(securityMode); - } - showSecurityScreen(securityMode); - } - - /** - * 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 showBackupSecurityScreen() { - if (DEBUG) Log.d(TAG, "showBackupSecurity()"); - SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); - showSecurityScreen(backup); - } - - public boolean showNextSecurityScreenIfPresent() { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - // Allow an alternate, such as biometric unlock - securityMode = mSecurityModel.getAlternateFor(securityMode); - if (SecurityMode.None == securityMode) { - return false; - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - return true; - } - } - - private void showNextSecurityScreenOrFinish(boolean authenticated) { - if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); - boolean finish = false; - if (SecurityMode.None == mCurrentSecuritySelection) { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - // Allow an alternate, such as biometric unlock - securityMode = mSecurityModel.getAlternateFor(securityMode); - if (SecurityMode.None == securityMode) { - finish = true; // no security required - } else { - showSecurityScreen(securityMode); // switch to the alternate security view - } - } else if (authenticated) { - switch (mCurrentSecuritySelection) { - case Pattern: - case Password: - case PIN: - case Account: - case Biometric: - finish = true; - break; - - case SimPin: - case SimPuk: - // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home - SecurityMode securityMode = mSecurityModel.getSecurityMode(); - if (securityMode != SecurityMode.None) { - showSecurityScreen(securityMode); - } else { - finish = true; - } - break; - - default: - Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); - showPrimarySecurityScreen(false); - break; - } - } else { - showPrimarySecurityScreen(false); - } - if (finish) { - // If the alternate unlock was suppressed, it can now be safely - // enabled because the user has left keyguard. - KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true); - - // If there's a pending runnable because the user interacted with a widget - // and we're leaving keyguard, then run it. - boolean deferKeyguardDone = false; - if (mDismissAction != null) { - deferKeyguardDone = mDismissAction.onDismiss(); - mDismissAction = null; - } - if (mViewMediatorCallback != null) { - if (deferKeyguardDone) { - mViewMediatorCallback.keyguardDonePending(); - } else { - mViewMediatorCallback.keyguardDone(true); - } - } - } else { - mViewStateManager.showBouncer(true); - } - } private static class MyOnClickHandler extends OnClickHandler { @@ -843,17 +590,17 @@ public class KeyguardHostView extends KeyguardViewBase { // due to Binder GC linkages to AppWidgetHost. By the same token, // this click handler should not keep references to any large // objects. - WeakReference<KeyguardHostView> mThis; + WeakReference<KeyguardHostView> mKeyguardHostView; MyOnClickHandler(KeyguardHostView hostView) { - mThis = new WeakReference<KeyguardHostView>(hostView); + mKeyguardHostView = new WeakReference<KeyguardHostView>(hostView); } @Override public boolean onClickHandler(final View view, final android.app.PendingIntent pendingIntent, final Intent fillInIntent) { - KeyguardHostView hostView = mThis.get(); + KeyguardHostView hostView = mKeyguardHostView.get(); if (hostView == null) { return false; } @@ -883,7 +630,7 @@ public class KeyguardHostView extends KeyguardViewBase { if (hostView.mViewStateManager.isChallengeShowing()) { hostView.mViewStateManager.showBouncer(true); } else { - hostView.mCallback.dismiss(false); + hostView.dismiss(); } return true; } else { @@ -892,153 +639,11 @@ public class KeyguardHostView extends KeyguardViewBase { }; }; - // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). - // This avoids unwanted asynchronous events from messing with the state. - private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { - - @Override - public void userActivity(long timeout) { - } - - @Override - public void showBackupSecurity() { - } - - @Override - public void setOnDismissAction(OnDismissAction action) { - } - - @Override - public void reportSuccessfulUnlockAttempt() { - } - - @Override - public void reportFailedUnlockAttempt() { - } - - @Override - public boolean isVerifyUnlockOnly() { - return false; - } - - @Override - public int getFailedAttempts() { - return 0; - } - - @Override - public void dismiss(boolean securityVerified) { - } - }; - - /** - * Sets an action to perform when keyguard is dismissed. - * @param action - */ - protected void setOnDismissAction(OnDismissAction action) { - mDismissAction = action; - } - - private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - KeyguardSecurityView view = null; - final int children = mSecurityViewContainer.getChildCount(); - for (int child = 0; child < children; child++) { - if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) { - view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child)); - break; - } - } - int layoutId = getLayoutIdFor(securityMode); - if (view == null && layoutId != 0) { - final LayoutInflater inflater = LayoutInflater.from(mContext); - if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); - View v = inflater.inflate(layoutId, mSecurityViewContainer, false); - mSecurityViewContainer.addView(v); - updateSecurityView(v); - view = (KeyguardSecurityView)v; - } - - if (view instanceof KeyguardSelectorView) { - KeyguardSelectorView selectorView = (KeyguardSelectorView) view; - View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); - selectorView.setCarrierArea(carrierText); - } - - return view; - } - - /** - * Switches to the given security view unless it's already being shown, in which case - * this is a no-op. - * - * @param securityMode - */ - private void showSecurityScreen(SecurityMode securityMode) { - if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); - - if (securityMode == mCurrentSecuritySelection) return; - - KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); - KeyguardSecurityView newView = getSecurityView(securityMode); - - // Enter full screen mode if we're in SIM or Account screen - boolean fullScreenEnabled = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen); - boolean isSimOrAccount = securityMode == SecurityMode.SimPin - || securityMode == SecurityMode.SimPuk - || securityMode == SecurityMode.Account; - mAppWidgetContainer.setVisibility( - isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE); - - // Don't show camera or search in navbar when SIM or Account screen is showing - setSystemUiVisibility(isSimOrAccount ? - (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH) - : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH)); - - if (mSlidingChallengeLayout != null) { - mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled); - } - - // Emulate Activity life cycle - if (oldView != null) { - oldView.onPause(); - oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view - } - newView.onResume(KeyguardSecurityView.VIEW_REVEALED); - newView.setKeyguardCallback(mCallback); - - final boolean needsInput = newView.needsInput(); - if (mViewMediatorCallback != null) { - mViewMediatorCallback.setNeedsInput(needsInput); - } - - // Find and show this child. - final int childCount = mSecurityViewContainer.getChildCount(); - - final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); - for (int i = 0; i < childCount; i++) { - if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) { - mSecurityViewContainer.setDisplayedChild(i); - break; - } - } - - if (securityMode == SecurityMode.None) { - // Discard current runnable if we're switching back to the selector view - setOnDismissAction(null); - } - if (securityMode == SecurityMode.Account && !mLockPatternUtils.isPermanentlyLocked()) { - // we're showing account as a backup, provide a way to get back to primary - setBackButtonEnabled(true); - } - mCurrentSecuritySelection = securityMode; - } - @Override public void onScreenTurnedOn() { if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode())); - showPrimarySecurityScreen(false); - getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON); + mSecurityContainer.showPrimarySecurityScreen(false); + mSecurityContainer.onResume(KeyguardSecurityView.SCREEN_ON); // This is a an attempt to fix bug 7137389 where the device comes back on but the entire // layout is blank but forcing a layout causes it to reappear (e.g. with with @@ -1065,8 +670,8 @@ public class KeyguardHostView extends KeyguardViewBase { if (KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) { checkAppWidgetConsistency(); } - showPrimarySecurityScreen(true); - getSecurityView(mCurrentSecuritySelection).onPause(); + mSecurityContainer.showPrimarySecurityScreen(true); + mSecurityContainer.onPause(); CameraWidgetFrame cameraPage = findCameraPage(); if (cameraPage != null) { cameraPage.onScreenTurnedOff(); @@ -1082,12 +687,12 @@ public class KeyguardHostView extends KeyguardViewBase { @Override public void show() { if (DEBUG) Log.d(TAG, "show()"); - showPrimarySecurityScreen(false); + mSecurityContainer.showPrimarySecurityScreen(false); } @Override public void verifyUnlock() { - SecurityMode securityMode = mSecurityModel.getSecurityMode(); + SecurityMode securityMode = mSecurityContainer.getSecurityMode(); if (securityMode == KeyguardSecurityModel.SecurityMode.None) { if (mViewMediatorCallback != null) { mViewMediatorCallback.keyguardDone(true); @@ -1101,37 +706,7 @@ public class KeyguardHostView extends KeyguardViewBase { } } else { // otherwise, go to the unlock screen, see if they can verify it - mIsVerifyUnlockOnly = true; - showSecurityScreen(securityMode); - } - } - - private int getSecurityViewIdForMode(SecurityMode securityMode) { - switch (securityMode) { - case None: return R.id.keyguard_selector_view; - case Pattern: return R.id.keyguard_pattern_view; - case PIN: return R.id.keyguard_pin_view; - case Password: return R.id.keyguard_password_view; - case Biometric: return R.id.keyguard_face_unlock_view; - case Account: return R.id.keyguard_account_view; - case SimPin: return R.id.keyguard_sim_pin_view; - case SimPuk: return R.id.keyguard_sim_puk_view; - } - return 0; - } - - private int getLayoutIdFor(SecurityMode securityMode) { - switch (securityMode) { - case None: return R.layout.keyguard_selector_view; - case Pattern: return R.layout.keyguard_pattern_view; - case PIN: return R.layout.keyguard_pin_view; - case Password: return R.layout.keyguard_password_view; - case Biometric: return R.layout.keyguard_face_unlock_view; - case Account: return R.layout.keyguard_account_view; - case SimPin: return R.layout.keyguard_sim_pin_view; - case SimPuk: return R.layout.keyguard_sim_puk_view; - default: - return 0; + mSecurityContainer.verifyUnlock(); } } @@ -1189,14 +764,19 @@ public class KeyguardHostView extends KeyguardViewBase { } @Override - KeyguardSecurityCallback getCallback() { - return mCallback; + void setOnDismissAction(OnDismissAction action) { + mDismissAction = action; } @Override LockPatternUtils getLockPatternUtils() { return mLockPatternUtils; } + + @Override + void requestDismissKeyguard() { + KeyguardHostView.this.dismiss(false); + } }; private int numWidgets() { @@ -1618,18 +1198,18 @@ public class KeyguardHostView extends KeyguardViewBase { UserSwitcherCallback callback = new UserSwitcherCallback() { @Override public void hideSecurityView(int duration) { - mSecurityViewContainer.animate().alpha(0).setDuration(duration); + mSecurityContainer.animate().alpha(0).setDuration(duration); } @Override public void showSecurityView() { - mSecurityViewContainer.setAlpha(1.0f); + mSecurityContainer.setAlpha(1.0f); } @Override public void showUnlockHint() { - if (mKeyguardSelectorView != null) { - mKeyguardSelectorView.showUsabilityHint(); + if (mSecurityContainer != null) { + mSecurityContainer.showUsabilityHint(); } } @@ -1688,21 +1268,21 @@ public class KeyguardHostView extends KeyguardViewBase { public boolean handleMenuKey() { // The following enables the MENU key to work for testing automation if (shouldEnableMenuKey()) { - showNextSecurityScreenOrFinish(false); + dismiss(); return true; } return false; } public boolean handleBackKey() { - if (mCurrentSecuritySelection == SecurityMode.Account) { + if (mSecurityContainer.getCurrentSecuritySelection() == SecurityMode.Account) { // go back to primary screen and re-disable back setBackButtonEnabled(false); - showPrimarySecurityScreen(false /*turningOff*/); + mSecurityContainer.showPrimarySecurityScreen(false /*turningOff*/); return true; } - if (mCurrentSecuritySelection != SecurityMode.None) { - mCallback.dismiss(false); + if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) { + mSecurityContainer.dismiss(false); return true; } return false; @@ -1712,7 +1292,54 @@ public class KeyguardHostView extends KeyguardViewBase { * Dismisses the keyguard by going to the next screen or making it gone. */ public void dismiss() { - showNextSecurityScreenOrFinish(false); + dismiss(false); + } + + private void dismiss(boolean authenticated) { + boolean finished = mSecurityContainer.showNextSecurityScreenOrFinish(authenticated); + if (!finished) { + updateAfterSecuritySelection(); + mViewStateManager.showBouncer(true); + } + } + + void setOnDismissAction(OnDismissAction action) { + mDismissAction = action; + } + + public void announceCurrentSecurityMethod() { + mSecurityContainer.announceCurrentSecurityMethod(); + } + + private void updateAfterSecuritySelection() { + // Enable or disable the back button based on security mode + if (mSecurityContainer.getSecurityMode() == SecurityMode.Account + && !mLockPatternUtils.isPermanentlyLocked()) { + // we're showing account as a backup, provide a way to get back to primary + setBackButtonEnabled(true); + } + + // Enter full screen mode if we're in SIM or Account screen + SecurityMode securityMode = mSecurityContainer.getSecurityMode(); + boolean isFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen); + boolean isSimOrAccount = securityMode == SecurityMode.SimPin + || securityMode == SecurityMode.SimPuk + || securityMode == SecurityMode.Account; + mAppWidgetContainer.setVisibility( + isSimOrAccount && isFullScreen ? View.GONE : View.VISIBLE); + + // Don't show camera or search in navbar when SIM or Account screen is showing + setSystemUiVisibility(isSimOrAccount ? + (getSystemUiVisibility() | View.STATUS_BAR_DISABLE_SEARCH) + : (getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_SEARCH)); + + if (mSlidingChallengeLayout != null) { + mSlidingChallengeLayout.setChallengeInteractive(!isFullScreen); + } + + if (mViewMediatorCallback != null) { + mViewMediatorCallback.setNeedsInput(mSecurityContainer.needsInput()); + } } public void showAssistant() { @@ -1726,9 +1353,7 @@ public class KeyguardHostView extends KeyguardViewBase { getHandler(), null); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - mActivityLauncher.launchActivityWithAnimation( - intent, false, opts.toBundle(), null, null); + mActivityLauncher.launchActivityWithAnimation(intent, false, opts.toBundle(), null, null); } public void dispatch(MotionEvent event) { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java index e7f1259..0fa27c1 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java @@ -260,7 +260,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit public void onPatternDetected(List<LockPatternView.Cell> pattern) { if (mLockPatternUtils.checkPattern(pattern)) { - mCallback.reportSuccessfulUnlockAttempt(); + mCallback.reportUnlockAttempt(true); mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); mTotalFailedPatternAttempts = 0; mCallback.dismiss(true); @@ -272,7 +272,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; mFailedPatternAttemptsSinceLastTimeout++; - mCallback.reportFailedUnlockAttempt(); + mCallback.reportUnlockAttempt(false); } if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java index 4f139ad..957098c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java @@ -15,8 +15,6 @@ */ package com.android.keyguard; -import com.android.keyguard.KeyguardHostView.OnDismissAction; - public interface KeyguardSecurityCallback { /** @@ -40,29 +38,13 @@ public interface KeyguardSecurityCallback { /** * Call when user correctly enters their credentials + * @param success */ - void reportSuccessfulUnlockAttempt(); - - /** - * Call when the user incorrectly enters their credentials - */ - void reportFailedUnlockAttempt(); - - /** - * Gets the number of attempts thus far as reported by {@link #reportFailedUnlockAttempt()} - * @return number of failed attempts - */ - int getFailedAttempts(); + void reportUnlockAttempt(boolean success); /** * Shows the backup security for the current method. If none available, this call is a no-op. */ void showBackupSecurity(); - /** - * Sets an action to perform after the user successfully enters their credentials. - * @param action - */ - void setOnDismissAction(OnDismissAction action); - } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java index 9d03c6a..7606689 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -1,11 +1,39 @@ package com.android.keyguard; +import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.widget.FrameLayout; -public class KeyguardSecurityContainer extends FrameLayout { +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardSecurityModel.SecurityMode; + +public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView { + private static final boolean DEBUG = KeyguardViewMediator.DEBUG; + private static final String TAG = "KeyguardSecurityView"; + private KeyguardSecurityModel mSecurityModel; + private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView + private LockPatternUtils mLockPatternUtils; + + private KeyguardSecurityViewFlipper mSecurityViewFlipper; + private boolean mIsVerifyUnlockOnly; + private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; + private boolean mIsBouncing; + private SecurityCallback mSecurityCallback; + + // Used to notify the container when something interesting happens. + public interface SecurityCallback { + public void dismiss(boolean authenticated); + public void userActivity(long timeout); + public void finish(); + } + public KeyguardSecurityContainer(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -16,9 +44,336 @@ public class KeyguardSecurityContainer extends FrameLayout { public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + mSecurityModel = new KeyguardSecurityModel(context); + mLockPatternUtils = new LockPatternUtils(context); + } + + public void setSecurityCallback(SecurityCallback callback) { + mSecurityCallback = callback; + } + + @Override + public void onResume(int reason) { + getSecurityView(mCurrentSecuritySelection).onResume(reason); + } + + @Override + public void onPause() { + getSecurityView(mCurrentSecuritySelection).onPause(); + } + + void updateSecurityViews(boolean isBouncing) { + int children = mSecurityViewFlipper.getChildCount(); + for (int i = 0; i < children; i++) { + updateSecurityView(mSecurityViewFlipper.getChildAt(i), isBouncing); + } + } + + public void announceCurrentSecurityMethod() { + View v = (View) getSecurityView(mCurrentSecuritySelection); + if (v != null) { + v.announceForAccessibility(v.getContentDescription()); + } + } + + private KeyguardSecurityView getSecurityView(SecurityMode securityMode) { + final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); + KeyguardSecurityView view = null; + final int children = mSecurityViewFlipper.getChildCount(); + for (int child = 0; child < children; child++) { + if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) { + view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child)); + break; + } + } + int layoutId = getLayoutIdFor(securityMode); + if (view == null && layoutId != 0) { + final LayoutInflater inflater = LayoutInflater.from(mContext); + if (DEBUG) Log.v(TAG, "inflating id = " + layoutId); + View v = inflater.inflate(layoutId, mSecurityViewFlipper, false); + mSecurityViewFlipper.addView(v); + updateSecurityView(v, mIsBouncing); + view = (KeyguardSecurityView)v; + } + + if (view instanceof KeyguardSelectorView) { + KeyguardSelectorView selectorView = (KeyguardSelectorView) view; + View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container); + selectorView.setCarrierArea(carrierText); + } + + return view; + } + + private void updateSecurityView(View view, boolean isBouncing) { + mIsBouncing = isBouncing; + if (view instanceof KeyguardSecurityView) { + KeyguardSecurityView ksv = (KeyguardSecurityView) view; + ksv.setKeyguardCallback(mCallback); + ksv.setLockPatternUtils(mLockPatternUtils); + if (isBouncing) { + ksv.showBouncer(0); + } else { + ksv.hideBouncer(0); + } + } else { + Log.w(TAG, "View " + view + " is not a KeyguardSecurityView"); + } + } + + protected void onFinishInflate() { + mSecurityViewFlipper = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper); + mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); + } + + public void setLockPatternUtils(LockPatternUtils utils) { + mLockPatternUtils = utils; + mSecurityModel.setLockPatternUtils(utils); + mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils); + } + + private void showDialog(String title, String message) { + final AlertDialog dialog = new AlertDialog.Builder(mContext) + .setTitle(title) + .setMessage(message) + .setNeutralButton(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 PIN: + messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message; + break; + case Password: + messageId = R.string.kg_too_many_failed_password_attempts_dialog_message; + break; + // These don't have timeout dialogs. + case Account: + case Biometric: + case Invalid: + case None: + case SimPin: + case SimPuk: + 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) { + 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); } - KeyguardSecurityViewFlipper getFlipper() { + 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, mLockPatternUtils.getCurrentUser()); + + 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 + + boolean showTimeout = false; + 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 { + 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(SecurityMode.Account); + // don't show timeout dialog because we show account unlock screen next + showTimeout = false; + } + } + } + monitor.reportFailedUnlockAttempt(); + mLockPatternUtils.reportFailedPasswordAttempt(); + if (showTimeout) { + showTimeoutDialog(); + } + } + + /** + * Shows the primary security screen for the user. This will be either the multi-selector + * or the user's security method. + * @param turningOff true if the device is being turned off + */ + void showPrimarySecurityScreen(boolean turningOff) { + SecurityMode securityMode = mSecurityModel.getSecurityMode(); + if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")"); + if (!turningOff && + KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) { + // If we're not turning off, then allow biometric alternate. + // We'll reload it when the device comes back on. + securityMode = mSecurityModel.getAlternateFor(securityMode); + } + showSecurityScreen(securityMode); + } + + /** + * 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 showBackupSecurityScreen() { + if (DEBUG) Log.d(TAG, "showBackupSecurity()"); + SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); + showSecurityScreen(backup); + } + + private boolean showNextSecurityScreenIfPresent() { + SecurityMode securityMode = mSecurityModel.getSecurityMode(); + // Allow an alternate, such as biometric unlock + securityMode = mSecurityModel.getAlternateFor(securityMode); + if (SecurityMode.None == securityMode) { + return false; + } else { + showSecurityScreen(securityMode); // switch to the alternate security view + return true; + } + } + + boolean showNextSecurityScreenOrFinish(boolean authenticated) { + if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); + boolean finish = false; + if (SecurityMode.None == mCurrentSecuritySelection) { + SecurityMode securityMode = mSecurityModel.getSecurityMode(); + // Allow an alternate, such as biometric unlock + securityMode = mSecurityModel.getAlternateFor(securityMode); + if (SecurityMode.None == securityMode) { + finish = true; // no security required + } else { + showSecurityScreen(securityMode); // switch to the alternate security view + } + } else if (authenticated) { + switch (mCurrentSecuritySelection) { + case Pattern: + case Password: + case PIN: + case Account: + case Biometric: + finish = true; + break; + + case SimPin: + case SimPuk: + // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home + SecurityMode securityMode = mSecurityModel.getSecurityMode(); + if (securityMode != SecurityMode.None) { + showSecurityScreen(securityMode); + } else { + finish = true; + } + break; + + default: + Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe"); + showPrimarySecurityScreen(false); + break; + } + } else { + showPrimarySecurityScreen(false); + } + if (finish) { + mSecurityCallback.finish(); + } + return finish; + } + + /** + * Switches to the given security view unless it's already being shown, in which case + * this is a no-op. + * + * @param securityMode + */ + private void showSecurityScreen(SecurityMode securityMode) { + if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")"); + + if (securityMode == mCurrentSecuritySelection) return; + + KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection); + KeyguardSecurityView newView = getSecurityView(securityMode); + + // Emulate Activity life cycle + if (oldView != null) { + oldView.onPause(); + oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view + } + newView.onResume(KeyguardSecurityView.VIEW_REVEALED); + newView.setKeyguardCallback(mCallback); + + // Find and show this child. + final int childCount = mSecurityViewFlipper.getChildCount(); + + final int securityViewIdForMode = getSecurityViewIdForMode(securityMode); + for (int i = 0; i < childCount; i++) { + if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) { + mSecurityViewFlipper.setDisplayedChild(i); + break; + } + } + + mCurrentSecuritySelection = securityMode; + } + + private KeyguardSecurityViewFlipper getFlipper() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof KeyguardSecurityViewFlipper) { @@ -41,5 +396,129 @@ public class KeyguardSecurityContainer extends FrameLayout { flipper.hideBouncer(duration); } } + + private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() { + + public void userActivity(long timeout) { + if (mSecurityCallback != null) { + mSecurityCallback.userActivity(timeout); + } + } + + public void dismiss(boolean authenticated) { + mSecurityCallback.dismiss(authenticated); + } + + public boolean isVerifyUnlockOnly() { + return mIsVerifyUnlockOnly; + } + + public void reportUnlockAttempt(boolean success) { + KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); + if (success) { + monitor.clearFailedUnlockAttempts(); + mLockPatternUtils.reportSuccessfulPasswordAttempt(); + } else { + if (mCurrentSecuritySelection == SecurityMode.Biometric) { + monitor.reportFailedBiometricUnlockAttempt(); + } else { + KeyguardSecurityContainer.this.reportFailedUnlockAttempt(); + } + } + } + + @Override + public void showBackupSecurity() { + KeyguardSecurityContainer.this.showBackupSecurityScreen(); + } + + }; + + // The following is used to ignore callbacks from SecurityViews that are no longer current + // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the + // state for the current security method. + private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { + @Override + public void userActivity(long timeout) { } + @Override + public void showBackupSecurity() { } + @Override + public void reportUnlockAttempt(boolean success) { } + @Override + public boolean isVerifyUnlockOnly() { return false; } + @Override + public void dismiss(boolean securityVerified) { } + }; + + private int getSecurityViewIdForMode(SecurityMode securityMode) { + switch (securityMode) { + case None: return R.id.keyguard_selector_view; + case Pattern: return R.id.keyguard_pattern_view; + case PIN: return R.id.keyguard_pin_view; + case Password: return R.id.keyguard_password_view; + case Biometric: return R.id.keyguard_face_unlock_view; + case Account: return R.id.keyguard_account_view; + case SimPin: return R.id.keyguard_sim_pin_view; + case SimPuk: return R.id.keyguard_sim_puk_view; + } + return 0; + } + + private int getLayoutIdFor(SecurityMode securityMode) { + switch (securityMode) { + case None: return R.layout.keyguard_selector_view; + case Pattern: return R.layout.keyguard_pattern_view; + case PIN: return R.layout.keyguard_pin_view; + case Password: return R.layout.keyguard_password_view; + case Biometric: return R.layout.keyguard_face_unlock_view; + case Account: return R.layout.keyguard_account_view; + case SimPin: return R.layout.keyguard_sim_pin_view; + case SimPuk: return R.layout.keyguard_sim_puk_view; + default: + return 0; + } + } + + public SecurityMode getSecurityMode() { + return mSecurityModel.getSecurityMode(); + } + + public void verifyUnlock() { + mIsVerifyUnlockOnly = true; + showSecurityScreen(getSecurityMode()); + } + + public SecurityMode getCurrentSecuritySelection() { + return mCurrentSecuritySelection; + } + + public void dismiss(boolean authenticated) { + mCallback.dismiss(authenticated); + } + + public boolean needsInput() { + return mSecurityViewFlipper.needsInput(); + } + + @Override + public void setKeyguardCallback(KeyguardSecurityCallback callback) { + mSecurityViewFlipper.setKeyguardCallback(callback); + } + + @Override + public void reset() { + mSecurityViewFlipper.reset(); + } + + @Override + public KeyguardSecurityCallback getCallback() { + return mSecurityViewFlipper.getCallback(); + } + + @Override + public void showUsabilityHint() { + mSecurityViewFlipper.showUsabilityHint(); + } + } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java index 718b06e..97aec68 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSelectorView.java @@ -58,23 +58,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri final int resId = mGlowPadView.getResourceIdForTarget(target); switch (resId) { - case R.drawable.ic_action_assist_generic: - Intent assistIntent = - ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .getAssistIntent(mContext, true, UserHandle.USER_CURRENT); - if (assistIntent != null) { - mActivityLauncher.launchActivity(assistIntent, false, true, null, null); - } else { - Log.w(TAG, "Failed to get intent for assist activity"); - } - mCallback.userActivity(0); - break; - - case R.drawable.ic_lockscreen_camera: - mActivityLauncher.launchCamera(null, null); - mCallback.userActivity(0); - break; - case R.drawable.ic_lockscreen_unlock_phantom: case R.drawable.ic_lockscreen_unlock: mCallback.userActivity(0); @@ -117,23 +100,6 @@ public class KeyguardSelectorView extends LinearLayout implements KeyguardSecuri } }; - private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() { - - @Override - KeyguardSecurityCallback getCallback() { - return mCallback; - } - - @Override - LockPatternUtils getLockPatternUtils() { - return mLockPatternUtils; - } - - @Override - Context getContext() { - return mContext; - }}; - public KeyguardSelectorView(Context context) { this(context, null); } |