diff options
Diffstat (limited to 'policy')
14 files changed, 531 insertions, 116 deletions
diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java index 7992dd8..26419dd 100644 --- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java @@ -177,12 +177,14 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); + mCallback.reportSuccessfulUnlockAttempt(); // close the keyguard mCallback.keyguardDone(true); } else { mInstructions.setText(R.string.lockscreen_glogin_invalid_input); mPassword.setText(""); + mCallback.reportFailedUnlockAttempt(); } } diff --git a/policy/com/android/internal/policy/impl/GlobalActions.java b/policy/com/android/internal/policy/impl/GlobalActions.java index 2f1f024..8b6257f 100644 --- a/policy/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/com/android/internal/policy/impl/GlobalActions.java @@ -548,6 +548,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac Settings.System.AIRPLANE_MODE_ON, on ? 1 : 0); Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("state", on); mContext.sendBroadcast(intent); } diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index 6bb6a45..06a5f19 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -63,13 +63,18 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { void takeEmergencyCallAction(); /** - * Report that the user had a failed attempt unlocking via the pattern. + * Report that the user had a failed attempt to unlock with password or pattern. */ - void reportFailedPatternAttempt(); + void reportFailedUnlockAttempt(); + + /** + * Report that the user successfully entered their password or pattern. + */ + void reportSuccessfulUnlockAttempt(); /** * Report whether we there's another way to unlock the device. - * @return true + * @return true */ boolean doesFallbackUnlockScreenExist(); } diff --git a/policy/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/com/android/internal/policy/impl/KeyguardViewManager.java index d4dc429..ba1d7f5 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewManager.java @@ -99,7 +99,7 @@ public class KeyguardViewManager implements KeyguardWindowController { mKeyguardHost = new KeyguardViewHost(mContext, mCallback); - final int stretch = ViewGroup.LayoutParams.FILL_PARENT; + final int stretch = ViewGroup.LayoutParams.MATCH_PARENT; int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING @@ -127,8 +127,8 @@ public class KeyguardViewManager implements KeyguardWindowController { mKeyguardView.setCallback(mCallback); final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT); + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); mKeyguardHost.addView(mKeyguardView, lp); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index 8d71146..c3c36b48 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -22,6 +22,7 @@ import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -90,7 +91,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private final static String TAG = "KeyguardViewMediator"; - private static final String DELAYED_KEYGUARD_ACTION = + private static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; // used for handler messages @@ -106,7 +107,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE_DRAWING = 10; private static final int KEYGUARD_DONE_AUTHENTICATING = 11; private static final int SET_HIDDEN = 12; - + /** * The default amount of time we stay awake (used for all key input) */ @@ -132,12 +133,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * that is reenabling the keyguard. */ private static final int KEYGUARD_DONE_DRAWING_TIMEOUT_MS = 2000; - + private Context mContext; private AlarmManager mAlarmManager; + private StatusBarManager mStatusBarManager; private boolean mSystemReady; - + /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ LocalPowerManager mRealPowerManager; @@ -232,7 +234,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mRealPowerManager = powerManager; mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mWakeLock = mPM.newWakeLock( - PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard"); mWakeLock.setReferenceCounted(false); mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); @@ -255,16 +257,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mUpdateMonitor.registerSimStateCallback(this); - mKeyguardViewProperties = - new LockPatternKeyguardViewProperties( - new LockPatternUtils(mContext.getContentResolver()), - mUpdateMonitor); + mKeyguardViewProperties = new LockPatternKeyguardViewProperties( + new LockPatternUtils(mContext), mUpdateMonitor); mKeyguardViewManager = new KeyguardViewManager( context, WindowManagerImpl.getDefault(), this, mKeyguardViewProperties, mUpdateMonitor); mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT); + mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); } /** @@ -294,7 +295,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mExitSecureCallback.onKeyguardExitResult(false); mExitSecureCallback = null; if (!mExternallyEnabled) { - hideLocked(); + hideLocked(); } } else if (mShowing) { notifyScreenOffLocked(); @@ -311,7 +312,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender); - if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = " + mDelayedShowingSequence); } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { // Do not enable the keyguard if the prox sensor forced the screen off. @@ -449,6 +450,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (mHidden != isHidden) { mHidden = isHidden; adjustUserActivityLocked(); + adjustStatusBarLocked(); } } } @@ -504,7 +506,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); return; } - + // if the setup wizard hasn't run yet, don't show final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false); @@ -518,7 +520,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, + " and the sim is not locked or missing"); return; } - + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); showLocked(); } @@ -556,7 +558,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Send a message to keyguard telling it the screen just turned on. - * @see #onScreenTurnedOn() + * @see #onScreenTurnedOn() * @see #handleNotifyScreenOn */ private void notifyScreenOnLocked() { @@ -599,7 +601,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Send message to keyguard telling it to hide itself - * @see #handleHide() + * @see #handleHide() */ private void hideLocked() { if (DEBUG) Log.d(TAG, "hideLocked"); @@ -647,7 +649,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public boolean isSecure() { return mKeyguardViewProperties.isSecure(); } - + private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -688,7 +690,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * The 'Tq' suffix is per the documentation in {@link WindowManagerPolicy}. * Be sure not to take any action that takes a long time; any significant * action should be posted to a handler. - * + * * @param keyCode The keycode of the key that woke the device * @return Whether we poked the wake lock (and turned the screen on) */ @@ -711,12 +713,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_MUTE: - case KeyEvent.KEYCODE_HEADSETHOOK: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; @@ -749,7 +751,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * {@inheritDoc} * - * @see #handleKeyguardDone + * @see #handleKeyguardDone */ public void keyguardDone(boolean authenticated) { keyguardDone(authenticated, true); @@ -757,14 +759,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public void keyguardDone(boolean authenticated, boolean wakeup) { synchronized (this) { - EventLog.writeEvent(70000, 2); + EventLog.writeEvent(70000, 2); if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")"); Message msg = mHandler.obtainMessage(KEYGUARD_DONE); msg.arg1 = wakeup ? 1 : 0; mHandler.sendMessage(msg); if (authenticated) { - mUpdateMonitor.clearFailedAttempts(); + mUpdateMonitor.clearFailedAttempts(); } if (mExitSecureCallback != null) { @@ -898,10 +900,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback, synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - + mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); + adjustStatusBarLocked(); try { ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { @@ -925,6 +928,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, mKeyguardViewManager.hide(); mShowing = false; adjustUserActivityLocked(); + adjustStatusBarLocked(); } } @@ -939,6 +943,23 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } } + private void adjustStatusBarLocked() { + if (mStatusBarManager == null) { + mStatusBarManager = (StatusBarManager) + mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + if (mStatusBarManager == null) { + Log.w(TAG, "Could not get status bar manager"); + } else { + // if the keyguard is shown, allow the status bar to open + // only if the keyguard is insecure and is covered by another window + boolean enable = !mShowing || (mHidden && !isSecure()); + mStatusBarManager.disable(enable ? + StatusBarManager.DISABLE_NONE : + StatusBarManager.DISABLE_EXPAND); + } + } + /** * Handle message sent by {@link #wakeWhenReadyLocked(int)} * @param keyCode The key that woke the device. @@ -969,7 +990,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** - * Handle message sent by {@link #resetStateLocked()} + * Handle message sent by {@link #resetStateLocked()} * @see #RESET */ private void handleReset() { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 85918fb..1e7d62e 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -113,7 +113,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase /** * Unlock by entering an account's login and password. */ - Account + Account, + + /** + * Unlock by entering a password or PIN + */ + Password } /** @@ -141,6 +146,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private final LockPatternUtils mLockPatternUtils; + private int mNumAccounts; private boolean mIsPortrait; /** @@ -153,22 +159,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT); } + // Called by AccountManager.getAccountByTypeAndFeatures() below... public void run(AccountManagerFuture<Account[]> future) { - // We err on the side of caution. - // In case of error we assume we have a SAML account. - boolean hasSAMLAccount = true; + int samlAccounts = 0; try { - hasSAMLAccount = future.getResult().length > 0; + samlAccounts = future.getResult().length; } catch (OperationCanceledException e) { } catch (IOException e) { } catch (AuthenticatorException e) { } - mEnableFallback = !hasSAMLAccount; + // At least one of the accounts must be non-SAML to enable the fallback. + mEnableFallback = samlAccounts < mNumAccounts; if (mUnlockScreen == null) { Log.w(TAG, "no unlock screen when receiving AccountManager information"); } else if (mUnlockScreen instanceof UnlockScreen) { - ((UnlockScreen)mUnlockScreen).setEnableFallback(true); + ((UnlockScreen)mUnlockScreen).setEnableFallback(mEnableFallback); } } @@ -290,6 +296,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase public boolean doesFallbackUnlockScreenExist() { return mEnableFallback; } + + public void reportFailedUnlockAttempt() { + mLockPatternUtils.reportFailedPasswordAttempt(); + } + + public void reportSuccessfulUnlockAttempt() { + mLockPatternUtils.reportSuccessfulPasswordAttempt(); + } }; /** @@ -317,12 +331,19 @@ public class LockPatternKeyguardView extends KeyguardViewBase mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreenMode = unlockMode; + maybeEnableFallback(context); + + addView(mUnlockScreen); + updateScreen(mMode); + } + + private void maybeEnableFallback(Context context) { // Ask the account manager if we have an account that can be used as a // fallback in case the user forgets his pattern. The response comes // back in run() below; don't bother asking until you've called // createUnlockScreenFor(), else the information will go unused. - final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0; - if (hasAccount) { + mNumAccounts = AccountManager.get(context).getAccounts().length; + if (mNumAccounts > 0) { /* If we have a SAML account which requires web login we can not use the fallback screen UI to ask the user for credentials. For now we will disable fallback screen in this case. @@ -332,9 +353,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase AccountManager.get(context).getAccountsByTypeAndFeatures( "com.google", features, this, null); } - - addView(mUnlockScreen); - updateScreen(mMode); } @@ -460,16 +478,25 @@ public class LockPatternKeyguardView extends KeyguardViewBase private boolean isSecure() { UnlockMode unlockMode = getUnlockMode(); - if (unlockMode == UnlockMode.Pattern) { - return mLockPatternUtils.isLockPatternEnabled(); - } else if (unlockMode == UnlockMode.SimPin) { - return mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED - || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; - } else if (unlockMode == UnlockMode.Account) { - return true; - } else { - throw new IllegalStateException("unknown unlock mode " + unlockMode); + boolean secure = false; + switch (unlockMode) { + case Pattern: + secure = mLockPatternUtils.isLockPatternEnabled(); + break; + case SimPin: + secure = mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED + || mUpdateMonitor.getSimState() == IccCard.State.PUK_REQUIRED; + break; + case Account: + secure = true; + break; + case Password: + secure = mLockPatternUtils.isLockPasswordEnabled(); + break; + default: + throw new IllegalStateException("unknown unlock mode " + unlockMode); } + return secure; } private void updateScreen(final Mode mode) { @@ -553,6 +580,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase // "permanently locked" state.) return createUnlockScreenFor(UnlockMode.Pattern); } + } else if (unlockMode == UnlockMode.Password) { + return new PasswordUnlockScreen( + mContext, + mLockPatternUtils, + mUpdateMonitor, + mKeyguardScreenCallback); } else { throw new IllegalArgumentException("unknown unlock mode " + unlockMode); } @@ -604,13 +637,29 @@ public class LockPatternKeyguardView extends KeyguardViewBase */ private UnlockMode getUnlockMode() { final IccCard.State simState = mUpdateMonitor.getSimState(); + UnlockMode currentMode; if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) { - return UnlockMode.SimPin; + currentMode = UnlockMode.SimPin; } else { - return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ? - UnlockMode.Account: - UnlockMode.Pattern; + final int mode = mLockPatternUtils.getPasswordMode(); + switch (mode) { + case LockPatternUtils.MODE_PIN: + case LockPatternUtils.MODE_PASSWORD: + currentMode = UnlockMode.Password; + break; + case LockPatternUtils.MODE_PATTERN: + // "forgot pattern" button is only available in the pattern mode... + if (mForgotPattern && mLockPatternUtils.isPermanentlyLocked()) { + currentMode = UnlockMode.Account; + } else { + currentMode = UnlockMode.Pattern; + } + break; + default: + throw new IllegalStateException("Unknown unlock mode:" + mode); + } } + return currentMode; } private void showTimeoutDialog() { diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java index 8a62cbd..ed5a058 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardViewProperties.java @@ -50,12 +50,7 @@ public class LockPatternKeyguardViewProperties implements KeyguardViewProperties } public boolean isSecure() { - return isLockPatternSecure() || isSimPinSecure(); - } - - private boolean isLockPatternSecure() { - return mLockPatternUtils.isLockPatternEnabled() && mLockPatternUtils - .savedPatternExists(); + return mLockPatternUtils.isSecure() || isSimPinSecure(); } private boolean isSimPinSecure() { diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index c370f9e..657bff1 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -23,6 +23,7 @@ import com.android.internal.widget.SlidingTab; import android.content.Context; import android.content.res.Resources; +import android.content.res.ColorStateList; import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -274,9 +275,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM getContext().getString(R.string.global_action_silent_mode_on_status) : getContext().getString(R.string.global_action_silent_mode_off_status); - final int toastIcon = mSilentMode ? R.drawable.ic_lock_ringer_off - : R.drawable.ic_lock_ringer_on; - toastMessage(mScreenLocked, message, toastIcon); + final int toastIcon = mSilentMode + ? R.drawable.ic_lock_ringer_off + : R.drawable.ic_lock_ringer_on; + + final int toastColor = mSilentMode + ? getContext().getResources().getColor(R.color.keyguard_text_color_soundoff) + : getContext().getResources().getColor(R.color.keyguard_text_color_soundon); + toastMessage(mScreenLocked, message, toastColor, toastIcon); mCallback.pokeWakelock(); } } @@ -292,32 +298,43 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM } /** - * Displays a message in a text view and then removes it. + * Displays a message in a text view and then restores the previous text. * @param textView The text view. * @param text The text. + * @param color The color to apply to the text, or 0 if the existing color should be used. * @param iconResourceId The left hand icon. */ - private void toastMessage(final TextView textView, final String text, final int iconResourceId) { + private void toastMessage(final TextView textView, final String text, final int color, final int iconResourceId) { + if (DBG) android.util.Log.d("LockScreen", "toastMessage(text=" + text +", color=" + color + ")"); + if (mPendingR1 != null) { textView.removeCallbacks(mPendingR1); mPendingR1 = null; } if (mPendingR2 != null) { + mPendingR2.run(); // fire immediately, restoring non-toasted appearance textView.removeCallbacks(mPendingR2); mPendingR2 = null; } + final String oldText = textView.getText().toString(); + final ColorStateList oldColors = textView.getTextColors(); + mPendingR1 = new Runnable() { public void run() { textView.setText(text); + if (color != 0) { + textView.setTextColor(color); + } textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0); - textView.setCompoundDrawablePadding(4); } }; + textView.postDelayed(mPendingR1, 0); mPendingR2 = new Runnable() { public void run() { - textView.setText(""); + textView.setText(oldText); + textView.setTextColor(oldColors); textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } }; @@ -415,11 +432,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM updateLayout(mStatus); } - private void putEmergencyBelow(int viewId) { + private void addRelativeLayoutRule(View view, int rule, int viewId) { final RelativeLayout.LayoutParams layoutParams = - (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams(); - layoutParams.addRule(RelativeLayout.BELOW, viewId); - mEmergencyCallButton.setLayoutParams(layoutParams); + (RelativeLayout.LayoutParams) view.getLayoutParams(); + layoutParams.addRule(rule, viewId); + view.setLayoutParams(layoutParams); } /** @@ -455,6 +472,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM * Update the layout to match the current status. */ private void updateLayout(Status status) { + // The emergency call button appears where the carrier would + // ordinarily be shown, so if one is VISIBLE the other must be + // INVISIBLE. switch (status) { case Normal: // text @@ -485,31 +505,31 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimMissing: // text - mCarrier.setText( + mCarrier.setText(""); + mScreenLocked.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_missing_sim_message_short))); - mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled); + // previously shown here: lockscreen_instructions_when_pattern_disabled // layout - mScreenLocked.setVisibility(View.INVISIBLE); + mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.VISIBLE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; case SimMissingLocked: // text - mCarrier.setText( + mCarrier.setText(""); + mScreenLocked.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_missing_sim_message_short))); - mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions); + // previously shown here: lockscreen_missing_sim_instructions // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; case SimLocked: // text @@ -525,17 +545,17 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM break; case SimPukLocked: // text - mCarrier.setText( + mCarrier.setText(""); + mScreenLocked.setText( getCarrierString( mUpdateMonitor.getTelephonyPlmn(), getContext().getText(R.string.lockscreen_sim_puk_locked_message))); - mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions); + // previously shown here: lockscreen_sim_puk_locked_instructions); // layout mScreenLocked.setVisibility(View.VISIBLE); mSelector.setVisibility(View.GONE); mEmergencyCallButton.setVisibility(View.VISIBLE); - putEmergencyBelow(R.id.screenLocked); break; } } diff --git a/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java new file mode 100644 index 0000000..1a250b8 --- /dev/null +++ b/policy/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy.impl; + +import android.content.Context; + +import com.android.internal.telephony.IccCard.State; +import com.android.internal.widget.LockPatternUtils; + +import android.text.Editable; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import com.android.internal.R; + +/** + * Displays a dialer-like interface or alphanumeric (latin-1) key entry for the user to enter + * an unlock password + */ +public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen, View.OnClickListener, + KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.InfoCallback { + + private static final int DIGIT_PRESS_WAKE_MILLIS = 5000; + + private final KeyguardUpdateMonitor mUpdateMonitor; + private final KeyguardScreenCallback mCallback; + + private final boolean mCreatedWithKeyboardOpen; + + private TextView mPasswordTextView; + private TextView mOkButton; + private TextView mEmergencyCallButton; + private View mBackSpaceButton; + private TextView mCarrier; + private LockPatternUtils mLockPatternUtils; + private Button mCancelButton; + + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + + // To avoid accidental lockout due to events while the device in in the pocket, ignore + // any passwords with length less than or equal to this length. + private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3; + + public PasswordUnlockScreen(Context context, LockPatternUtils lockPatternUtils, + KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback) { + super(context); + mUpdateMonitor = updateMonitor; + mCallback = callback; + mCreatedWithKeyboardOpen = mUpdateMonitor.isKeyboardOpen(); + + LayoutInflater layoutInflater = LayoutInflater.from(context); + if (mCreatedWithKeyboardOpen) { + layoutInflater.inflate(R.layout.keyguard_screen_password_landscape, this, true); + } else { + layoutInflater.inflate(R.layout.keyguard_screen_password_portrait, this, true); + new TouchInput(); + } + + mPasswordTextView = (TextView) findViewById(R.id.pinDisplay); + mBackSpaceButton = findViewById(R.id.backspace); + mBackSpaceButton.setOnClickListener(this); + + // The cancel button is not used on this screen. + mCancelButton = (Button) findViewById(R.id.cancel); + if (mCancelButton != null) { + mCancelButton.setText(""); + } + + mEmergencyCallButton = (TextView) findViewById(R.id.emergencyCall); + mOkButton = (TextView) findViewById(R.id.ok); + + mPasswordTextView.setFocusable(false); + + mEmergencyCallButton.setOnClickListener(this); + mOkButton.setOnClickListener(this); + + mUpdateMonitor.registerConfigurationChangeCallback(this); + + mLockPatternUtils = lockPatternUtils; + mCarrier = (TextView) findViewById(R.id.carrier); + // until we get an update... + mCarrier.setText(LockScreen.getCarrierString(mUpdateMonitor.getTelephonyPlmn(), + mUpdateMonitor.getTelephonySpn())); + + updateMonitor.registerInfoCallback(this); + updateMonitor.registerConfigurationChangeCallback(this); + + setFocusableInTouchMode(true); + } + + /** {@inheritDoc} */ + public boolean needsInput() { + return true; + } + + /** {@inheritDoc} */ + public void onPause() { + + } + + /** {@inheritDoc} */ + public void onResume() { + // start fresh + mPasswordTextView.setText(""); + } + + /** {@inheritDoc} */ + public void cleanUp() { + mUpdateMonitor.removeCallback(this); + } + + public void onClick(View v) { + if (v == mBackSpaceButton) { + final Editable digits = mPasswordTextView.getEditableText(); + final int len = digits.length(); + if (len > 0) { + digits.delete(len-1, len); + } + } else if (v == mEmergencyCallButton) { + mCallback.takeEmergencyCallAction(); + } else if (v == mOkButton) { + verifyPasswordAndUnlock(); + } + mCallback.pokeWakelock(); + } + + private void verifyPasswordAndUnlock() { + String entry = mPasswordTextView.getText().toString(); + if (mLockPatternUtils.checkPassword(entry)) { + mCallback.keyguardDone(true); + mCallback.reportSuccessfulUnlockAttempt(); + } 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(); + } + mPasswordTextView.setText(""); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + return true; + } + + final char match = event.getMatch(DIGITS); + if (match != 0) { + reportDigit(match - '0'); + return true; + } + if (keyCode == KeyEvent.KEYCODE_DEL) { + mPasswordTextView.onKeyDown(keyCode, event); + return true; + } + + if (keyCode == KeyEvent.KEYCODE_ENTER) { + verifyPasswordAndUnlock(); + return true; + } + + return false; + } + + private void reportDigit(int digit) { + mPasswordTextView.append(Integer.toString(digit)); + } + + public void onOrientationChange(boolean inPortrait) { + + } + + public void onKeyboardChange(boolean isKeyboardOpen) { + if (isKeyboardOpen != mCreatedWithKeyboardOpen) { + mCallback.recreateMe(); + } + } + + /** + * Helper class to handle input from touch dialer. Only relevant when + * the keyboard is shut. + */ + private class TouchInput implements View.OnClickListener { + private int mDigitIds[] = { R.id.zero, R.id.one, R.id.two, R.id.three, R.id.four, + R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine }; + private TextView mCancelButton; + private TouchInput() { + for (int i = 0; i < mDigitIds.length; i++) { + Button button = (Button) findViewById(mDigitIds[i]); + button.setOnClickListener(this); + button.setText(Integer.toString(i)); + } + mCancelButton = (TextView) findViewById(R.id.cancel); + mCancelButton.setOnClickListener(this); + mOkButton = (TextView) findViewById(R.id.ok); + mOkButton.setOnClickListener(this); + } + + public void onClick(View v) { + if (v == mCancelButton) { + return; + } + if (v == mOkButton) { + verifyPasswordAndUnlock(); + } + + final int digit = checkDigit(v); + if (digit >= 0) { + mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS); + reportDigit(digit); + } + } + + private int checkDigit(View v) { + int digit = -1; + for (int i = 0; i < mDigitIds.length; i++) { + if (v.getId() == mDigitIds[i]) { + digit = i; + break; + } + } + return digit; + } + } + + /** {@inheritDoc} */ + public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) { + mCarrier.setText(LockScreen.getCarrierString(plmn, spn)); + } + + public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) { + + } + + public void onRingerModeChanged(int state) { + + } + + public void onTimeChanged() { + + } + + public void onSimStateChanged(State simState) { + + } +} diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 6dd5d93..55772b2 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -15,7 +15,7 @@ package com.android.internal.policy.impl; -import static android.view.ViewGroup.LayoutParams.FILL_PARENT; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; @@ -41,8 +41,6 @@ import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -61,7 +59,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewManager; import android.view.VolumePanel; @@ -204,7 +201,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setContentView(View view) { - setContentView(view, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } @Override @@ -424,7 +421,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } int backgroundResId; - if (lp.width == ViewGroup.LayoutParams.FILL_PARENT) { + if (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) { // If the contents is fill parent for the width, set the // corresponding background backgroundResId = st.fullBackground; @@ -1811,7 +1808,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (SWEEP_OPEN_MENU) { if (mMenuBackground == null && mFeatureId < 0 && getAttributes().height - == WindowManager.LayoutParams.FILL_PARENT) { + == WindowManager.LayoutParams.MATCH_PARENT) { mMenuBackground = getContext().getResources().getDrawable( com.android.internal.R.drawable.menu_background); } @@ -2151,7 +2148,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor.startChanging(); View in = mLayoutInflater.inflate(layoutResource, null); - decor.addView(in, new ViewGroup.LayoutParams(FILL_PARENT, FILL_PARENT)); + decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 30f0d2d..f071771 100755 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -100,6 +100,8 @@ import android.view.animation.AnimationUtils; import android.media.IAudioService; import android.media.AudioManager; +import java.util.ArrayList; + /** * WindowManagerPolicy implementation for the Android phone UI. This * introduces a new method suffix, Lp, for an internal lock of the @@ -181,6 +183,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; WindowState mStatusBar = null; + final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>(); WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; @@ -802,8 +805,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - win.setLayout(WindowManager.LayoutParams.FILL_PARENT, - WindowManager.LayoutParams.FILL_PARENT); + win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT); final WindowManager.LayoutParams params = win.getAttributes(); params.token = appToken; @@ -881,6 +884,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; break; + case TYPE_STATUS_BAR_PANEL: + mStatusBarPanels.add(win); + break; case TYPE_KEYGUARD: if (mKeyguard != null) { return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; @@ -898,6 +904,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (mKeyguard == win) { mKeyguard = null; + } else { + mStatusBarPanels.remove(win); } } @@ -1436,7 +1444,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mKeyguard != null) { if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { - if (mKeyguard.hideLw(false)) { + if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -1449,14 +1457,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); } } else if (mHideLockScreen) { - if (mKeyguard.hideLw(false)) { + if (mKeyguard.hideLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } mKeyguardMediator.setHidden(true); } else { - if (mKeyguard.showLw(false)) { + if (mKeyguard.showLw(true)) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -1493,6 +1501,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + public boolean allowAppAnimationsLw() { + if (mKeyguard != null && mKeyguard.isVisibleLw()) { + // If keyguard is currently visible, no reason to animate + // behind it. + return false; + } + if (mStatusBar != null && mStatusBar.isVisibleLw()) { + Rect rect = new Rect(mStatusBar.getShownFrameLw()); + for (int i=mStatusBarPanels.size()-1; i>=0; i--) { + WindowState w = mStatusBarPanels.get(i); + if (w.isVisibleLw()) { + rect.union(w.getShownFrameLw()); + } + } + final int insetw = mW/10; + final int inseth = mH/10; + if (rect.contains(insetw, inseth, mW-insetw, mH-inseth)) { + // All of the status bar windows put together cover the + // screen, so the app can't be seen. (Note this test doesn't + // work if the rects of these windows are at off offsets or + // sizes, causing gaps in the rect union we have computed.) + return false; + } + } + return true; + } + /** {@inheritDoc} */ public boolean preprocessInputEventTq(RawInputEvent event) { switch (event.type) { @@ -1725,8 +1760,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.removeCallbacks(mPowerLongPress); if (mShouldTurnOffOnKeyUp) { mShouldTurnOffOnKeyUp = false; - boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; - boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + boolean gohome, sleeps; + if (code == KeyEvent.KEYCODE_ENDCALL) { + gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; + sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; + } else { + gohome = false; + sleeps = true; + } if (keyguardActive || (sleeps && !gohome) || (gohome && !goHome() && sleeps)) { @@ -1919,6 +1960,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + public boolean isScreenOn() { + return mScreenOn; + } + + /** {@inheritDoc} */ public void enableKeyguard(boolean enabled) { mKeyguardMediator.setKeyguardEnabled(enabled); } @@ -1928,8 +1974,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator.verifyUnlock(callback); } - /** {@inheritDoc} */ - public boolean keyguardIsShowingTq() { + private boolean keyguardIsShowingTq() { return mKeyguardMediator.isShowingAndNotHidden(); } diff --git a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java index 4c46be5..c5aafa5 100644 --- a/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -110,8 +110,11 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener if (b == v) { // prepare a launch intent and send it Intent intent = (Intent)b.getTag(); - intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); - getContext().startActivity(intent); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY); + getContext().startActivity(intent); + } + break; } } dismiss(); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 3881d11..8c738a7 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -27,7 +27,6 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; -import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; @@ -167,6 +166,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } mCallback.pokeWakelock(); } else if (v == mEmergencyCallButton) { + mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } else if (v == mOkButton) { checkPin(); @@ -219,8 +219,8 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie mHeaderText.setText(R.string.keyguard_password_wrong_pin_code); mPinText.setText(""); mEnteredDigits = 0; - mCallback.pokeWakelock(); } + mCallback.pokeWakelock(); } }.start(); } diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index e090ac5..5e6e54d 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -52,12 +52,20 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // how long before we clear the wrong pattern private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000; - // how long we stay awake once the user is ready to enter a pattern + // how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000; + // how long we stay awake after the user hits the first dot. + private static final int UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS = 2000; + // how many cells the user has to cross before we poke the wakelock private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2; + // This dictates how long a pattern should be before we count it as an attempt. + // This should be long enough to avoid false triggers while the device is in a pocket, + // as this can lead to a wiped device if a {@link DeviceAdmin} is active and has it enabled. + private static final int MIN_PATTERN_BEFORE_REPORT = 3; + private int mFailedPatternAttemptsSinceLastTimeout = 0; private int mTotalFailedPatternAttempts = 0; private CountDownTimer mCountdownTimer = null; @@ -197,6 +205,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // emergency call buttons final OnClickListener emergencyClick = new OnClickListener() { public void onClick(View v) { + mCallback.pokeWakelock(); mCallback.takeEmergencyCallAction(); } }; @@ -465,6 +474,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // the user actually trying to draw a pattern of some minimal length. if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); + } else { + // Give just a little extra time if they hit one of the first few dots + mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_FIRST_DOTS_MS); } } @@ -475,6 +487,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mInstructions = ""; updateStatusLines(); mCallback.keyguardDone(true); + mCallback.reportSuccessfulUnlockAttempt(); } else { if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS); @@ -483,19 +496,21 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { mTotalFailedPatternAttempts++; mFailedPatternAttemptsSinceLastTimeout++; - mCallback.reportFailedPatternAttempt(); } if (mFailedPatternAttemptsSinceLastTimeout >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) { long deadline = mLockPatternUtils.setLockoutAttemptDeadline(); handleAttemptLockout(deadline); - return; + } else { + // TODO mUnlockIcon.setVisibility(View.VISIBLE); + mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); + updateStatusLines(); + mLockPatternView.postDelayed( + mCancelPatternRunnable, + PATTERN_CLEAR_TIMEOUT_MS); + } + if (pattern.size() > MIN_PATTERN_BEFORE_REPORT) { + mCallback.reportFailedUnlockAttempt(); } - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong); - updateStatusLines(); - mLockPatternView.postDelayed( - mCancelPatternRunnable, - PATTERN_CLEAR_TIMEOUT_MS); } } } |