eclair snapshot
diff --git a/mid/com/android/internal/policy/impl/MidWindow.java b/mid/com/android/internal/policy/impl/MidWindow.java
index 68727fb..b2e9ebd 100644
--- a/mid/com/android/internal/policy/impl/MidWindow.java
+++ b/mid/com/android/internal/policy/impl/MidWindow.java
@@ -67,6 +67,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+
+import android.view.Window.Callback;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 import android.widget.FrameLayout;
@@ -1886,6 +1888,11 @@
         @Override
         protected void onAttachedToWindow() {
             super.onAttachedToWindow();
+            
+            final Callback cb = getCallback();
+            if (cb != null && mFeatureId < 0) {
+                cb.onAttachedToWindow();
+            }
 
             if (mFeatureId == -1) {
                 /*
@@ -1898,6 +1905,16 @@
                 openPanelsAfterRestore();
             }
         }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            
+            final Callback cb = getCallback();
+            if (cb != null && mFeatureId < 0) {
+                cb.onDetachedFromWindow();
+            }
+        }
     }
 
     protected DecorView generateDecor() {
diff --git a/mid/com/android/internal/policy/impl/MidWindowManager.java b/mid/com/android/internal/policy/impl/MidWindowManager.java
index 2bff15b..ffdf872 100644
--- a/mid/com/android/internal/policy/impl/MidWindowManager.java
+++ b/mid/com/android/internal/policy/impl/MidWindowManager.java
@@ -83,6 +83,7 @@
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManagerPolicy.WindowState;
+import android.view.animation.Animation;
 import android.media.IAudioService;
 import android.media.AudioManager;
 
@@ -354,6 +355,19 @@
         return 0;
     }
 
+    public int getMaxWallpaperLayer() {
+        return STATUS_BAR_LAYER;
+    }
+
+    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
+        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
+    }
+    
+    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
+        return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
+                && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
+    }
+    
     /** {@inheritDoc} */
     public View addStartingWindow(IBinder appToken, String packageName,
                                   int theme, CharSequence nonLocalizedLabel,
@@ -520,13 +534,17 @@
         return 0;
     }
 
+    public Animation createForceHideEnterAnimation() {
+        return null;
+    }
+    
     private static IAudioService getAudioInterface() {
         return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
     }
 
     /** {@inheritDoc} */
     public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 
-            int repeatCount) {
+            int repeatCount, int flags) {
         if (false) {
             Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
                     + repeatCount);
@@ -762,8 +780,8 @@
     }
 
     /** {@inheritDoc} */
-    public boolean finishLayoutLw() {
-        return false;
+    public int finishLayoutLw() {
+        return 0;
     }
 
     /** {@inheritDoc} */
@@ -834,17 +852,12 @@
      * @return Whether music is being played right now.
      */
     private boolean isMusicActive() {
-        final IAudioService audio = getAudioInterface();
-        if (audio == null) {
-            Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
+        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+        if (am == null) {
+            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
             return false;
         }
-        try {
-            return audio.isMusicActive();
-        } catch (RemoteException e) {
-            Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
-            return false;
-        }
+        return am.isMusicActive();
     }
 
     /**
@@ -1072,6 +1085,13 @@
         return false;
     }
     
+    public void keyFeedbackFromInput(KeyEvent event) {
+    }
+    
     public void screenOnStoppedLw() {
     }
+
+    public boolean allowKeyRepeat() {
+        return true;
+    }
 }
diff --git a/phone/com/android/internal/policy/impl/AccountUnlockScreen.java b/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
index 65102c6..7992dd8 100644
--- a/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -19,38 +19,39 @@
 import com.android.internal.R;
 import com.android.internal.widget.LockPatternUtils;
 
-import android.accounts.AccountsServiceConstants;
-import android.accounts.IAccountsService;
-import android.content.ComponentName;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.OperationCanceledException;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.AccountManagerCallback;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.graphics.Rect;
-import android.os.IBinder;
-import android.os.RemoteException;
 import android.text.Editable;
 import android.text.InputFilter;
 import android.text.LoginFilter;
 import android.text.TextWatcher;
-import android.text.TextUtils;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+
+import java.io.IOException;
 
 /**
  * When the user forgets their password a bunch of times, we fall back on their
  * account's login/password to unlock the phone (and reset their lock pattern).
- *
- * <p>This class is useful only on platforms that support the
- * IAccountsService.
  */
 public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen,
-        View.OnClickListener, ServiceConnection, TextWatcher {
+        View.OnClickListener, TextWatcher {
     private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
     private static final String LOCK_PATTERN_CLASS =
             "com.android.settings.ChooseLockPattern";
@@ -62,7 +63,6 @@
 
     private final KeyguardScreenCallback mCallback;
     private final LockPatternUtils mLockPatternUtils;
-    private IAccountsService mAccountsService;
 
     private TextView mTopHeader;
     private TextView mInstructions;
@@ -72,14 +72,16 @@
     private Button mEmergencyCall;
 
     /**
+     * Shown while making asynchronous check of password.
+     */
+    private ProgressDialog mCheckingDialog;
+
+    /**
      * AccountUnlockScreen constructor.
-     *
-     * @throws IllegalStateException if the IAccountsService is not
-     * available on the current platform.
      */
     public AccountUnlockScreen(Context context,
-            KeyguardScreenCallback callback,
-            LockPatternUtils lockPatternUtils) {
+                               KeyguardScreenCallback callback,
+                               LockPatternUtils lockPatternUtils) {
         super(context);
         mCallback = callback;
         mLockPatternUtils = lockPatternUtils;
@@ -88,6 +90,9 @@
                 R.layout.keyguard_screen_glogin_unlock, this, true);
 
         mTopHeader = (TextView) findViewById(R.id.topHeader);
+        mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ?
+                R.string.lockscreen_glogin_too_many_attempts :
+                R.string.lockscreen_glogin_forgot_pattern);
 
         mInstructions = (TextView) findViewById(R.id.instructions);
 
@@ -103,14 +108,6 @@
 
         mEmergencyCall = (Button) findViewById(R.id.emergencyCall);
         mEmergencyCall.setOnClickListener(this);
-
-        Log.v("AccountUnlockScreen", "debug: Connecting to accounts service");
-        final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
-                this, Context.BIND_AUTO_CREATE);
-        if (!connected) {
-            Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service");
-            throw new IllegalStateException("couldn't bind to accounts service");
-        }
     }
 
     public void afterTextChanged(Editable s) {
@@ -150,30 +147,16 @@
 
     /** {@inheritDoc} */
     public void cleanUp() {
-        mContext.unbindService(this);
+        if (mCheckingDialog != null) {
+            mCheckingDialog.hide();
+        }
     }
 
     /** {@inheritDoc} */
     public void onClick(View v) {
         mCallback.pokeWakelock();
         if (v == mOk) {
-            if (checkPassword()) {
-                // clear out forgotten password
-                mLockPatternUtils.setPermanentlyLocked(false);
-
-                // launch the 'choose lock pattern' activity so
-                // the user can pick a new one if they want to
-                Intent intent = new Intent();
-                intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                mContext.startActivity(intent);
-
-                // close the keyguard
-                mCallback.keyguardDone(true);
-            } else {
-                mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
-                mPassword.setText("");
-            }
+            asyncCheckPassword();
         }
 
         if (v == mEmergencyCall) {
@@ -181,11 +164,37 @@
         }
     }
 
+    private void onCheckPasswordResult(boolean success) {
+        if (success) {
+            // clear out forgotten password
+            mLockPatternUtils.setPermanentlyLocked(false);
+            mLockPatternUtils.setLockPatternEnabled(false);
+            mLockPatternUtils.saveLockPattern(null);
+
+            // launch the 'choose lock pattern' activity so
+            // the user can pick a new one if they want to
+            Intent intent = new Intent();
+            intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+
+            // close the keyguard
+            mCallback.keyguardDone(true);
+        } else {
+            mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
+            mPassword.setText("");
+        }
+    }
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (event.getAction() == KeyEvent.ACTION_DOWN
                 && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-            mCallback.goToLockScreen();
+            if (mLockPatternUtils.isPermanentlyLocked()) {
+                mCallback.goToLockScreen();
+            } else {
+                mCallback.forgotPattern(false);
+            }
             return true;
         }
         return super.dispatchKeyEvent(event);
@@ -207,33 +216,25 @@
      * @return an account name from the database, or null if we can't
      * find a single best match.
      */
-    private String findIntendedAccount(String username) {
-        String[] accounts = null;
-        try {
-            accounts = mAccountsService.getAccounts();
-        } catch (RemoteException e) {
-            return null;
-        }
-        if (accounts == null) {
-            return null;
-        }
+    private Account findIntendedAccount(String username) {
+        Account[] accounts = AccountManager.get(mContext).getAccounts();
 
         // Try to figure out which account they meant if they
         // typed only the username (and not the domain), or got
         // the case wrong.
 
-        String bestAccount = null;
+        Account bestAccount = null;
         int bestScore = 0;
-        for (String a: accounts) {
+        for (Account a: accounts) {
             int score = 0;
-            if (username.equals(a)) {
+            if (username.equals(a.name)) {
                 score = 4;
-            } else if (username.equalsIgnoreCase(a)) {
+            } else if (username.equalsIgnoreCase(a.name)) {
                 score = 3;
             } else if (username.indexOf('@') < 0) {
-                int i = a.indexOf('@');
+                int i = a.name.indexOf('@');
                 if (i >= 0) {
-                    String aUsername = a.substring(0, i);
+                    String aUsername = a.name.substring(0, i);
                     if (username.equals(aUsername)) {
                         score = 2;
                     } else if (username.equalsIgnoreCase(aUsername)) {
@@ -251,28 +252,64 @@
         return bestAccount;
     }
 
-    private boolean checkPassword() {
+    private void asyncCheckPassword() {
+        mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
         final String login = mLogin.getText().toString();
         final String password = mPassword.getText().toString();
-        try {
-            String account = findIntendedAccount(login);
-            if (account == null) {
-                return false;
-            }
-            return mAccountsService.shouldUnlock(account, password);
-        } catch (RemoteException e) {
-            return false;
+        Account account = findIntendedAccount(login);
+        if (account == null) {
+            onCheckPasswordResult(false);
+            return;
         }
+        getProgressDialog().show();
+        Bundle options = new Bundle();
+        options.putString(AccountManager.KEY_PASSWORD, password);
+        AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */,
+                new AccountManagerCallback<Bundle>() {
+            public void run(AccountManagerFuture<Bundle> future) {
+                try {
+                    mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
+                    final Bundle result = future.getResult();
+                    final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+                    // ensure on UI thread
+                    mLogin.post(new Runnable() {
+                        public void run() {
+                            onCheckPasswordResult(verified);
+                        }
+                    });
+                } catch (OperationCanceledException e) {
+                    onCheckPasswordResult(false);
+                } catch (IOException e) {
+                    onCheckPasswordResult(false);
+                } catch (AuthenticatorException e) {
+                    onCheckPasswordResult(false);
+                } finally {
+                    mLogin.post(new Runnable() {
+                        public void run() {
+                            getProgressDialog().hide();
+                        }
+                    });
+                }
+            }
+        }, null /* handler */);
     }
 
-    /** {@inheritDoc} */
-    public void onServiceConnected(ComponentName name, IBinder service) {
-        Log.v("AccountUnlockScreen", "debug: About to grab as interface");
-        mAccountsService = IAccountsService.Stub.asInterface(service);
-    }
-
-    /** {@inheritDoc} */
-    public void onServiceDisconnected(ComponentName name) {
-        mAccountsService = null;
+    private Dialog getProgressDialog() {
+        if (mCheckingDialog == null) {
+            mCheckingDialog = new ProgressDialog(mContext);
+            mCheckingDialog.setMessage(
+                    mContext.getString(R.string.lockscreen_glogin_checking_password));
+            mCheckingDialog.setIndeterminate(true);
+            mCheckingDialog.setCancelable(false);
+            mCheckingDialog.getWindow().setType(
+                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+            if (!mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_sf_slowBlur)) {
+                mCheckingDialog.getWindow().setFlags(
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+            }
+        }
+        return mCheckingDialog;
     }
 }
diff --git a/phone/com/android/internal/policy/impl/GlobalActions.java b/phone/com/android/internal/policy/impl/GlobalActions.java
index 377ff78..2f1f024 100644
--- a/phone/com/android/internal/policy/impl/GlobalActions.java
+++ b/phone/com/android/internal/policy/impl/GlobalActions.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy.impl;
 
+import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
@@ -26,6 +27,7 @@
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemProperties;
 import android.provider.Settings;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -40,6 +42,8 @@
 import android.widget.TextView;
 import com.android.internal.R;
 import com.android.internal.app.ShutdownThread;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.TelephonyProperties;
 import com.google.android.collect.Lists;
 
 import java.util.ArrayList;
@@ -69,6 +73,7 @@
     private boolean mKeyguardShowing = false;
     private boolean mDeviceProvisioned = false;
     private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
+    private boolean mIsWaitingForEcmExit = false;
 
     /**
      * @param context everything needs a context :(
@@ -81,6 +86,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
         context.registerReceiver(mBroadcastReceiver, filter);
 
         // get notified of phone state changes
@@ -141,20 +147,27 @@
                 R.string.global_actions_airplane_mode_off_status) {
 
             void onToggle(boolean on) {
-                // Change the system setting
-                Settings.System.putInt(
-                        mContext.getContentResolver(),
-                        Settings.System.AIRPLANE_MODE_ON,
-                        on ? 1 : 0);
-                Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-                intent.putExtra("state", on);
-                mContext.sendBroadcast(intent);
+                if (Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                    mIsWaitingForEcmExit = true;
+                    // Launch ECM exit dialog
+                    Intent ecmDialogIntent =
+                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
+                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    mContext.startActivity(ecmDialogIntent);
+                } else {
+                    changeAirplaneModeSystemSetting(on);
+                }
             }
 
             @Override
             protected void changeStateFromPress(boolean buttonOn) {
-                mState = buttonOn ? State.TurningOn : State.TurningOff;
-                mAirplaneState = mState;
+                // In ECM mode airplane state cannot be changed
+                if (!(Boolean.parseBoolean(
+                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                    mState = buttonOn ? State.TurningOn : State.TurningOff;
+                    mAirplaneState = mState;
+                }
             }
 
             public boolean showDuringKeyguard() {
@@ -200,8 +213,11 @@
 
         final AlertDialog dialog = ab.create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);        
+        if (!mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_sf_slowBlur)) {
+            dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        }
 
         dialog.setOnDismissListener(this);
 
@@ -218,7 +234,7 @@
         if (mKeyguardShowing) {
             mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         } else {
-            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);            
+            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
         }
     }
 
@@ -490,6 +506,14 @@
                 if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
                     mHandler.sendEmptyMessage(MESSAGE_DISMISS);
                 }
+            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
+                // Airplane mode can be changed after ECM exits if airplane toggle button
+                // is pressed during ECM mode
+                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
+                        mIsWaitingForEcmExit) {
+                    mIsWaitingForEcmExit = false;
+                    changeAirplaneModeSystemSetting(true);
+                }
             }
         }
     };
@@ -514,4 +538,17 @@
             }
         }
     };
+
+    /**
+     * Change the airplane mode system setting
+     */
+    private void changeAirplaneModeSystemSetting(boolean on) {
+        Settings.System.putInt(
+                mContext.getContentResolver(),
+                Settings.System.AIRPLANE_MODE_ON,
+                on ? 1 : 0);
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", on);
+        mContext.sendBroadcast(intent);
+    }
 }
diff --git a/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java b/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
index b46b37d..6bb6a45 100644
--- a/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
+++ b/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
@@ -28,11 +28,20 @@
     void goToLockScreen();
 
     /**
-     * Transitino to th unlock screen.
+     * Transition to the unlock screen.
      */
     void goToUnlockScreen();
 
     /**
+     * The user reported that they forgot their pattern (or not, when they want to back out of the
+     * forgot pattern screen).
+     *
+     * @param isForgotten True if the user hit the forgot pattern, false if they want to back out
+     *        of the account screen.
+     */
+    void forgotPattern(boolean isForgotten);
+
+    /**
      * @return Whether the keyguard requires some sort of PIN.
      */
     boolean isSecure();
diff --git a/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index cd21427..58905a1 100644
--- a/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -35,7 +35,6 @@
 import static android.provider.Telephony.Intents.EXTRA_SPN;
 import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION;
 
-import com.android.internal.app.ShutdownThread;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.TelephonyIntents;
 import android.util.Log;
@@ -67,6 +66,8 @@
     private boolean mInPortrait;
     private boolean mKeyboardOpen;
 
+    private boolean mKeyguardBypassEnabled;
+
     private boolean mDevicePluggedIn;
     
     private boolean mDeviceProvisioned;
@@ -163,6 +164,9 @@
             }
         };
 
+        mKeyguardBypassEnabled = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_bypass_keyguard_if_slider_open);
+
         mDeviceProvisioned = Settings.Secure.getInt(
                 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
      
@@ -295,13 +299,6 @@
                         shouldShowBatteryInfo(), pluggedIn, batteryLevel);
             }
         }
-
-        // shut down gracefully if our battery is critically low and we are not powered
-        if (batteryLevel == 0 &&
-                pluggedInStatus != BATTERY_STATUS_CHARGING &&
-                pluggedInStatus != BATTERY_STATUS_UNKNOWN) {
-            ShutdownThread.shutdown(mContext, false);
-        }
     }
 
     /**
@@ -513,6 +510,10 @@
         return mKeyboardOpen;
     }
 
+    public boolean isKeyguardBypassEnabled() {
+        return mKeyguardBypassEnabled;
+    }
+
     public boolean isDevicePluggedIn() {
         return mDevicePluggedIn;
     }
diff --git a/phone/com/android/internal/policy/impl/KeyguardViewManager.java b/phone/com/android/internal/policy/impl/KeyguardViewManager.java
index 297d62f..bac2fca 100644
--- a/phone/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/phone/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -48,7 +48,7 @@
 
     private WindowManager.LayoutParams mWindowLayoutParams;
     private boolean mNeedsInput = false;
-    
+
     private FrameLayout mKeyguardHost;
     private KeyguardViewBase mKeyguardView;
 
@@ -101,6 +101,8 @@
 
             final int stretch = ViewGroup.LayoutParams.FILL_PARENT;
             int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+                    | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
+                    | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
                     /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
             if (!mNeedsInput) {
@@ -108,7 +110,7 @@
             }
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                     stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD,
-                    flags, PixelFormat.OPAQUE);
+                    flags, PixelFormat.TRANSLUCENT);
             lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
             lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
             lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -152,7 +154,7 @@
             mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
         }
     }
-    
+
     /**
      * Reset the state of the view.
      */
@@ -195,10 +197,14 @@
      *
      * @param keyCode The wake key.
      */
-    public void wakeWhenReadyTq(int keyCode) {
+    public boolean wakeWhenReadyTq(int keyCode) {
         if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
         if (mKeyguardView != null) {
             mKeyguardView.wakeWhenReadyTq(keyCode);
+            return true;
+        } else {
+            Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
+            return false;
         }
     }
 
@@ -209,10 +215,19 @@
         if (DEBUG) Log.d(TAG, "hide()");
         if (mKeyguardHost != null) {
             mKeyguardHost.setVisibility(View.GONE);
+            // Don't do this right away, so we can let the view continue to animate
+            // as it goes away.
             if (mKeyguardView != null) {
-                mKeyguardHost.removeView(mKeyguardView);
-                mKeyguardView.cleanUp();
+                final KeyguardViewBase lastView = mKeyguardView;
                 mKeyguardView = null;
+                mKeyguardHost.postDelayed(new Runnable() {
+                    public void run() {
+                        synchronized (KeyguardViewManager.this) {
+                            mKeyguardHost.removeView(lastView);
+                            lastView.cleanUp();
+                        }
+                    }
+                }, 500);
             }
         }
     }
diff --git a/phone/com/android/internal/policy/impl/KeyguardViewMediator.java b/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
index 043f727..f5591b2 100644
--- a/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -19,11 +19,9 @@
 import com.android.internal.telephony.IccCard;
 import com.android.internal.widget.LockPatternUtils;
 
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.app.StatusBarManager;
-import static android.app.StatusBarManager.DISABLE_EXPAND;
-import static android.app.StatusBarManager.DISABLE_NONE;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -32,7 +30,9 @@
 import android.os.LocalPowerManager;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.telephony.TelephonyManager;
 import android.util.Config;
 import android.util.EventLog;
@@ -84,7 +84,7 @@
  * thread of the keyguard.
  */
 public class KeyguardViewMediator implements KeyguardViewCallback,
-        KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback {
+        KeyguardUpdateMonitor.SimStateCallback {
     private final static boolean DEBUG = false && Config.LOGD;
     private final static boolean DBG_WAKE = DEBUG || true;
 
@@ -104,6 +104,7 @@
     private static final int WAKE_WHEN_READY = 8;
     private static final int KEYGUARD_DONE = 9;
     private static final int KEYGUARD_DONE_DRAWING = 10;
+    private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
     
     /**
      * The default amount of time we stay awake (used for all key input)
@@ -122,7 +123,7 @@
      * turning on the keyguard (i.e, the user has this much time to turn
      * the screen back on without having to face the keyguard).
      */
-    private static final int KEYGUARD_DELAY_MS = 0;
+    private static final int KEYGUARD_DELAY_MS = 5000;
 
     /**
      * How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()}
@@ -150,6 +151,12 @@
     private PowerManager.WakeLock mWakeLock;
 
     /**
+     * Used to keep the device awake while to ensure the keyguard finishes opening before
+     * we sleep.
+     */
+    private PowerManager.WakeLock mShowKeyguardWakeLock;
+
+    /**
      * Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)}
      * is called to make sure the device doesn't sleep before it has a chance to poke
      * the wake lock.
@@ -157,11 +164,6 @@
      */
     private PowerManager.WakeLock mWakeAndHandOff;
 
-    /**
-     * Used to disable / reenable status bar expansion.
-     */
-    private StatusBarManager mStatusBarManager;
-
     private KeyguardViewManager mKeyguardViewManager;
 
     // these are protected by synchronized (this)
@@ -182,6 +184,9 @@
     // answer whether the input should be restricted)
     private boolean mShowing = false;
 
+    // true if the keyguard is hidden by another window
+    private boolean mHidden = false;
+
     /**
      * Helps remember whether the screen has turned on since the last time
      * it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
@@ -229,6 +234,8 @@
                 PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 
                 "keyguard");
         mWakeLock.setReferenceCounted(false);
+        mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
+        mShowKeyguardWakeLock.setReferenceCounted(false);
 
         mWakeAndHandOff = mPM.newWakeLock(
                 PowerManager.PARTIAL_WAKE_LOCK,
@@ -245,7 +252,6 @@
 
         mUpdateMonitor = new KeyguardUpdateMonitor(context);
 
-        mUpdateMonitor.registerConfigurationChangeCallback(this);
         mUpdateMonitor.registerSimStateCallback(this);
 
         mKeyguardViewProperties =
@@ -347,14 +353,12 @@
                 if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
                         + "disabling status bar expansion");
                 mNeedToReshowWhenReenabled = true;
-                setStatusBarExpandable(false);
                 hideLocked();
             } else if (enabled && mNeedToReshowWhenReenabled) {
                 // reenabled after previously hidden, reshow
                 if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
                         + "status bar expansion");
                 mNeedToReshowWhenReenabled = false;
-                setStatusBarExpandable(true);
 
                 if (mExitSecureCallback != null) {
                     if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
@@ -409,15 +413,6 @@
         }
     }
 
-
-    private void setStatusBarExpandable(boolean isExpandable) {
-        if (mStatusBarManager == null) {
-            mStatusBarManager =
-                    (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
-        }
-        mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND);
-    }
-
     /**
      * Is the keyguard currently showing?
      */
@@ -426,6 +421,17 @@
     }
 
     /**
+     * Notify us when the keyguard is hidden by another window
+     */
+    public void setHidden(boolean isHidden) {
+        if (DEBUG) Log.d(TAG, "setHidden " + isHidden);
+        synchronized (KeyguardViewMediator.this) {
+            mHidden = isHidden;
+            adjustUserActivityLocked();
+        }
+    }
+
+    /**
      * Given the state of the keyguard, is the input restricted?
      * Input is restricted when the keyguard is showing, or when the keyguard
      * was suppressed by an app that disabled the keyguard or we haven't been provisioned yet.
@@ -434,6 +440,21 @@
         return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
     }
 
+    /**
+     * Returns true if the change is resulting in the keyguard beign dismissed,
+     * meaning the screen can turn on immediately.  Otherwise returns false.
+     */
+    public boolean doLidChangeTq(boolean isLidOpen) {
+        mKeyboardOpen = isLidOpen;
+
+        if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen
+                && !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) {
+            if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard");
+            mHandler.sendEmptyMessage(KEYGUARD_DONE_AUTHENTICATING);
+            return true;
+        }
+        return false;
+    }
 
     /**
      * Enable the keyguard if the settings are appropriate.
@@ -463,9 +484,13 @@
             }
             
             // if the setup wizard hasn't run yet, don't show
+            final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim",
+                    false);
             final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
             final IccCard.State state = mUpdateMonitor.getSimState();
-            final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT);
+            final boolean lockedOrMissing = state.isPinLocked()
+                    || ((state == IccCard.State.ABSENT) && requireSim);
+
             if (!lockedOrMissing && !provisioned) {
                 if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
                         + " and the sim is not locked or missing");
@@ -544,6 +569,8 @@
      */
     private void showLocked() {
         if (DEBUG) Log.d(TAG, "showLocked");
+        // ensure we stay awake until we are finished displaying the keyguard
+        mShowKeyguardWakeLock.acquire();
         Message msg = mHandler.obtainMessage(SHOW);
         mHandler.sendMessage(msg);
     }
@@ -558,26 +585,6 @@
         mHandler.sendMessage(msg);
     }
 
-    /**
-     * {@link KeyguardUpdateMonitor} callbacks.
-     */
-
-    /** {@inheritDoc} */
-    public void onOrientationChange(boolean inPortrait) {
-
-    }
-
-    /** {@inheritDoc} */
-    public void onKeyboardChange(boolean isKeyboardOpen) {
-        mKeyboardOpen = isKeyboardOpen;
-
-        if (mKeyboardOpen && !mKeyguardViewProperties.isSecure()
-                && mKeyguardViewManager.isShowing()) {
-            if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard");
-            keyguardDone(true);
-        }
-    }
-
     /** {@inheritDoc} */
     public void onSimStateChanged(IccCard.State simState) {
         if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);
@@ -615,6 +622,10 @@
         }
     }
 
+    public boolean isSecure() {
+        return mKeyguardViewProperties.isSecure();
+    }
+    
     private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -719,10 +730,15 @@
      * @see #handleKeyguardDone 
      */
     public void keyguardDone(boolean authenticated) {
+        keyguardDone(authenticated, true);
+    }
+
+    public void keyguardDone(boolean authenticated, boolean wakeup) {
         synchronized (this) {
             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) {
@@ -738,7 +754,6 @@
                     // the keyguard when they've released the lock
                     mExternallyEnabled = true;
                     mNeedToReshowWhenReenabled = false;
-                    setStatusBarExpandable(true);
                 }
             }
         }
@@ -789,10 +804,14 @@
                     handleWakeWhenReady(msg.arg1);
                     return;
                 case KEYGUARD_DONE:
-                    handleKeyguardDone();
+                    handleKeyguardDone(msg.arg1 != 0);
                     return;
                 case KEYGUARD_DONE_DRAWING:
                     handleKeyguardDoneDrawing();
+                    return;
+                case KEYGUARD_DONE_AUTHENTICATING:
+                    keyguardDone(true);
+                    return;
             }
         }
     };
@@ -801,10 +820,12 @@
      * @see #keyguardDone
      * @see #KEYGUARD_DONE
      */
-    private void handleKeyguardDone() {
+    private void handleKeyguardDone(boolean wakeup) {
         if (DEBUG) Log.d(TAG, "handleKeyguardDone");
         handleHide();
-        mPM.userActivity(SystemClock.uptimeMillis(), true);
+        if (wakeup) {
+            mPM.userActivity(SystemClock.uptimeMillis(), true);
+        }
         mWakeLock.release();
         mContext.sendBroadcast(mUserPresentIntent);
     }
@@ -853,12 +874,14 @@
             if (DEBUG) Log.d(TAG, "handleShow");
             if (!mSystemReady) return;
             
-            // while we're showing, we control the wake state, so ask the power
-            // manager not to honor request for userActivity.
-            mRealPowerManager.enableUserActivity(false);
-
             mKeyguardViewManager.show();
             mShowing = true;
+            adjustUserActivityLocked();
+            try {
+                ActivityManagerNative.getDefault().closeSystemDialogs("lock");
+            } catch (RemoteException e) {
+            }
+            mShowKeyguardWakeLock.release();
         }
     }
 
@@ -869,11 +892,25 @@
     private void handleHide() {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleHide");
-            // When we go away, tell the poewr manager to honor requests from userActivity.
-            mRealPowerManager.enableUserActivity(true);
+            if (mWakeAndHandOff.isHeld()) {
+                Log.w(TAG, "attempt to hide the keyguard while waking, ignored");
+                return;
+            }
 
             mKeyguardViewManager.hide();
             mShowing = false;
+            adjustUserActivityLocked();
+        }
+    }
+
+    private void adjustUserActivityLocked() {
+        // disable user activity if we are shown and not hidden
+        if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden);
+        boolean enabled = !mShowing || mHidden;
+        mRealPowerManager.enableUserActivity(enabled);
+        if (!enabled && mScreenOn) {
+            // reinstate our short screen timeout policy
+            pokeWakelock();
         }
     }
 
@@ -888,7 +925,11 @@
 
             // this should result in a call to 'poke wakelock' which will set a timeout
             // on releasing the wakelock
-            mKeyguardViewManager.wakeWhenReadyTq(keyCode);
+            if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {
+                // poke wakelock ourselves if keyguard is no longer active
+                Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves");
+                pokeWakelock();
+            }
 
             /**
              * Now that the keyguard is ready and has poked the wake lock, we can
@@ -897,7 +938,7 @@
             mWakeAndHandOff.release();
 
             if (!mWakeLock.isHeld()) {
-                Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock");
+                Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq");
             }
         }
     }
diff --git a/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java b/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 6a1c279..0ebd945 100644
--- a/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -16,41 +16,47 @@
 
 package com.android.internal.policy.impl;
 
-import android.accounts.AccountsServiceConstants;
-import android.accounts.IAccountsService;
+import com.android.internal.R;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.widget.LockPatternUtils;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
 import android.app.AlertDialog;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.SystemProperties;
-import com.android.internal.telephony.IccCard;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PixelFormat;
-import android.graphics.ColorFilter;
-import com.android.internal.R;
-import com.android.internal.widget.LockPatternUtils;
+
+import java.io.IOException;
 
 /**
  * The host view for all of the screens of the pattern unlock screen.  There are
  * two {@link Mode}s of operation, lock and unlock.  This will show the appropriate
- * screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback
+ * screen, and listen for callbacks via
+ * {@link com.android.internal.policy.impl.KeyguardScreenCallback}
  * from the current screen.
  *
- * This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager}
+ * This view, in turn, communicates back to
+ * {@link com.android.internal.policy.impl.KeyguardViewManager}
  * via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
  */
-public class LockPatternKeyguardView extends KeyguardViewBase {
+public class LockPatternKeyguardView extends KeyguardViewBase
+        implements AccountManagerCallback<Account[]> {
 
     // intent action for launching emergency dialer activity.
     static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
@@ -60,12 +66,12 @@
 
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final KeyguardWindowController mWindowController;
-    
+
     private View mLockScreen;
     private View mUnlockScreen;
 
     private boolean mScreenOn = false;
-    private boolean mHasAccount = false; // assume they don't have an account until we know better
+    private boolean mEnableFallback = false; // assume no fallback UI until we know better
 
 
     /**
@@ -114,10 +120,13 @@
     private Mode mMode = Mode.LockScreen;
 
     /**
-     * Keeps track of what mode the current unlock screen is
+     * Keeps track of what mode the current unlock screen is (cached from most recent computation in
+     * {@link #getUnlockMode}).
      */
     private UnlockMode mUnlockScreenMode;
 
+    private boolean mForgotPattern;
+
     /**
      * If true, it means we are in the process of verifying that the user
      * can get past the lock screen per {@link #verifyUnlock()}
@@ -131,11 +140,6 @@
     private final LockPatternUtils mLockPatternUtils;
 
     /**
-     * Used to fetch accounts from GLS.
-     */
-    private ServiceConnection mServiceConnection;
-
-    /**
      * @return Whether we are stuck on the lock screen because the sim is
      *   missing.
      */
@@ -145,6 +149,22 @@
                 && (mUpdateMonitor.getSimState() == IccCard.State.ABSENT);
     }
 
+    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;
+        try {
+            hasSAMLAccount = future.getResult().length > 0;
+        } catch (OperationCanceledException e) {
+        } catch (IOException e) {
+        } catch (AuthenticatorException e) {
+        }
+        mEnableFallback = !hasSAMLAccount;
+        if (mUnlockScreen instanceof UnlockScreen) {
+            ((UnlockScreen)mUnlockScreen).setEnableFallback(true);
+        }
+    }
+
     /**
      * @param context Used to inflate, and create views.
      * @param updateMonitor Knows the state of the world, and passed along to each
@@ -158,9 +178,21 @@
             LockPatternUtils lockPatternUtils,
             KeyguardWindowController controller) {
         super(context);
+
+        final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0;
+        if (hasAccount) {
+            /* 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.
+             Ultimately we could consider bringing up a web login from GLS
+             but need to make sure that it will work in the "locked screen" mode. */
+            String[] features = new String[] {"saml"};
+            AccountManager.get(context).getAccountsByTypeAndFeatures(
+                    "com.google", features, this, null);
+        }
         
-        asyncCheckForAccount();
-        
+        mEnableFallback = false;
+
         mRequiresSim =
                 TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
 
@@ -169,10 +201,11 @@
         mWindowController = controller;
 
         mMode = getInitialMode();
-        
+
         mKeyguardScreenCallback = new KeyguardScreenCallback() {
 
             public void goToLockScreen() {
+                mForgotPattern = false;
                 if (mIsVerifyUnlockOnly) {
                     // navigating away from unlock screen during verify mode means
                     // we are done and the user failed to authenticate.
@@ -197,6 +230,13 @@
                 }
             }
 
+            public void forgotPattern(boolean isForgotten) {
+                if (mEnableFallback) {
+                    mForgotPattern = isForgotten;
+                    updateScreen(Mode.UnlockScreen);
+                }
+            }
+
             public boolean isSecure() {
                 return LockPatternKeyguardView.this.isSecure();
             }
@@ -235,11 +275,11 @@
             public void reportFailedPatternAttempt() {
                 mUpdateMonitor.reportFailedAttempt();
                 final int failedAttempts = mUpdateMonitor.getFailedAttempts();
-                if (mHasAccount && failedAttempts ==
-                        (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET 
+                if (mEnableFallback && failedAttempts ==
+                        (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
                                 - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
                     showAlmostAtAccountLoginDialog();
-                } else if (mHasAccount
+                } else if (mEnableFallback
                         && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
                     mLockPatternUtils.setPermanentlyLocked(true);
                     updateScreen(mMode);
@@ -248,9 +288,9 @@
                     showTimeoutDialog();
                 }
             }
-            
+
             public boolean doesFallbackUnlockScreenExist() {
-                return mHasAccount;
+                return mEnableFallback;
             }
         };
 
@@ -262,9 +302,11 @@
         setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
 
         // wall paper background
-        final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper();
-        setBackgroundDrawable(
-                new FastBitmapDrawable(drawable.getBitmap()));
+        if (false) {
+            final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper();
+            setBackgroundDrawable(
+                    new FastBitmapDrawable(drawable.getBitmap()));
+        }
 
         // create both the lock and unlock screen so they are quickly available
         // when the screen turns on
@@ -277,45 +319,18 @@
         updateScreen(mMode);
     }
 
-    /** 
-     * Asynchronously checks for at least one account. This will set mHasAccount
-     * to true if an account is found.
-     */
-    private void asyncCheckForAccount() {
-        
-        mServiceConnection = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className, IBinder service) {
-                try {
-                    IAccountsService accountsService = IAccountsService.Stub.asInterface(service);
-                    String accounts[] = accountsService.getAccounts();
-                    mHasAccount = (accounts.length > 0);
-                } catch (RemoteException e) {
-                    // Not much we can do here...
-                    Log.e(TAG, "Gls died while attempting to get accounts: " + e);
-                } finally {
-                    getContext().unbindService(mServiceConnection);
-                    mServiceConnection = null;
-                }
-            }
-
-            public void onServiceDisconnected(ComponentName className) {
-                // nothing to do here
-            }
-        };
-        boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT,
-                mServiceConnection, Context.BIND_AUTO_CREATE);
-        if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account");
-    }
 
     @Override
     public void reset() {
         mIsVerifyUnlockOnly = false;
+        mForgotPattern = false;
         updateScreen(getInitialMode());
     }
 
     @Override
     public void onScreenTurnedOff() {
         mScreenOn = false;
+        mForgotPattern = false;
         if (mMode == Mode.LockScreen) {
            ((KeyguardScreen) mLockScreen).onPause();
         } else {
@@ -423,7 +438,7 @@
         // do this before changing visibility so focus isn't requested before the input
         // flag is set
         mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
-        
+
 
         if (mScreenOn) {
             if (goneScreen.getVisibility() == View.VISIBLE) {
@@ -454,12 +469,14 @@
 
     View createUnlockScreenFor(UnlockMode unlockMode) {
         if (unlockMode == UnlockMode.Pattern) {
-            return new UnlockScreen(
+            UnlockScreen view = new UnlockScreen(
                     mContext,
                     mLockPatternUtils,
                     mUpdateMonitor,
                     mKeyguardScreenCallback,
                     mUpdateMonitor.getFailedAttempts());
+            view.setEnableFallback(mEnableFallback);
+            return view;
         } else if (unlockMode == UnlockMode.SimPin) {
             return new SimUnlockScreen(
                     mContext,
@@ -525,7 +542,7 @@
         final IccCard.State simState = mUpdateMonitor.getSimState();
         if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) {
             return Mode.LockScreen;
-        } else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) {
+        } else if (isSecure()) {
             return Mode.UnlockScreen;
         } else {
             return Mode.LockScreen;
@@ -540,7 +557,7 @@
         if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) {
             return UnlockMode.SimPin;
         } else {
-            return mLockPatternUtils.isPermanentlyLocked() ?
+            return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ?
                     UnlockMode.Account:
                     UnlockMode.Pattern;
         }
@@ -558,9 +575,12 @@
                 .setNeutralButton(R.string.ok, null)
                 .create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        dialog.getWindow().setFlags(
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        if (!mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_sf_slowBlur)) {
+            dialog.getWindow().setFlags(
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        }
         dialog.show();
     }
 
@@ -578,15 +598,20 @@
                 .setNeutralButton(R.string.ok, null)
                 .create();
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        dialog.getWindow().setFlags(
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        if (!mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_sf_slowBlur)) {
+            dialog.getWindow().setFlags(
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        }
         dialog.show();
     }
 
     /**
-     * Used to put wallpaper on the background of the lock screen.  Centers it Horizontally and
-     * vertically.
+     * Used to put wallpaper on the background of the lock screen.  Centers it
+     * Horizontally and pins the bottom (assuming that the lock screen is aligned
+     * with the bottom, so the wallpaper should extend above the top into the
+     * status bar).
      */
     static private class FastBitmapDrawable extends Drawable {
         private Bitmap mBitmap;
@@ -602,7 +627,7 @@
             canvas.drawBitmap(
                     mBitmap,
                     (getBounds().width() - mBitmap.getWidth()) / 2,
-                    (getBounds().height() - mBitmap.getHeight()) / 2,
+                    (getBounds().height() - mBitmap.getHeight()),
                     null);
         }
 
diff --git a/phone/com/android/internal/policy/impl/LockScreen.java b/phone/com/android/internal/policy/impl/LockScreen.java
index 0495a76..dda5097 100644
--- a/phone/com/android/internal/policy/impl/LockScreen.java
+++ b/phone/com/android/internal/policy/impl/LockScreen.java
@@ -18,21 +18,26 @@
 
 import com.android.internal.R;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.RotarySelector;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.text.format.DateFormat;
-import android.text.TextUtils;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
+import android.widget.*;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.media.AudioManager;
+import android.os.SystemProperties;
+
 import com.android.internal.telephony.IccCard;
 
 import java.util.Date;
+import java.io.File;
+import java.text.SimpleDateFormat;
 
 /**
  * The screen within {@link LockPatternKeyguardView} that shows general
@@ -40,40 +45,28 @@
  * past it, as applicable.
  */
 class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback,
-        KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback {
+        KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback,
+        RotarySelector.OnDialTriggerListener {
+
+    private static final boolean DBG = false;
+    private static final String TAG = "LockScreen";
+    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
+
+    private Status mStatus = Status.Normal;
+
     private final LockPatternUtils mLockPatternUtils;
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final KeyguardScreenCallback mCallback;
 
-    private TextView mHeaderSimOk1;
-    private TextView mHeaderSimOk2;
-
-    private TextView mHeaderSimBad1;
-    private TextView mHeaderSimBad2;
-
+    private TextView mCarrier;
+    private RotarySelector mRotary;
     private TextView mTime;
     private TextView mDate;
-
-    private ViewGroup mBatteryInfoGroup;
-    private ImageView mBatteryInfoIcon;
-    private TextView mBatteryInfoText;
-    private View mBatteryInfoSpacer;
-
-    private ViewGroup mNextAlarmGroup;
-    private TextView mAlarmText;
-    private View mAlarmSpacer;
-
-    private ViewGroup mScreenLockedMessageGroup;
-
-    private TextView mLockInstructions;
-
+    private TextView mStatus1;
+    private TextView mStatus2;
+    private TextView mScreenLocked;
     private Button mEmergencyCallButton;
 
-    /**
-     * false means sim is missing or PUK'd
-     */
-    private boolean mSimOk = true;
-
     // are we showing battery information?
     private boolean mShowingBatteryInfo = false;
 
@@ -83,10 +76,83 @@
     // last known battery level
     private int mBatteryLevel = 100;
 
+    private String mNextAlarm = null;
+    private Drawable mAlarmIcon = null;
+    private String mCharging = null;
+    private Drawable mChargingIcon = null;
 
-    private View[] mOnlyVisibleWhenSimOk;
+    private boolean mSilentMode;
+    private AudioManager mAudioManager;
+    private java.text.DateFormat mDateFormat;
+    private java.text.DateFormat mTimeFormat;
+    private boolean mCreatedInPortrait;
+    private boolean mEnableMenuKeyInLockScreen;
 
-    private View[] mOnlyVisibleWhenSimNotOk;
+    /**
+     * The status of this lock screen.
+     */
+    enum Status {
+        /**
+         * Normal case (sim card present, it's not locked)
+         */
+        Normal(true),
+
+        /**
+         * The sim card is 'network locked'.
+         */
+        NetworkLocked(true),
+
+        /**
+         * The sim card is missing.
+         */
+        SimMissing(false),
+
+        /**
+         * The sim card is missing, and this is the device isn't provisioned, so we don't let
+         * them get past the screen.
+         */
+        SimMissingLocked(false),
+
+        /**
+         * The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many
+         * times.
+         */
+        SimPukLocked(false),
+
+        /**
+         * The sim card is locked.
+         */
+        SimLocked(true);
+
+        private final boolean mShowStatusLines;
+
+        Status(boolean mShowStatusLines) {
+            this.mShowStatusLines = mShowStatusLines;
+        }
+
+        /**
+         * @return Whether the status lines (battery level and / or next alarm) are shown while
+         *         in this state.  Mostly dictated by whether this is room for them.
+         */
+        public boolean showStatusLines() {
+            return mShowStatusLines;
+        }
+    }
+
+    /**
+     * In general, we enable unlocking the insecure key guard with the menu key. However, there are
+     * some cases where we wish to disable it, notably when the menu button placement or technology
+     * is prone to false positives.
+     *
+     * @return true if the menu key should be enabled
+     */
+    private boolean shouldEnableMenuKey() {
+        final Resources res = getResources();
+        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
+        final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false);
+        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
+        return !configDisabled || isMonkey || fileOverride;
+    }
 
     /**
      * @param context Used to setup the view.
@@ -103,262 +169,391 @@
         mUpdateMonitor = updateMonitor;
         mCallback = callback;
 
+        mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
+
+        mCreatedInPortrait = updateMonitor.isInPortrait();
+
         final LayoutInflater inflater = LayoutInflater.from(context);
-        inflater.inflate(R.layout.keyguard_screen_lock, this, true);
+        if (mCreatedInPortrait) {
+            inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true);
+        } else {
+            inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true);
+        }
 
-        mSimOk = isSimOk(updateMonitor.getSimState());
-        mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
-        mPluggedIn = updateMonitor.isDevicePluggedIn();
-        mBatteryLevel = updateMonitor.getBatteryLevel();
-
-        mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1);
-        mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2);
-
-        mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1);
-        mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2);
-
+        mCarrier = (TextView) findViewById(R.id.carrier);
         mTime = (TextView) findViewById(R.id.time);
         mDate = (TextView) findViewById(R.id.date);
-
-        mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo);
-        mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon);
-        mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText);
-        mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer);
-
-        mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo);
-        mAlarmText = (TextView) findViewById(R.id.nextAlarmText);
-        mAlarmSpacer = findViewById(R.id.nextAlarmSpacer);
-
-        mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo);
-
-        mLockInstructions = (TextView) findViewById(R.id.lockInstructions);
+        mStatus1 = (TextView) findViewById(R.id.status1);
+        mStatus2 = (TextView) findViewById(R.id.status2);
 
         mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
-
+        mEmergencyCallButton.setText(R.string.lockscreen_emergency_call);
+        mScreenLocked = (TextView) findViewById(R.id.screenLocked);
+        mRotary = (RotarySelector) findViewById(R.id.rotary);
         mEmergencyCallButton.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 mCallback.takeEmergencyCallAction();
             }
         });
 
-        mOnlyVisibleWhenSimOk = new View[] {
-            mHeaderSimOk1,
-            mHeaderSimOk2,
-            mBatteryInfoGroup,
-            mBatteryInfoSpacer,
-            mNextAlarmGroup,
-            mAlarmSpacer,
-            mScreenLockedMessageGroup,
-            mLockInstructions
-        };
-
-        mOnlyVisibleWhenSimNotOk = new View[] {
-            mHeaderSimBad1,
-            mHeaderSimBad2,
-            mEmergencyCallButton
-        };
-
         setFocusable(true);
         setFocusableInTouchMode(true);
         setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
 
-        refreshBatteryDisplay();
-        refreshAlarmDisplay();
-        refreshTimeAndDateDisplay();
-        refreshUnlockIntructions();
-        refreshViewsWRTSimOk();
-        refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn());
-
         updateMonitor.registerInfoCallback(this);
         updateMonitor.registerSimStateCallback(this);
         updateMonitor.registerConfigurationChangeCallback(this);
+
+        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+        mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT;
+
+        mRotary.setOnDialTriggerListener(this);
+        mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock);
+        mRotary.setRightHandleResource(mSilentMode ?
+                R.drawable.ic_jog_dial_sound_off :
+                R.drawable.ic_jog_dial_sound_on);
+
+        resetStatusInfo(updateMonitor);
     }
 
+    private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) {
+        mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
+        mPluggedIn = updateMonitor.isDevicePluggedIn();
+        mBatteryLevel = updateMonitor.getBatteryLevel();
+
+        mStatus = getCurrentStatus(updateMonitor.getSimState());
+        updateLayout(mStatus);
+
+        refreshBatteryStringAndIcon();
+        refreshAlarmDisplay();
+
+        mTimeFormat = DateFormat.getTimeFormat(getContext());
+        mDateFormat = getLockScreenDateFormat();
+        refreshTimeAndDateDisplay();
+        updateStatusLines();
+    }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_MENU) {
+        if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) {
             mCallback.goToUnlockScreen();
         }
         return false;
     }
 
-    private void refreshViewsWRTSimOk() {
-        if (mSimOk) {
-            for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
-                final View view = mOnlyVisibleWhenSimOk[i];
-                if (view == null) throw new RuntimeException("index " + i + " null");
-                view.setVisibility(View.VISIBLE);
-            }
-            for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
-                final View view = mOnlyVisibleWhenSimNotOk[i];
-                view.setVisibility(View.GONE);
-            }
-            refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), 
-                                    mUpdateMonitor.getTelephonySpn());
-            refreshAlarmDisplay();
-            refreshBatteryDisplay();
-        } else {
-            for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
-                final View view = mOnlyVisibleWhenSimOk[i];
-                view.setVisibility(View.GONE);
-            }
-            for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
-                final View view = mOnlyVisibleWhenSimNotOk[i];
-                view.setVisibility(View.VISIBLE);
-            }
-            refreshSimBadInfo();
+    /** {@inheritDoc} */
+    public void onDialTrigger(View v, int whichHandle) {
+        if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) {
+            mCallback.goToUnlockScreen();
+        } else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) {
+            // toggle silent mode
+            mSilentMode = !mSilentMode;
+            mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT
+                        : AudioManager.RINGER_MODE_NORMAL);
+            final int handleIcon = mSilentMode ?
+                    R.drawable.ic_jog_dial_sound_off :
+                    R.drawable.ic_jog_dial_sound_on;
+            final int toastIcon = mSilentMode ?
+                    R.drawable.ic_lock_ringer_off :
+                    R.drawable.ic_lock_ringer_on;
+            mRotary.setRightHandleResource(handleIcon);
+            String message = mSilentMode ?
+                    getContext().getString(R.string.global_action_silent_mode_on_status) :
+                    getContext().getString(R.string.global_action_silent_mode_off_status);
+            toastMessage(mScreenLocked, message, toastIcon);
+            mCallback.pokeWakelock();
         }
     }
 
-    private void refreshSimBadInfo() {
-        final IccCard.State simState = mUpdateMonitor.getSimState();
-        if (simState == IccCard.State.PUK_REQUIRED) {
-            mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message);
-            mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions);
-        } else if (simState == IccCard.State.ABSENT) {
-            mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message);
-            mHeaderSimBad2.setVisibility(View.GONE);
-            //mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions);
-        } else {
-            mHeaderSimBad1.setVisibility(View.GONE);
-            mHeaderSimBad2.setVisibility(View.GONE);
-        }
+    /** {@inheritDoc} */
+    public void onGrabbedStateChange(View v, int grabbedState) {
+        // TODO: Update onscreen hint text based on the new state.
     }
 
-    private void refreshUnlockIntructions() {
-        if (mLockPatternUtils.isLockPatternEnabled()
-                || mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED
-                || mUpdateMonitor.getSimState() == IccCard.State.ABSENT) {
-            mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled);
-        } else {
-            mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled);
+    /**
+     * Displays a message in a text view and then removes it.
+     * @param textView The text view.
+     * @param text The text.
+     * @param iconResourceId The left hand icon.
+     */
+    private void toastMessage(final TextView textView, final String text, final int iconResourceId) {
+        if (mPendingR1 != null) {
+            textView.removeCallbacks(mPendingR1);
+            mPendingR1 = null;
         }
+        if (mPendingR2 != null) {
+            textView.removeCallbacks(mPendingR2);
+            mPendingR2 = null;
+        }
+
+        mPendingR1 = new Runnable() {
+            public void run() {
+                textView.setText(text);
+                textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0);
+                textView.setCompoundDrawablePadding(4);
+            }
+        };
+        textView.postDelayed(mPendingR1, 0);
+        mPendingR2 = new Runnable() {
+            public void run() {
+                textView.setText("");
+                textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+            }
+        };
+        textView.postDelayed(mPendingR2, 3500);
     }
+    private Runnable mPendingR1;
+    private Runnable mPendingR2;
+
 
     private void refreshAlarmDisplay() {
-        final String nextAlarmText = mLockPatternUtils.getNextAlarm();
-
-        // bug 1685880: if we are in landscape and showing plmn, the information can end up not
-        // fitting on screen.  in this case, the alarm will get cut.
-        final CharSequence plmn = mUpdateMonitor.getTelephonyPlmn();
-        final boolean showingPlmn = plmn != null && !TextUtils.isEmpty(plmn);
-        final boolean wontFit = !mUpdateMonitor.isInPortrait() && showingPlmn;
-        if (nextAlarmText != null && mSimOk && !wontFit) {
-            setAlarmInfoVisible(true);
-            mAlarmText.setText(nextAlarmText);
-        } else {
-            setAlarmInfoVisible(false);
+        mNextAlarm = mLockPatternUtils.getNextAlarm();
+        if (mNextAlarm != null) {
+            mAlarmIcon = getContext().getResources().getDrawable(R.drawable.ic_lock_idle_alarm);
         }
+        updateStatusLines();
     }
 
-    private void setAlarmInfoVisible(boolean visible) {
-        final int visibilityFlag = visible ? View.VISIBLE : View.GONE;
-        mNextAlarmGroup.setVisibility(visibilityFlag);
-        mAlarmSpacer.setVisibility(visibilityFlag);
-    }
-
-
+    /** {@inheritDoc} */
     public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
             int batteryLevel) {
+        if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")");
         mShowingBatteryInfo = showBatteryInfo;
         mPluggedIn = pluggedIn;
         mBatteryLevel = batteryLevel;
 
-        refreshBatteryDisplay();
+        refreshBatteryStringAndIcon();
+        updateStatusLines();
     }
 
-    private void refreshBatteryDisplay() {
-        if (!mShowingBatteryInfo || !mSimOk) {
-            mBatteryInfoGroup.setVisibility(View.GONE);
-            mBatteryInfoSpacer.setVisibility(View.GONE);
+    private void refreshBatteryStringAndIcon() {
+        if (!mShowingBatteryInfo) {
+            mCharging = null;
             return;
         }
-        mBatteryInfoGroup.setVisibility(View.VISIBLE);
-        mBatteryInfoSpacer.setVisibility(View.VISIBLE);
+
+        if (mChargingIcon == null) {
+            mChargingIcon =
+                    getContext().getResources().getDrawable(R.drawable.ic_lock_idle_charging);
+        }
 
         if (mPluggedIn) {
-            mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging);
             if (mBatteryLevel >= 100) {
-                mBatteryInfoText.setText(R.string.lockscreen_charged);
+                mCharging = getContext().getString(R.string.lockscreen_charged);
             } else {
-                mBatteryInfoText.setText(
-                        getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel));
+                mCharging = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel);
             }
         } else {
-            mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery);
-            mBatteryInfoText.setText(R.string.lockscreen_low_battery);
+            mCharging = getContext().getString(R.string.lockscreen_low_battery);
         }
     }
 
+    /** {@inheritDoc} */
     public void onTimeChanged() {
         refreshTimeAndDateDisplay();
     }
 
     private void refreshTimeAndDateDisplay() {
         Date now = new Date();
-        mTime.setText(DateFormat.getTimeFormat(getContext()).format(now));
-        mDate.setText(DateFormat.getDateFormat(getContext()).format(now));
+        mTime.setText(mTimeFormat.format(now));
+        mDate.setText(mDateFormat.format(now));
     }
 
+    /**
+     * @return A localized format like "Fri, Sep 18, 2009"
+     */
+    private java.text.DateFormat getLockScreenDateFormat() {
+        SimpleDateFormat adjusted = null;
+        try {
+            // this call gives us the localized order
+            final SimpleDateFormat dateFormat = (SimpleDateFormat)
+                    java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL);
+            adjusted = new SimpleDateFormat(dateFormat.toPattern()
+                    .replace("MMMM", "MMM")    // we want "Sep", not "September"
+                    .replace("EEEE", "EEE"));  // we want "Fri", no "Friday"
+        } catch (ClassCastException e) {
+            // in case the library implementation changes and this throws a class cast exception
+            // or anything else that is funky
+            Log.e("LockScreen", "couldn't finnagle our custom date format :(", e);
+            return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM);
+        }
+        return adjusted;
+    }
+
+    private void updateStatusLines() {
+        if (!mStatus.showStatusLines()
+                || (mCharging == null && mNextAlarm == null)) {
+            mStatus1.setVisibility(View.INVISIBLE);
+            mStatus2.setVisibility(View.INVISIBLE);
+        } else if (mCharging != null && mNextAlarm == null) {
+            // charging only
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatus2.setVisibility(View.INVISIBLE);
+
+            mStatus1.setText(mCharging);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
+        } else if (mNextAlarm != null && mCharging == null) {
+            // next alarm only
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatus2.setVisibility(View.INVISIBLE);
+
+            mStatus1.setText(mNextAlarm);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
+        } else if (mCharging != null && mNextAlarm != null) {
+            // both charging and next alarm
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatus2.setVisibility(View.VISIBLE);
+
+            mStatus1.setText(mCharging);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
+            mStatus2.setText(mNextAlarm);
+            mStatus2.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
+        }
+    }
+
+    /** {@inheritDoc} */
     public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
-        refreshSimOkHeaders(plmn, spn);
-        refreshAlarmDisplay();  // in case alarm won't fit anymore
+        if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")");
+        updateLayout(mStatus);
     }
 
-    private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) {
-        final IccCard.State simState = mUpdateMonitor.getSimState();
-        if (simState == IccCard.State.READY) {
-            if (plmn != null && !TextUtils.isEmpty(plmn)) {
-                mHeaderSimOk1.setVisibility(View.VISIBLE);
-                mHeaderSimOk1.setText(plmn);
-            } else {
-                mHeaderSimOk1.setVisibility(View.GONE);
-            }
+    private void putEmergencyBelow(int viewId) {
+        final RelativeLayout.LayoutParams layoutParams =
+                (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams();
+        layoutParams.addRule(RelativeLayout.BELOW, viewId);
+        mEmergencyCallButton.setLayoutParams(layoutParams);
+    }
 
-            if (spn != null && !TextUtils.isEmpty(spn)) {
-                mHeaderSimOk2.setVisibility(View.VISIBLE);
-                mHeaderSimOk2.setText(spn);
-            } else {
-                mHeaderSimOk2.setVisibility(View.GONE);
-            }
-        } else if (simState == IccCard.State.PIN_REQUIRED) {
-            mHeaderSimOk1.setVisibility(View.VISIBLE);
-            mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message);
-            mHeaderSimOk2.setVisibility(View.GONE);
-        } else if (simState == IccCard.State.ABSENT) {
-            mHeaderSimOk1.setVisibility(View.VISIBLE);
-            mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short);
-            mHeaderSimOk2.setVisibility(View.GONE);
-        } else if (simState == IccCard.State.NETWORK_LOCKED) {
-            mHeaderSimOk1.setVisibility(View.VISIBLE);
-            mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message);
-            mHeaderSimOk2.setVisibility(View.GONE);
+    /**
+     * Determine the current status of the lock screen given the sim state and other stuff.
+     */
+    private Status getCurrentStatus(IccCard.State simState) {
+        boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
+                && simState == IccCard.State.ABSENT);
+        if (missingAndNotProvisioned) {
+            return Status.SimMissingLocked;
+        }
+
+        switch (simState) {
+            case ABSENT:
+                return Status.SimMissing;
+            case NETWORK_LOCKED:
+                return Status.SimMissingLocked;
+            case NOT_READY:
+                return Status.SimMissing;
+            case PIN_REQUIRED:
+                return Status.SimLocked;
+            case PUK_REQUIRED:
+                return Status.SimPukLocked;
+            case READY:
+                return Status.Normal;
+            case UNKNOWN:
+                return Status.SimMissing;
+        }
+        return Status.SimMissing;
+    }
+
+    /**
+     * Update the layout to match the current status.
+     */
+    private void updateLayout(Status status) {
+        switch (status) {
+            case Normal:
+                // text
+                mCarrier.setText(
+                        getCarrierString(
+                                mUpdateMonitor.getTelephonyPlmn(),
+                                mUpdateMonitor.getTelephonySpn()));
+//                mScreenLocked.setText(R.string.lockscreen_screen_locked);
+
+                // layout
+                mScreenLocked.setVisibility(View.VISIBLE);
+                mRotary.setVisibility(View.VISIBLE);
+                mEmergencyCallButton.setVisibility(View.GONE);
+                break;
+            case NetworkLocked:
+                //  text
+                mCarrier.setText(R.string.lockscreen_network_locked_message);
+                mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled);
+
+                // layout
+                mScreenLocked.setVisibility(View.VISIBLE);
+                mRotary.setVisibility(View.VISIBLE);
+                mEmergencyCallButton.setVisibility(View.GONE);
+                break;
+            case SimMissing:
+                // text
+                mCarrier.setText(R.string.lockscreen_missing_sim_message_short);
+                mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled);
+
+                // layout
+                mScreenLocked.setVisibility(View.INVISIBLE);
+                mRotary.setVisibility(View.VISIBLE);
+                mEmergencyCallButton.setVisibility(View.VISIBLE);
+                putEmergencyBelow(R.id.divider);
+                break;
+            case SimMissingLocked:
+                // text
+                mCarrier.setText(R.string.lockscreen_missing_sim_message_short);
+                mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions);
+
+                // layout
+                mScreenLocked.setVisibility(View.VISIBLE);
+                mRotary.setVisibility(View.GONE);
+                mEmergencyCallButton.setVisibility(View.VISIBLE);
+                putEmergencyBelow(R.id.screenLocked);
+                break;
+            case SimLocked:
+                // text
+                mCarrier.setText(R.string.lockscreen_sim_locked_message);
+
+                // layout
+                mScreenLocked.setVisibility(View.INVISIBLE);
+                mRotary.setVisibility(View.VISIBLE);
+                mEmergencyCallButton.setVisibility(View.GONE);
+                break;
+            case SimPukLocked:
+                // text
+                mCarrier.setText(R.string.lockscreen_sim_puk_locked_message);
+                mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions);
+
+                // layout
+                mScreenLocked.setVisibility(View.VISIBLE);
+                mRotary.setVisibility(View.GONE);
+                mEmergencyCallButton.setVisibility(View.VISIBLE);
+                putEmergencyBelow(R.id.screenLocked);
+                break;
+        }
+    }
+
+    static CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) {
+        if (telephonyPlmn != null && telephonySpn == null) {
+            return telephonyPlmn;
+        } else if (telephonyPlmn != null && telephonySpn != null) {
+            return telephonyPlmn + "\n" + telephonySpn;
+        } else if (telephonyPlmn == null && telephonySpn != null) {
+            return telephonySpn;
+        } else {
+            return "";
         }
     }
 
     public void onSimStateChanged(IccCard.State simState) {
-        mSimOk = isSimOk(simState);
-        refreshViewsWRTSimOk();
-        refreshUnlockIntructions();
+        if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")");
+        mStatus = getCurrentStatus(simState);
+        updateLayout(mStatus);
+        updateStatusLines();
     }
 
-    /**
-     * @return Whether the sim state is ok, meaning we don't need to show
-     *   a special screen with the emergency call button and keep them from
-     *   doing anything else.
-     */
-    private boolean isSimOk(IccCard.State simState) {
-        boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
-                && simState == IccCard.State.ABSENT);
-        return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED);
-    }
 
     public void onOrientationChange(boolean inPortrait) {
+        if (inPortrait != mCreatedInPortrait) {
+            mCallback.recreateMe();
+        }
     }
 
     public void onKeyboardChange(boolean isKeyboardOpen) {
-        if (isKeyboardOpen) {
+        if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
             mCallback.goToUnlockScreen();
         }
     }
@@ -376,7 +571,7 @@
 
     /** {@inheritDoc} */
     public void onResume() {
-
+        resetStatusInfo(mUpdateMonitor);
     }
 
     /** {@inheritDoc} */
@@ -384,4 +579,3 @@
         mUpdateMonitor.removeCallback(this);
     }
 }
-
diff --git a/phone/com/android/internal/policy/impl/PhoneWindow.java b/phone/com/android/internal/policy/impl/PhoneWindow.java
index 6341771..6dd5d93 100644
--- a/phone/com/android/internal/policy/impl/PhoneWindow.java
+++ b/phone/com/android/internal/policy/impl/PhoneWindow.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 
 import com.android.internal.view.menu.ContextMenuBuilder;
 import com.android.internal.view.menu.MenuBuilder;
@@ -34,7 +35,6 @@
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -124,6 +124,7 @@
      * this is 0, there is no key held down.
      */
     private int mPanelChordingKey;
+    private boolean mPanelMayLongPress;
 
     private ImageView mLeftIconView;
 
@@ -155,120 +156,6 @@
 
     private TelephonyManager mTelephonyManager = null;
     
-    private boolean mSearchKeyDownReceived;
-
-    private boolean mKeycodeCallTimeoutActive = false;
-
-    private boolean mKeycodeCameraTimeoutActive = false;
-
-    static final int MSG_MENU_LONG_PRESS = 1;
-    static final int MSG_MENU_LONG_PRESS_COMPLETE = 2;
-    static final int MSG_CALL_LONG_PRESS = 3;
-    static final int MSG_CALL_LONG_PRESS_COMPLETE = 4;
-    static final int MSG_CAMERA_LONG_PRESS = 5;
-    static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6;
-    static final int MSG_SEARCH_LONG_PRESS = 7;
-    static final int MSG_SEARCH_LONG_PRESS_COMPLETE = 8;
-
-    private final Handler mKeycodeMenuTimeoutHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_MENU_LONG_PRESS: {
-                    if (mPanelChordingKey == 0) return;
-                    // Before actually doing the long press, enqueue another
-                    // message and do the processing there.  This helps if
-                    // the app isn't being responsive, and finally woke up --
-                    // if the window manager wasn't told about it processing
-                    // the down key for too long, it would enqueue the key up
-                    // at a time after the timeout of this message.  So we go
-                    // through another message, to make sure we process an up
-                    // before continuing.
-                    mKeycodeMenuTimeoutHandler.sendEmptyMessage(
-                            MSG_MENU_LONG_PRESS_COMPLETE);
-                    break;
-                }
-                case MSG_CALL_LONG_PRESS: {
-                    if (!mKeycodeCallTimeoutActive) return;
-                    // See above.
-                    mKeycodeMenuTimeoutHandler.sendEmptyMessage(
-                            MSG_CALL_LONG_PRESS_COMPLETE);
-                    break;
-                }
-                case MSG_CAMERA_LONG_PRESS: {
-                    if (!mKeycodeCameraTimeoutActive) return;
-                    // See above.
-                    Message newMessage = Message.obtain(msg);
-                    newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE;
-                    mKeycodeMenuTimeoutHandler.sendMessage(newMessage);
-                    break;
-                }
-                case MSG_SEARCH_LONG_PRESS: {
-                    if (!mSearchKeyDownReceived) return;
-                    // See above.
-                    Message newMessage = Message.obtain(msg);
-                    newMessage.what = MSG_SEARCH_LONG_PRESS_COMPLETE;
-                    mKeycodeMenuTimeoutHandler.sendMessage(newMessage);
-                    break;
-                }
-                case MSG_MENU_LONG_PRESS_COMPLETE: {
-                    if (mPanelChordingKey == 0) return;
-                    mPanelChordingKey = 0;
-                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    InputMethodManager imm = (InputMethodManager)
-                            getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-                    if (imm != null) {
-                        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
-                    }
-                } break;
-                case MSG_CALL_LONG_PRESS_COMPLETE: {
-                    if (!mKeycodeCallTimeoutActive) return;
-                    mKeycodeCallTimeoutActive = false;
-                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    // launch the VoiceDialer
-                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        sendCloseSystemWindows();
-                        getContext().startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
-                        startCallActivity();
-                    }
-                } break;
-                case MSG_CAMERA_LONG_PRESS_COMPLETE: {
-                    if (!mKeycodeCameraTimeoutActive) return;
-                    mKeycodeCameraTimeoutActive = false;
-                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    sendCloseSystemWindows();
-                    // Broadcast an intent that the Camera button was longpressed
-                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
-                    intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj);
-                    getContext().sendOrderedBroadcast(intent, null);
-                } break;
-                case MSG_SEARCH_LONG_PRESS_COMPLETE: {
-                    if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
-                            !mSearchKeyDownReceived) {
-                        mSearchKeyDownReceived = false;
-                        return;
-                    }
-                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                    // launch the search activity
-                    Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        sendCloseSystemWindows();
-                        getContext().startActivity(intent);
-                        // Only clear this if we successfully start the
-                        // activity; otherwise we will allow the normal short
-                        // press action to be performed.
-                        mSearchKeyDownReceived = false;
-                    } catch (ActivityNotFoundException e) {
-                    }
-                } break;
-            }
-        }
-    };
-
     public PhoneWindow(Context context) {
         super(context);
         mLayoutInflater = LayoutInflater.from(context);
@@ -295,11 +182,9 @@
             /* Custom title feature is enabled and the user is trying to enable another feature */
             throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
         }
-        /*  FEATURE_OPENGL disabled for 1.0
         if (featureId == FEATURE_OPENGL) {
             getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU;
         }
-        */
         return super.requestFeature(featureId);
     }
 
@@ -567,7 +452,7 @@
 
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 WRAP_CONTENT, WRAP_CONTENT,
-                st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
+                st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
                 WindowManager.LayoutParams.FLAG_DITHER
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 st.decorView.mDefaultOpacity);
@@ -649,19 +534,35 @@
      * @return Whether the key was handled.
      */
     public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
-        // The panel key was pushed, so set the chording key
-        mPanelChordingKey = event.getKeyCode();
-
-        PanelFeatureState st = getPanelState(featureId, true);
-        if (!st.isOpen) {
-            if (getContext().getResources().getConfiguration().keyboard
-                    == Configuration.KEYBOARD_NOKEYS) {
-                mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
-                mKeycodeMenuTimeoutHandler.sendMessageDelayed(
-                        mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS),
-                        ViewConfiguration.getLongPressTimeout());
+        final int keyCode = event.getKeyCode();
+        
+        if (event.getRepeatCount() == 0) {
+            // The panel key was pushed, so set the chording key
+            mPanelChordingKey = keyCode;
+            mPanelMayLongPress = false;
+            
+            PanelFeatureState st = getPanelState(featureId, true);
+            if (!st.isOpen) {
+                if (getContext().getResources().getConfiguration().keyboard
+                        == Configuration.KEYBOARD_NOKEYS) {
+                    mPanelMayLongPress = true;
+                }
+                return preparePanel(st, event);
             }
-            return preparePanel(st, event);
+            
+        } else if (mPanelMayLongPress && mPanelChordingKey == keyCode
+                && (event.getFlags()&KeyEvent.FLAG_LONG_PRESS) != 0) {
+            // We have had a long press while in a state where this
+            // should be executed...  do it!
+            mPanelChordingKey = 0;
+            mPanelMayLongPress = false;
+            InputMethodManager imm = (InputMethodManager)
+                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            if (imm != null) {
+                mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
+            }
+            
         }
 
         return false;
@@ -676,8 +577,12 @@
         // The panel key was released, so clear the chording key
         if (mPanelChordingKey != 0) {
             mPanelChordingKey = 0;
-            mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
+            mPanelMayLongPress = false;
 
+            if (event.isCanceled()) {
+                return;
+            }
+            
             boolean playSoundEffect = false;
             PanelFeatureState st = getPanelState(featureId, true);
             if (st.isOpen || st.isHandled) {
@@ -1214,6 +1119,11 @@
      * @see android.view.KeyEvent
      */
     protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
+        final KeyEvent.DispatcherState dispatcher =
+                mDecor != null ? mDecor.getKeyDispatcherState() : null;
+        //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
+        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
+        
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN: {
@@ -1260,21 +1170,25 @@
             }
 
             case KeyEvent.KEYCODE_CAMERA: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()
+                        || dispatcher == null) {
                     break;
                 }
-                if (event.getRepeatCount() > 0) break;
-                mKeycodeCameraTimeoutActive = true;
-                mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
-                Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS);
-                message.obj = event;
-                mKeycodeMenuTimeoutHandler.sendMessageDelayed(message,
-                        ViewConfiguration.getLongPressTimeout());
+                if (event.getRepeatCount() == 0) {
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+                    dispatcher.performedLongPress(event);
+                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                    sendCloseSystemWindows();
+                    // Broadcast an intent that the Camera button was longpressed
+                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+                    getContext().sendOrderedBroadcast(intent, null);
+                }
                 return true;
             }
 
             case KeyEvent.KEYCODE_MENU: {
-                if (event.getRepeatCount() > 0) break;
                 onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
                 return true;
             }
@@ -1282,48 +1196,61 @@
             case KeyEvent.KEYCODE_BACK: {
                 if (event.getRepeatCount() > 0) break;
                 if (featureId < 0) break;
-                if (featureId == FEATURE_OPTIONS_PANEL) {
-                    PanelFeatureState st = getPanelState(featureId, false);
-                    if (st != null && st.isInExpandedMode) {
-                        // If the user is in an expanded menu and hits back, it
-                        // should go back to the icon menu
-                        reopenMenu(true);
-                        return true;
-                    }
-                }
-                closePanel(featureId);
+                // Currently don't do anything with long press.
+                dispatcher.startTracking(event, this);
                 return true;
             }
 
             case KeyEvent.KEYCODE_CALL: {
-                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()
+                        || dispatcher == null) {
                     break;
                 }
-                if (event.getRepeatCount() > 0) break;
-                mKeycodeCallTimeoutActive = true;
-                mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
-                mKeycodeMenuTimeoutHandler.sendMessageDelayed(
-                        mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS),
-                        ViewConfiguration.getLongPressTimeout());
+                if (event.getRepeatCount() == 0) {
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
+                    dispatcher.performedLongPress(event);
+                    mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                    // launch the VoiceDialer
+                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    try {
+                        sendCloseSystemWindows();
+                        getContext().startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        startCallActivity();
+                    }
+                }
                 return true;
             }
 
             case KeyEvent.KEYCODE_SEARCH: {
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()
+                        || dispatcher == null) {
+                    break;
+                }
                 if (event.getRepeatCount() == 0) {
-                    mSearchKeyDownReceived = true;
+                    dispatcher.startTracking(event, this);
+                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
                     Configuration config = getContext().getResources().getConfiguration(); 
                     if (config.keyboard == Configuration.KEYBOARD_NOKEYS
-                            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
-                        // If this device does not have a hardware keyboard,
-                        // or that keyboard is hidden, then we can't use the
-                        // search key for chording to perform shortcuts;
-                        // instead, we will let the user long press,
-                        mKeycodeMenuTimeoutHandler.removeMessages(MSG_SEARCH_LONG_PRESS);
-                        mKeycodeMenuTimeoutHandler.sendMessageDelayed(
-                                mKeycodeMenuTimeoutHandler.obtainMessage(MSG_SEARCH_LONG_PRESS),
-                                ViewConfiguration.getLongPressTimeout());
+                            || config.hardKeyboardHidden
+                                    == Configuration.HARDKEYBOARDHIDDEN_YES) {
+                        // launch the search activity
+                        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        try {
+                            sendCloseSystemWindows();
+                            getContext().startActivity(intent);
+                            mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+                            // Only clear this if we successfully start the
+                            // activity; otherwise we will allow the normal short
+                            // press action to be performed.
+                            dispatcher.performedLongPress(event);
+                        } catch (ActivityNotFoundException e) {
+                            // Ignore
+                        }
                     }
-                    return true;
                 }
                 break;
             }
@@ -1349,6 +1276,14 @@
      * @see android.view.KeyEvent
      */
     protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
+        final KeyEvent.DispatcherState dispatcher =
+                mDecor != null ? mDecor.getKeyDispatcherState() : null;
+        if (dispatcher != null) {
+            dispatcher.handleUpEvent(event);
+        }
+        //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
+        //        + " flags=0x" + Integer.toHexString(event.getFlags()));
+        
         switch (keyCode) {
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN: {
@@ -1374,6 +1309,24 @@
                 return true;
             }
 
+            case KeyEvent.KEYCODE_BACK: {
+                if (featureId < 0) break;
+                if (event.isTracking() && !event.isCanceled()) {
+                    if (featureId == FEATURE_OPTIONS_PANEL) {
+                        PanelFeatureState st = getPanelState(featureId, false);
+                        if (st != null && st.isInExpandedMode) {
+                            // If the user is in an expanded menu and hits back, it
+                            // should go back to the icon menu
+                            reopenMenu(true);
+                            return true;
+                        }
+                    }
+                    closePanel(featureId);
+                    return true;
+                }
+                break;
+            }
+
             case KeyEvent.KEYCODE_HEADSETHOOK:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_STOP:
@@ -1391,11 +1344,9 @@
                 if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
                     break;
                 }
-                if (event.getRepeatCount() > 0) break; // Can a key up event repeat?
-                mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
-                if (!mKeycodeCameraTimeoutActive) break;
-                mKeycodeCameraTimeoutActive = false;
-                // Add short press behavior here if desired
+                if (event.isTracking() && !event.isCanceled()) {
+                    // Add short press behavior here if desired
+                }
                 return true;
             }
 
@@ -1403,11 +1354,9 @@
                 if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
                     break;
                 }
-                if (event.getRepeatCount() > 0) break;
-                mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
-                if (!mKeycodeCallTimeoutActive) break;
-                mKeycodeCallTimeoutActive = false;
-                startCallActivity();
+                if (event.isTracking() && !event.isCanceled()) {
+                    startCallActivity();
+                }
                 return true;
             }
 
@@ -1416,13 +1365,12 @@
                  * Do this in onKeyUp since the Search key is also used for
                  * chording quick launch shortcuts.
                  */
-                if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
-                        !mSearchKeyDownReceived) {
-                    mSearchKeyDownReceived = false;
+                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
                     break;
                 }
-                mSearchKeyDownReceived = false;
-                launchDefaultSearch();
+                if (event.isTracking() && !event.isCanceled()) {
+                    launchDefaultSearch();
+                }
                 return true;
             }
         }
@@ -1584,9 +1532,11 @@
         PanelFeatureState st;
         for (int i = panels.length - 1; i >= 0; i--) {
             st = panels[i];
-            if ((st != null) && st.isOpen) {
-                // Clear st.isOpen (openPanel will not open if it's already open)
-                st.isOpen = false;
+            // We restore the panel if it was last open; we skip it if it
+            // now is open, to avoid a race condition if the user immediately
+            // opens it when we are resuming.
+            if ((st != null) && !st.isOpen && st.wasLastOpen) {
+                st.isInExpandedMode = st.wasLastExpanded;
                 openPanel(st, null);
             }
         }
@@ -1606,8 +1556,6 @@
 
         private final Rect mFrameOffsets = new Rect();
 
-        private final Paint mBlackPaint = new Paint();
-
         private boolean mChanging;
 
         private Drawable mMenuBackground;
@@ -1617,7 +1565,6 @@
         public DecorView(Context context, int featureId) {
             super(context);
             mFeatureId = featureId;
-            mBlackPaint.setColor(0xFF000000);
         }
 
         @Override
@@ -2009,16 +1956,11 @@
         public void onWindowFocusChanged(boolean hasWindowFocus) {
             super.onWindowFocusChanged(hasWindowFocus);
 
-            // no KEYCODE_CALL events active across focus changes
-            mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
-            mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
-            mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
-            mKeycodeCallTimeoutActive = false;
-            mKeycodeCameraTimeoutActive = false;
+            mPanelMayLongPress = false;
 
             // If the user is chording a menu shortcut, release the chord since
             // this window lost focus
-            if (!hasWindowFocus && mPanelChordingKey > 0) {
+            if (!hasWindowFocus && mPanelChordingKey != 0) {
                 closePanel(FEATURE_OPTIONS_PANEL);
             }
 
@@ -2031,6 +1973,11 @@
         @Override
         protected void onAttachedToWindow() {
             super.onAttachedToWindow();
+            
+            final Callback cb = getCallback();
+            if (cb != null && mFeatureId < 0) {
+                cb.onAttachedToWindow();
+            }
 
             if (mFeatureId == -1) {
                 /*
@@ -2043,6 +1990,23 @@
                 openPanelsAfterRestore();
             }
         }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            
+            final Callback cb = getCallback();
+            if (cb != null && mFeatureId < 0) {
+                cb.onDetachedFromWindow();
+            }
+        }
+        
+        @Override
+        public void onCloseSystemDialogs(String reason) {
+            if (mFeatureId >= 0) {
+                closeAllPanels();
+            }
+        }
     }
 
     protected DecorView generateDecor() {
@@ -2097,6 +2061,10 @@
             setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
         }
 
+        if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+            setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
+        }
+
         WindowManager.LayoutParams params = getAttributes();
 
         if (!hasSoftInputMode()) {
@@ -2606,6 +2574,10 @@
 
         boolean refreshDecorView;
 
+        boolean wasLastOpen;
+        
+        boolean wasLastExpanded;
+        
         /**
          * Contains the state of the menu when told to freeze.
          */
@@ -2654,8 +2626,8 @@
         void onRestoreInstanceState(Parcelable state) {
             SavedState savedState = (SavedState) state;
             featureId = savedState.featureId;
-            isOpen = savedState.isOpen;
-            isInExpandedMode = savedState.isInExpandedMode;
+            wasLastOpen = savedState.isOpen;
+            wasLastExpanded = savedState.isInExpandedMode;
             frozenMenuState = savedState.menuState;
 
             /*
diff --git a/phone/com/android/internal/policy/impl/PhoneWindowManager.java b/phone/com/android/internal/policy/impl/PhoneWindowManager.java
old mode 100644
new mode 100755
index 8140b3d..e57fbe8
--- a/phone/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/phone/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -20,17 +20,19 @@
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.IStatusBar;
+import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
-import android.content.ContentQueryMap;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Rect;
+import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.LocalPowerManager;
@@ -67,6 +69,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -88,8 +91,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicy.WindowState;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
 import android.media.IAudioService;
 import android.media.AudioManager;
 
@@ -108,29 +115,31 @@
     static final boolean SHOW_STARTING_ANIMATIONS = true;
     static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
     
-    static final int APPLICATION_LAYER = 1;
-    static final int PHONE_LAYER = 2;
-    static final int SEARCH_BAR_LAYER = 3;
-    static final int STATUS_BAR_PANEL_LAYER = 4;
+    // wallpaper is at the bottom, though the window manager may move it.
+    static final int WALLPAPER_LAYER = 2;
+    static final int APPLICATION_LAYER = 2;
+    static final int PHONE_LAYER = 3;
+    static final int SEARCH_BAR_LAYER = 4;
+    static final int STATUS_BAR_PANEL_LAYER = 5;
     // toasts and the plugged-in battery thing
-    static final int TOAST_LAYER = 5;
-    static final int STATUS_BAR_LAYER = 6;
+    static final int TOAST_LAYER = 6;
+    static final int STATUS_BAR_LAYER = 7;
     // SIM errors and unlock.  Not sure if this really should be in a high layer.
-    static final int PRIORITY_PHONE_LAYER = 7;
+    static final int PRIORITY_PHONE_LAYER = 8;
     // like the ANR / app crashed dialogs
-    static final int SYSTEM_ALERT_LAYER = 8;
+    static final int SYSTEM_ALERT_LAYER = 9;
     // system-level error dialogs
-    static final int SYSTEM_ERROR_LAYER = 9;
+    static final int SYSTEM_ERROR_LAYER = 10;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_LAYER = 10;
+    static final int INPUT_METHOD_LAYER = 11;
     // on-screen keyboards and other such input method user interfaces go here.
-    static final int INPUT_METHOD_DIALOG_LAYER = 11;
+    static final int INPUT_METHOD_DIALOG_LAYER = 12;
     // the keyguard; nothing on top of these can take focus, since they are
     // responsible for power management when displayed.
-    static final int KEYGUARD_LAYER = 12;
-    static final int KEYGUARD_DIALOG_LAYER = 13;
+    static final int KEYGUARD_LAYER = 13;
+    static final int KEYGUARD_DIALOG_LAYER = 14;
     // things in here CAN NOT take focus, but are shown on top of everything else.
-    static final int SYSTEM_OVERLAY_LAYER = 14;
+    static final int SYSTEM_OVERLAY_LAYER = 15;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -146,9 +155,6 @@
     static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
 
-    // Vibrator pattern for haptic feedback of a long press.
-    private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
-    
     final Object mLock = new Object();
     
     Context mContext;
@@ -156,6 +162,18 @@
     LocalPowerManager mPowerManager;
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
 
+    // Vibrator pattern for haptic feedback of a long press.
+    long[] mLongPressVibePattern;
+    
+    // Vibrator pattern for haptic feedback of virtual key press.
+    long[] mVirtualKeyVibePattern;
+    
+    // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
+    long[] mSafeModeDisabledVibePattern;
+    
+    // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
+    long[] mSafeModeEnabledVibePattern;
+    
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
     
@@ -168,7 +186,21 @@
     RecentApplicationsDialog mRecentAppsDialog;
     Handler mHandler;
 
+    final IntentFilter mBatteryStatusFilter = new IntentFilter();
+    
     boolean mLidOpen;
+    int mPlugged;
+    boolean mRegisteredBatteryReceiver;
+    int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    int mLidOpenRotation;
+    int mCarDockRotation;
+    int mDeskDockRotation;
+    int mCarDockKeepsScreenOn;
+    int mDeskDockKeepsScreenOn;
+    boolean mCarDockEnablesAccelerometer;
+    boolean mDeskDockEnablesAccelerometer;
+    int mLidKeyboardAccessibility;
+    int mLidNavigationAccessibility;
     boolean mScreenOn = false;
     boolean mOrientationSensorEnabled = false;
     int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -200,9 +232,12 @@
     
     WindowState mTopFullscreenOpaqueWindowState;
     boolean mForceStatusBar;
-    boolean mHideKeyguard;
+    boolean mHideLockScreen;
+    boolean mDismissKeyguard;
     boolean mHomePressed;
     Intent mHomeIntent;
+    Intent mCarDockIntent;
+    Intent mDeskDockIntent;
     boolean mSearchKeyPressed;
     boolean mConsumeSearchKeyUp;
 
@@ -219,6 +254,7 @@
 
     ShortcutManager mShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
+    PowerManager.WakeLock mDockWakeLock;
 
     class SettingsObserver extends ContentObserver {
         SettingsObserver(Handler handler) {
@@ -284,7 +320,7 @@
         @Override
         public void onOrientationChanged(int rotation) {
             // Send updates based on orientation value
-            if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation);
+            if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
             try {
                 mWindowManager.setRotation(rotation, false,
                         mFancyRotationAnimation);
@@ -297,14 +333,27 @@
     MyOrientationListener mOrientationListener;
 
     boolean useSensorForOrientationLp(int appOrientation) {
+        // The app says use the sensor.
         if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
             return true;
         }
-        if (mAccelerometerDefault != 0 && (
-                appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
-                appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
+        // The user preference says we can rotate, and the app is willing to rotate.
+        if (mAccelerometerDefault != 0 &&
+                (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
+                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
             return true;
         }
+        // We're in a dock that has a rotation affinity, an the app is willing to rotate.
+        if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR)
+                || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) {
+            // Note we override the nosensor flag here.
+            if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
+                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+                return true;
+            }
+        }
+        // Else, don't use the sensor.
         return false;
     }
     
@@ -319,6 +368,12 @@
             // orientation, then we need to turn the sensor or.
             return true;
         }
+        if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) ||
+            (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) {
+            // enable accelerometer if we are docked in a dock that enables accelerometer
+            // orientation management,
+            return true;
+        }
         if (mAccelerometerDefault == 0) {
             // If the setting for using the sensor by default is enabled, then
             // we will always leave it on.  Note that the user could go to
@@ -350,7 +405,7 @@
         }
         //Could have been invoked due to screen turning on or off or
         //change of the currently visible window's orientation
-        if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+
+        if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+
                 ", current orientation="+mCurrentAppOrientation+
                 ", SensorEnabled="+mOrientationSensorEnabled);
         boolean disable = true;
@@ -360,7 +415,7 @@
                 //enable listener if not already enabled
                 if (!mOrientationSensorEnabled) {
                     mOrientationListener.enable();
-                    if(localLOGV) Log.i(TAG, "Enabling listeners");
+                    if(localLOGV) Log.v(TAG, "Enabling listeners");
                     mOrientationSensorEnabled = true;
                 }
             } 
@@ -368,12 +423,12 @@
         //check if sensors need to be disabled
         if (disable && mOrientationSensorEnabled) {
             mOrientationListener.disable();
-            if(localLOGV) Log.i(TAG, "Disabling listeners");
+            if(localLOGV) Log.v(TAG, "Disabling listeners");
             mOrientationSensorEnabled = false;
         }
     }
 
-    Runnable mEndCallLongPress = new Runnable() {
+    Runnable mPowerLongPress = new Runnable() {
         public void run() {
             mShouldTurnOffOnKeyUp = false;
             performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
@@ -443,10 +498,81 @@
         mHomeIntent.addCategory(Intent.CATEGORY_HOME);
         mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
+        mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
+        mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        mDeskDockIntent =  new Intent(Intent.ACTION_MAIN, null);
+        mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
+        mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "PhoneWindowManager.mBroadcastWakeLock");
+        mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
+                "PhoneWindowManager.mDockWakeLock");
+        mDockWakeLock.setReferenceCounted(false);
         mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
+        mLidOpenRotation = readRotation(
+                com.android.internal.R.integer.config_lidOpenRotation);
+        mCarDockRotation = readRotation(
+                com.android.internal.R.integer.config_carDockRotation);
+        mDeskDockRotation = readRotation(
+                com.android.internal.R.integer.config_deskDockRotation);
+        mCarDockKeepsScreenOn = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_carDockKeepsScreenOn);
+        mDeskDockKeepsScreenOn = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_deskDockKeepsScreenOn);
+        mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
+        mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
+        mLidKeyboardAccessibility = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lidKeyboardAccessibility);
+        mLidNavigationAccessibility = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_lidNavigationAccessibility);
+        // register for battery events
+        mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        mPlugged = 0;
+        updatePlugged(context.registerReceiver(null, mBatteryStatusFilter));
+        // register for dock events
+        context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+        mVibrator = new Vibrator();
+        mLongPressVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_longPressVibePattern);
+        mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_virtualKeyVibePattern);
+        mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_safeModeDisabledVibePattern);
+        mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
+                com.android.internal.R.array.config_safeModeEnabledVibePattern);
+    }
+
+    void updatePlugged(Intent powerIntent) {
+        if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras());
+        if (powerIntent != null) {
+            mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+            if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged);
+        }
+    }
+    
+    private int readRotation(int resID) {
+        try {
+            int rotation = mContext.getResources().getInteger(resID);
+            switch (rotation) {
+                case 0:
+                    return Surface.ROTATION_0;
+                case 90:
+                    return Surface.ROTATION_90;
+                case 180:
+                    return Surface.ROTATION_180;
+                case 270:
+                    return Surface.ROTATION_270;
+            }
+        } catch (Resources.NotFoundException e) {
+            // fall through
+        }
+        return -1;
     }
 
     /** {@inheritDoc} */
@@ -465,7 +591,8 @@
                 // monitor/control what they are doing.
                 break;
             case TYPE_INPUT_METHOD:
-                // The window manager will check this.
+            case TYPE_WALLPAPER:
+                // The window manager will check these.
                 break;
             case TYPE_PHONE:
             case TYPE_PRIORITY_PHONE:
@@ -499,7 +626,7 @@
     
     void readLidState() {
         try {
-            int sw = mWindowManager.getSwitchState(0);
+            int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID);
             if (sw >= 0) {
                 mLidOpen = sw == 0;
             }
@@ -508,17 +635,32 @@
         }
     }
     
+    private int determineHiddenState(boolean lidOpen,
+            int mode, int hiddenValue, int visibleValue) {
+        switch (mode) {
+            case 1:
+                return lidOpen ? visibleValue : hiddenValue;
+            case 2:
+                return lidOpen ? hiddenValue : visibleValue;
+        }
+        return visibleValue;
+    }
+    
     /** {@inheritDoc} */
     public void adjustConfigurationLw(Configuration config) {
         readLidState();
         final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
         mPowerManager.setKeyboardVisibility(lidOpen);
-        config.keyboardHidden = (lidOpen || mHasSoftInput)
-            ? Configuration.KEYBOARDHIDDEN_NO
-            : Configuration.KEYBOARDHIDDEN_YES;
-        config.hardKeyboardHidden = lidOpen
-            ? Configuration.KEYBOARDHIDDEN_NO
-            : Configuration.KEYBOARDHIDDEN_YES;
+        config.hardKeyboardHidden = determineHiddenState(lidOpen,
+                mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES,
+                Configuration.HARDKEYBOARDHIDDEN_NO);
+        config.navigationHidden = determineHiddenState(lidOpen,
+                mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES,
+                Configuration.NAVIGATIONHIDDEN_NO);
+        config.keyboardHidden = (config.hardKeyboardHidden
+                        == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput)
+                ? Configuration.KEYBOARDHIDDEN_NO
+                : Configuration.KEYBOARDHIDDEN_YES;
     }
     
     public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
@@ -566,6 +708,8 @@
             return PRIORITY_PHONE_LAYER;
         case TYPE_TOAST:
             return TOAST_LAYER;
+        case TYPE_WALLPAPER:
+            return WALLPAPER_LAYER;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return APPLICATION_LAYER;
@@ -588,6 +732,19 @@
         return 0;
     }
 
+    public int getMaxWallpaperLayer() {
+        return STATUS_BAR_LAYER;
+    }
+
+    public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
+        return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
+    }
+    
+    public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
+        return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
+                && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
+    }
+    
     /** {@inheritDoc} */
     public View addStartingWindow(IBinder appToken, String packageName,
                                   int theme, CharSequence nonLocalizedLabel,
@@ -756,6 +913,11 @@
         return 0;
     }
 
+    public Animation createForceHideEnterAnimation() {
+        return AnimationUtils.loadAnimation(mContext,
+                com.android.internal.R.anim.lock_screen_behind_enter);
+    }
+    
     static ITelephony getPhoneInterface() {
         return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
     }
@@ -775,7 +937,7 @@
 
     /** {@inheritDoc} */
     public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 
-            int repeatCount) {
+            int repeatCount, int flags) {
         boolean keyguardOn = keyguardOn();
 
         if (false) {
@@ -800,32 +962,36 @@
                 if (!down) {
                     mHomePressed = false;
                     
-                    // If an incoming call is ringing, HOME is totally disabled.
-                    // (The user is already on the InCallScreen at this point,
-                    // and his ONLY options are to answer or reject the call.)
-                    boolean incomingRinging = false;
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            incomingRinging = phoneServ.isRinging();
-                        } else {
-                            Log.w(TAG, "Unable to find ITelephony interface");
+                    if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
+                        // If an incoming call is ringing, HOME is totally disabled.
+                        // (The user is already on the InCallScreen at this point,
+                        // and his ONLY options are to answer or reject the call.)
+                        boolean incomingRinging = false;
+                        try {
+                            ITelephony phoneServ = getPhoneInterface();
+                            if (phoneServ != null) {
+                                incomingRinging = phoneServ.isRinging();
+                            } else {
+                                Log.w(TAG, "Unable to find ITelephony interface");
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
-                    }
-    
-                    if (incomingRinging) {
-                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+        
+                        if (incomingRinging) {
+                            Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+                        } else {
+                            launchHomeFromHotKey();
+                        }
                     } else {
-                        launchHomeFromHotKey();
+                        Log.i(TAG, "Ignoring HOME; event canceled.");
                     }
                 }
             }
             
             return true;
         }
-            
+        
         // First we always handle the home key here, so applications
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
@@ -942,9 +1108,9 @@
      * given the situation with the keyguard.
      */
     void launchHomeFromHotKey() {
-        if (mKeyguardMediator.isShowing()) {
+        if (!mHideLockScreen && mKeyguardMediator.isShowing()) {
             // don't launch home if keyguard showing
-        } else if (mKeyguardMediator.isInputRestricted()) {
+        } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
             // when in keyguard restricted mode, must first verify unlock
             // before launching home
             mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
@@ -955,7 +1121,7 @@
                         } catch (RemoteException e) {
                         }
                         sendCloseSystemWindows();
-                        mContext.startActivity(mHomeIntent);
+                        startDockOrHome();
                     }
                 }
             });
@@ -966,7 +1132,7 @@
             } catch (RemoteException e) {
             }
             sendCloseSystemWindows();
-            mContext.startActivity(mHomeIntent);
+            startDockOrHome();
         }
     }
 
@@ -994,7 +1160,8 @@
 
         mTopFullscreenOpaqueWindowState = null;
         mForceStatusBar = false;
-        mHideKeyguard = false;
+        mHideLockScreen = false;
+        mDismissKeyguard = false;
         
         // decide where the status bar goes ahead of time
         if (mStatusBar != null) {
@@ -1192,20 +1359,24 @@
         
         win.computeFrameLw(pf, df, cf, vf);
         
-        if (win.isVisibleLw()) {
+        if (mTopFullscreenOpaqueWindowState == null &&
+                win.isVisibleOrBehindKeyguardLw()) {
             if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
                 mForceStatusBar = true;
-            } else if (mTopFullscreenOpaqueWindowState == null
-                    && attrs.type >= FIRST_APPLICATION_WINDOW
+            } 
+            if (attrs.type >= FIRST_APPLICATION_WINDOW
                     && attrs.type <= LAST_APPLICATION_WINDOW
                     && win.fillsScreenLw(mW, mH, false, false)) {
                 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
+                if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+                    if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+                    mHideLockScreen = true;
+                }
             }
-            if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
-                // TODO Add a check for the window to be full screen
-                if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win);
-                mHideKeyguard = true;
+            if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
+                if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+                mDismissKeyguard = true;
             }
         }
         
@@ -1229,15 +1400,15 @@
     }
 
     /** {@inheritDoc} */
-    public boolean finishLayoutLw() {
-        boolean changed = false;
+    public int finishLayoutLw() {
+        int changes = 0;
         boolean hiding = false;
         if (mStatusBar != null) {
-            //Log.i(TAG, "force=" + mForceStatusBar
-            //        + " top=" + mTopFullscreenOpaqueWindowState);
+            if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar
+                    + " top=" + mTopFullscreenOpaqueWindowState);
             if (mForceStatusBar) {
                 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
-                changed |= mStatusBar.showLw(true);
+                if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
             } else if (mTopFullscreenOpaqueWindowState != null) {
                 //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
                 //        + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
@@ -1248,26 +1419,49 @@
                     (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
                 if (hideStatusBar) {
                     if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
-                    changed |= mStatusBar.hideLw(true);
+                    if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
                     hiding = true;
                 } else {
                     if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
-                    changed |= mStatusBar.showLw(true);
+                    if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
                 }
             }
         }
         // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
         // when the screen is locked
         if (mKeyguard != null) {
-            if (localLOGV) Log.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard);
-            if (mHideKeyguard) {
-                changed |= mKeyguard.hideLw(true);
+            if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen);
+            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
+                if (mKeyguard.hideLw(false)) {
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+                if (mKeyguardMediator.isShowing()) {
+                    mHandler.post(new Runnable() {
+                        public void run() {
+                            mKeyguardMediator.keyguardDone(false, false);
+                        }
+                    });
+                }
+            } else if (mHideLockScreen) {
+                if (mKeyguard.hideLw(false)) {
+                    mKeyguardMediator.setHidden(true);
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
             } else {
-                changed |= mKeyguard.showLw(true);
+                if (mKeyguard.showLw(false)) {
+                    mKeyguardMediator.setHidden(false);
+                    changes |= FINISH_LAYOUT_REDO_LAYOUT
+                            | FINISH_LAYOUT_REDO_CONFIG
+                            | FINISH_LAYOUT_REDO_WALLPAPER;
+                }
             }
         }
         
-        if (changed && hiding) {
+        if (changes != 0 && hiding) {
             IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
             if (sbs != null) {
                 try {
@@ -1278,7 +1472,7 @@
             }
         }
         
-        return changed;
+        return changes;
     }
 
     /** {@inheritDoc} */
@@ -1299,15 +1493,23 @@
     public boolean preprocessInputEventTq(RawInputEvent event) {
         switch (event.type) {
             case RawInputEvent.EV_SW:
-                if (event.keycode == 0) {
+                if (event.keycode == RawInputEvent.SW_LID) {
                     // lid changed state
                     mLidOpen = event.value == 0;
+                    boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
                     updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
-                    if (keyguardIsShowingTq()) {
+                    if (awakeNow) {
+                        // If the lid opening and we don't have to keep the
+                        // keyguard up, then we can turn on the screen
+                        // immediately.
+                        mKeyguardMediator.pokeWakelock();
+                    } else if (keyguardIsShowingTq()) {
                         if (mLidOpen) {
-                            // only do this if it's opening -- closing the device shouldn't turn it
-                            // off, but it also shouldn't turn it on.
-                            mKeyguardMediator.pokeWakelock();
+                            // If we are opening the lid and not hiding the
+                            // keyguard, then we need to have it turn on the
+                            // screen once it is shown.
+                            mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
+                                    KeyEvent.KEYCODE_POWER);
                         }
                     } else {
                         // Light up the keyboard if we are sliding up.
@@ -1365,27 +1567,22 @@
      * @return Whether music is being played right now.
      */
     boolean isMusicActive() {
-        final IAudioService audio = getAudioInterface();
-        if (audio == null) {
-            Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
+        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+        if (am == null) {
+            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
             return false;
         }
-        try {
-            return audio.isMusicActive();
-        } catch (RemoteException e) {
-            Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
-            return false;
-        }
+        return am.isMusicActive();
     }
 
     /**
      * Tell the audio service to adjust the volume appropriate to the event.
      * @param keycode
      */
-    void sendVolToMusic(int keycode) {
+    void handleVolumeKey(int stream, int keycode) {
         final IAudioService audio = getAudioInterface();
         if (audio == null) {
-            Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
+            Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
             return;
         }
         try {
@@ -1393,8 +1590,7 @@
             // during the call, but we do it as a precaution for the rare possibility
             // that the music stops right before we call this
             mBroadcastWakeLock.acquire();
-            audio.adjustStreamVolume(
-                AudioManager.STREAM_MUSIC,
+            audio.adjustStreamVolume(stream,
                 keycode == KeyEvent.KEYCODE_VOLUME_UP
                             ? AudioManager.ADJUST_RAISE
                             : AudioManager.ADJUST_LOWER,
@@ -1456,12 +1652,22 @@
                         } else if (isMusicActive()) {
                             // when keyguard is showing and screen off, we need
                             // to handle the volume key for music here
-                            sendVolToMusic(event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
                         }
                     }
                 }
             }
         } else if (!screenIsOn) {
+            // If we are in-call with screen off and keyguard is not showing,
+            // then handle the volume key ourselves.
+            // This is necessary because the phone app will disable the keyguard
+            // when the proximity sensor is in use.
+            if (isInCall() && event.type == RawInputEvent.EV_KEY &&
+                     (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+                result &= ~ACTION_PASS_TO_USER;
+                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+            }
             if (isWakeKey) {
                 // a wake key has a sole purpose of waking the device; don't pass
                 // it to the user
@@ -1475,33 +1681,41 @@
         boolean down = event.value != 0;
 
         if (type == RawInputEvent.EV_KEY) {
-            if (code == KeyEvent.KEYCODE_ENDCALL) {
+            if (code == KeyEvent.KEYCODE_ENDCALL
+                    || code == KeyEvent.KEYCODE_POWER) {
                 if (down) {
-                    boolean hungUp = false;
+                    boolean handled = false;
                     // key repeats are generated by the window manager, and we don't see them
                     // here, so unless the driver is doing something it shouldn't be, we know
                     // this is the real press event.
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            hungUp = phoneServ.endCall();
-                        } else {
-                            Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
+                    ITelephony phoneServ = getPhoneInterface();
+                    if (phoneServ != null) {
+                        try {
+                            if (code == KeyEvent.KEYCODE_ENDCALL) {
+                                handled = phoneServ.endCall();
+                            } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) {
+                                // Pressing power during incoming call should silence the ringer
+                                phoneServ.silenceRinger();
+                                handled = true;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException" + ex);
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
+                    } else {
+                        Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
                     }
-                    if (hungUp || !screenIsOn) {
+                    // power button should turn off screen in addition to hanging up the phone
+                    if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) {
                         mShouldTurnOffOnKeyUp = false;
                     } else {
                         // only try to turn off the screen if we didn't already hang up
                         mShouldTurnOffOnKeyUp = true;
-                        mHandler.postDelayed(mEndCallLongPress,
+                        mHandler.postDelayed(mPowerLongPress,
                                 ViewConfiguration.getGlobalActionKeyTimeout());
                         result &= ~ACTION_PASS_TO_USER;
                     }
                 } else {
-                    mHandler.removeCallbacks(mEndCallLongPress);
+                    mHandler.removeCallbacks(mPowerLongPress);
                     if (mShouldTurnOffOnKeyUp) {
                         mShouldTurnOffOnKeyUp = false;
                         boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0;
@@ -1620,7 +1834,34 @@
             mBroadcastWakeLock.release();
         }
     };
-    
+
+    BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            updatePlugged(intent);
+            updateDockKeepingScreenOn();
+        }
+    };
+
+    BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+            if (watchBattery != mRegisteredBatteryReceiver) {
+                mRegisteredBatteryReceiver = watchBattery;
+                if (watchBattery) {
+                    updatePlugged(mContext.registerReceiver(mBatteryReceiver,
+                            mBatteryStatusFilter));
+                } else {
+                    mContext.unregisterReceiver(mBatteryReceiver);
+                }
+            }
+            updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
+            updateDockKeepingScreenOn();
+            updateOrientationListenerLp();
+        }
+    };
+
     /** {@inheritDoc} */
     public boolean isWakeRelMovementTq(int device, int classes,
             RawInputEvent event) {
@@ -1736,7 +1977,11 @@
             // or orientation sensor disabled
             //or case.unspecified
             if (mLidOpen) {
-                return Surface.ROTATION_90;
+                return mLidOpenRotation;
+            } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
+                return mCarDockRotation;
+            } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
+                return mDeskDockRotation;
             } else {
                 if (useSensorForOrientationLp(orientation)) {
                     // If the user has enabled auto rotation by default, do it.
@@ -1751,8 +1996,19 @@
     public boolean detectSafeMode() {
         try {
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
-            mSafeMode = menuState > 0;
-            Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
+            int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
+            int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
+            int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE);
+            mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
+            performHapticFeedbackLw(null, mSafeMode
+                    ? HapticFeedbackConstants.SAFE_MODE_ENABLED
+                    : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
+            if (mSafeMode) {
+                Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
+                        + " dpad=" + dpadState + " trackball=" + trackballState + ")");
+            } else {
+                Log.i(TAG, "SAFE MODE not enabled");
+            }
             return mSafeMode;
         } catch (RemoteException e) {
             // Doom! (it's also local)
@@ -1760,23 +2016,25 @@
         }
     }
     
+    static long[] getLongIntArray(Resources r, int resid) {
+        int[] ar = r.getIntArray(resid);
+        if (ar == null) {
+            return null;
+        }
+        long[] out = new long[ar.length];
+        for (int i=0; i<ar.length; i++) {
+            out[i] = ar[i];
+        }
+        return out;
+    }
+    
     /** {@inheritDoc} */
     public void systemReady() {
-        try {
-            if (mSafeMode) {
-                // If the user is holding the menu key code, then we are
-                // going to boot into safe mode.
-                ActivityManagerNative.getDefault().enterSafeMode();
-            }
-            // tell the keyguard
-            mKeyguardMediator.onSystemReady();
-            android.os.SystemProperties.set("dev.bootcomplete", "1"); 
-            synchronized (mLock) {
-                updateOrientationListenerLp();
-                mVibrator = new Vibrator();
-            }
-        } catch (RemoteException e) {
-            // Ignore
+        // tell the keyguard
+        mKeyguardMediator.onSystemReady();
+        android.os.SystemProperties.set("dev.bootcomplete", "1"); 
+        synchronized (mLock) {
+            updateOrientationListenerLp();
         }
     }
    
@@ -1787,12 +2045,41 @@
         updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
     }
     
+    void updateDockKeepingScreenOn() {
+        if (mPlugged != 0) {
+            if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState
+                    + " mPlugged=" + mPlugged
+                    + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn
+                    + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn);
+            if (mDockState == Intent.EXTRA_DOCK_STATE_CAR
+                    && (mPlugged&mCarDockKeepsScreenOn) != 0) {
+                if (!mDockWakeLock.isHeld()) {
+                    mDockWakeLock.acquire();
+                }
+                return;
+            } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK
+                    && (mPlugged&mDeskDockKeepsScreenOn) != 0) {
+                if (!mDockWakeLock.isHeld()) {
+                    mDockWakeLock.acquire();
+                }
+                return;
+            }
+        }
+        
+        if (mDockWakeLock.isHeld()) {
+            mDockWakeLock.release();
+        }
+    }
+
     void updateRotation(int animFlags) {
         mPowerManager.setKeyboardVisibility(mLidOpen);
-        int rotation=  Surface.ROTATION_0;
+        int rotation = Surface.ROTATION_0;
         if (mLidOpen) {
-            // always use landscape if lid is open             
-            rotation = Surface.ROTATION_90;
+            rotation = mLidOpenRotation;
+        } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
+            rotation = mCarDockRotation;
+        } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
+            rotation = mDeskDockRotation;
         }
         //if lid is closed orientation will be portrait
         try {
@@ -1805,6 +2092,53 @@
     }
 
     /**
+     * Return an Intent to launch the currently active dock as home.  Returns
+     * null if the standard home should be launched.
+     * @return
+     */
+    Intent createHomeDockIntent() {
+        if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+            return null;
+        }
+        
+        Intent intent;
+        if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+            intent = mCarDockIntent;
+        } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+            intent = mDeskDockIntent;
+        } else {
+            Log.w(TAG, "Unknown dock state: " + mDockState);
+            return null;
+        }
+        
+        ActivityInfo ai = intent.resolveActivityInfo(
+                mContext.getPackageManager(), PackageManager.GET_META_DATA);
+        if (ai == null) {
+            return null;
+        }
+        
+        if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
+            intent = new Intent(intent);
+            intent.setClassName(ai.packageName, ai.name);
+            return intent;
+        }
+        
+        return null;
+    }
+    
+    void startDockOrHome() {
+        Intent dock = createHomeDockIntent();
+        if (dock != null) {
+            try {
+                mContext.startActivity(dock);
+                return;
+            } catch (ActivityNotFoundException e) {
+            }
+        }
+        mContext.startActivity(mHomeIntent);
+    }
+    
+    /**
      * goes to the home screen
      * @return whether it did anything
      */
@@ -1816,13 +2150,23 @@
             } catch (RemoteException e) {
             }
             sendCloseSystemWindows();
-            mContext.startActivity(mHomeIntent);
+            startDockOrHome();
         } else {
             // This code brings home to the front or, if it is already
             // at the front, puts the device to sleep.
             try {
                 ActivityManagerNative.getDefault().stopAppSwitches();
                 sendCloseSystemWindows();
+                Intent dock = createHomeDockIntent();
+                if (dock != null) {
+                    int result = ActivityManagerNative.getDefault()
+                            .startActivity(null, dock,
+                                    dock.resolveTypeIfNeeded(mContext.getContentResolver()),
+                                    null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
+                    if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
+                        return false;
+                    }
+                }
                 int result = ActivityManagerNative.getDefault()
                         .startActivity(null, mHomeIntent,
                                 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
@@ -1847,23 +2191,45 @@
     }
     
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
-        if (!always && Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
+        final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0;
+        if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) {
             return false;
         }
         switch (effectId) {
             case HapticFeedbackConstants.LONG_PRESS:
-                mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1);
+                mVibrator.vibrate(mLongPressVibePattern, -1);
+                return true;
+            case HapticFeedbackConstants.VIRTUAL_KEY:
+                mVibrator.vibrate(mVirtualKeyVibePattern, -1);
+                return true;
+            case HapticFeedbackConstants.SAFE_MODE_DISABLED:
+                mVibrator.vibrate(mSafeModeDisabledVibePattern, -1);
+                return true;
+            case HapticFeedbackConstants.SAFE_MODE_ENABLED:
+                mVibrator.vibrate(mSafeModeEnabledVibePattern, -1);
                 return true;
         }
         return false;
     }
     
+    public void keyFeedbackFromInput(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN
+                && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
+    }
+    
     public void screenOnStoppedLw() {
         if (!mKeyguardMediator.isShowing()) {
             long curTime = SystemClock.uptimeMillis();
             mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
         }
     }
+
+    public boolean allowKeyRepeat() {
+        // disable key repeat when screen is off
+        return mScreenOn;
+    }
 }
 
diff --git a/phone/com/android/internal/policy/impl/PowerDialog.java b/phone/com/android/internal/policy/impl/PowerDialog.java
index f4d4b04..de35bd7 100644
--- a/phone/com/android/internal/policy/impl/PowerDialog.java
+++ b/phone/com/android/internal/policy/impl/PowerDialog.java
@@ -70,8 +70,11 @@
         setContentView(com.android.internal.R.layout.power_dialog);
 
         getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        if (!getContext().getResources().getBoolean(
+                com.android.internal.R.bool.config_sf_slowBlur)) {
+            getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        }
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
 
diff --git a/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java b/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
index a680cc8..4c46be5 100644
--- a/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -20,7 +20,6 @@
 import android.app.Dialog;
 import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -30,13 +29,10 @@
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.View.OnClickListener;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import java.util.List;
@@ -59,7 +55,7 @@
     private int mIconSize;
 
     public RecentApplicationsDialog(Context context) {
-        super(context);
+        super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
 
         final Resources resources = context.getResources();
         mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size);
@@ -84,8 +80,8 @@
         Window theWindow = getWindow();
         theWindow.requestFeature(Window.FEATURE_NO_TITLE);
         theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
+                WindowManager.LayoutParams.FLAG_DIM_BEHIND);
         theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         theWindow.setTitle("Recents");
diff --git a/phone/com/android/internal/policy/impl/SimUnlockScreen.java b/phone/com/android/internal/policy/impl/SimUnlockScreen.java
index 0f7fe32..3881d11 100644
--- a/phone/com/android/internal/policy/impl/SimUnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/SimUnlockScreen.java
@@ -182,9 +182,12 @@
             mSimUnlockProgressDialog.setCancelable(false);
             mSimUnlockProgressDialog.getWindow().setType(
                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-            mSimUnlockProgressDialog.getWindow().setFlags(
-                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
-                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+            if (!mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_sf_slowBlur)) {
+                mSimUnlockProgressDialog.getWindow().setFlags(
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                        WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+            }
         }
         return mSimUnlockProgressDialog;
     }
diff --git a/phone/com/android/internal/policy/impl/UnlockScreen.java b/phone/com/android/internal/policy/impl/UnlockScreen.java
index 9aedf90..a5032b3 100644
--- a/phone/com/android/internal/policy/impl/UnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/UnlockScreen.java
@@ -17,30 +17,33 @@
 package com.android.internal.policy.impl;
 
 import android.content.Context;
-import android.content.ServiceConnection;
 import android.os.CountDownTimer;
 import android.os.SystemClock;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.MotionEvent;
 import android.widget.Button;
-import android.widget.ImageView;
 import android.widget.TextView;
+import android.text.format.DateFormat;
+import android.text.TextUtils;
 import com.android.internal.R;
+import com.android.internal.telephony.IccCard;
 import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockPatternView.Cell;
 
 import java.util.List;
+import java.util.Date;
 
 /**
  * This is the screen that shows the 9 circle unlock widget and instructs
  * the user how to unlock their device, or make an emergency call.
  */
 class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
-        implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback {
+        implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback,
+        KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
 
     private static final String TAG = "UnlockScreen";
 
@@ -50,6 +53,9 @@
     // how long we stay awake once the user is ready to enter a pattern
     private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
 
+    // how many cells the user has to cross before we poke the wakelock
+    private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
+
     private int mFailedPatternAttemptsSinceLastTimeout = 0;
     private int mTotalFailedPatternAttempts = 0;
     private CountDownTimer mCountdownTimer = null;
@@ -58,10 +64,35 @@
     private final KeyguardUpdateMonitor mUpdateMonitor;
     private final KeyguardScreenCallback mCallback;
 
+    /**
+     * whether there is a fallback option available when the pattern is forgotten.
+     */
+    private boolean mEnableFallback;
+
     private boolean mCreatedInPortrait;
 
-    private ImageView mUnlockIcon;
-    private TextView mUnlockHeader;
+    private TextView mCarrier;
+    private TextView mCenterDot;
+    private TextView mDate;
+    private TextView mTime;
+
+    // are we showing battery information?
+    private boolean mShowingBatteryInfo = false;
+
+    // last known plugged in state
+    private boolean mPluggedIn = false;
+
+    // last known battery level
+    private int mBatteryLevel = 100;
+
+    private String mNextAlarm = null;
+
+    private String mInstructions = null;
+    private TextView mStatus1;
+    private TextView mStatusSep;
+    private TextView mStatus2;
+
+
     private LockPatternView mLockPatternView;
 
     private ViewGroup mFooterNormal;
@@ -86,9 +117,6 @@
 
     private Button mForgotPatternButton;
 
-    private ServiceConnection mServiceConnection;
-
-
     enum FooterMode {
         Normal,
         ForgotLockPattern,
@@ -104,6 +132,7 @@
             case ForgotLockPattern:
                 mFooterNormal.setVisibility(View.GONE);
                 mFooterForgotPattern.setVisibility(View.VISIBLE);
+                mForgotPatternButton.setVisibility(View.VISIBLE);
                 break;
             case VerifyUnlocked:
                 mFooterNormal.setVisibility(View.GONE);
@@ -117,12 +146,15 @@
      * @param updateMonitor Used to lookup state affecting keyguard.
      * @param callback Used to notify the manager when we're done, etc.
      * @param totalFailedAttempts The current number of failed attempts.
+     * @param enableFallback True if a backup unlock option is available when the user has forgotten
+     *        their pattern (e.g they have a google account so we can show them the account based
+     *        backup option).
      */
     UnlockScreen(Context context,
-            LockPatternUtils lockPatternUtils,
-            KeyguardUpdateMonitor updateMonitor,
-            KeyguardScreenCallback callback,
-            int totalFailedAttempts) {
+                 LockPatternUtils lockPatternUtils,
+                 KeyguardUpdateMonitor updateMonitor,
+                 KeyguardScreenCallback callback,
+                 int totalFailedAttempts) {
         super(context);
         mLockPatternUtils = lockPatternUtils;
         mUpdateMonitor = updateMonitor;
@@ -136,12 +168,22 @@
             LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true);
         }
 
-        mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon);
+        mCarrier = (TextView) findViewById(R.id.carrier);
+        mCenterDot = (TextView) findViewById(R.id.centerDot);
+        mDate = (TextView) findViewById(R.id.date);
+        mTime = (TextView) findViewById(R.id.time);
+
+        mCenterDot.setText("|");
+        refreshTimeAndDateDisplay();
+
+        mStatus1 = (TextView) findViewById(R.id.status1);
+        mStatusSep = (TextView) findViewById(R.id.statusSep);
+        mStatus2 = (TextView) findViewById(R.id.status2);
+
+        resetStatusInfo();
+
 
         mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
-        mUnlockHeader = (TextView) findViewById(R.id.headerText);
-
-        mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
 
         mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal);
         mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern);
@@ -164,8 +206,7 @@
         mForgotPatternButton.setOnClickListener(new OnClickListener() {
 
             public void onClick(View v) {
-                mLockPatternUtils.setPermanentlyLocked(true);
-                mCallback.goToUnlockScreen();
+                mCallback.forgotPattern(true);
             }
         });
 
@@ -187,18 +228,105 @@
         updateFooter(FooterMode.Normal);
 
         mCreatedInPortrait = updateMonitor.isInPortrait();
+        updateMonitor.registerInfoCallback(this);
+        updateMonitor.registerSimStateCallback(this);
         updateMonitor.registerConfigurationChangeCallback(this);
         setFocusableInTouchMode(true);
+
+        // until we get an update...
+        mCarrier.setText(
+                LockScreen.getCarrierString(
+                        mUpdateMonitor.getTelephonyPlmn(),
+                        mUpdateMonitor.getTelephonySpn()));
     }
 
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            mCallback.goToLockScreen();
-            return true;
-        }
-        return false;        
+    public void setEnableFallback(boolean state) {
+        mEnableFallback = state;
     }
+    
+    private void resetStatusInfo() {
+        mInstructions = null;
+        mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo();
+        mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
+        mBatteryLevel = mUpdateMonitor.getBatteryLevel();
+        mNextAlarm = mLockPatternUtils.getNextAlarm();
+        updateStatusLines();
+    }
+
+    private void updateStatusLines() {
+        if (mInstructions != null) {
+            // instructions only
+            mStatus1.setText(mInstructions);
+            if (TextUtils.isEmpty(mInstructions)) {
+                mStatus1.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+            } else {
+                mStatus1.setCompoundDrawablesWithIntrinsicBounds(
+                        R.drawable.ic_lock_idle_lock, 0, 0, 0);
+            }
+
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatusSep.setVisibility(View.GONE);
+            mStatus2.setVisibility(View.GONE);
+        } else if (mShowingBatteryInfo && mNextAlarm == null) {
+            // battery only
+            if (mPluggedIn) {
+              if (mBatteryLevel >= 100) {
+                mStatus1.setText(getContext().getString(R.string.lockscreen_charged));
+              } else {
+                  mStatus1.setText(getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel));
+              }
+            } else {
+                mStatus1.setText(getContext().getString(R.string.lockscreen_low_battery));
+            }
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0);
+
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatusSep.setVisibility(View.GONE);
+            mStatus2.setVisibility(View.GONE);
+
+        } else if (mNextAlarm != null && !mShowingBatteryInfo) {
+            // alarm only
+            mStatus1.setText(mNextAlarm);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0);
+
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatusSep.setVisibility(View.GONE);
+            mStatus2.setVisibility(View.GONE);
+        } else if (mNextAlarm != null && mShowingBatteryInfo) {
+            // both battery and next alarm
+            mStatus1.setText(mNextAlarm);
+            mStatusSep.setText("|");
+            mStatus2.setText(getContext().getString(
+                    R.string.lockscreen_battery_short,
+                    Math.min(100, mBatteryLevel)));
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0);
+            if (mPluggedIn) {
+                mStatus2.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0);
+            } else {
+                mStatus2.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+            }
+
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatusSep.setVisibility(View.VISIBLE);
+            mStatus2.setVisibility(View.VISIBLE);
+        } else {
+            // nothing specific to show; show general instructions
+            mStatus1.setText(R.string.lockscreen_pattern_instructions);
+            mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, 0, 0);
+
+            mStatus1.setVisibility(View.VISIBLE);
+            mStatusSep.setVisibility(View.GONE);
+            mStatus2.setVisibility(View.GONE);
+        }
+    }
+
+
+    private void refreshTimeAndDateDisplay() {
+        Date now = new Date();
+        mTime.setText(DateFormat.getTimeFormat(getContext()).format(now));
+        mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now));
+    }
+
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
@@ -210,11 +338,40 @@
                 ((SystemClock.elapsedRealtime() - mLastPokeTime)
                         >  (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
             mLastPokeTime = SystemClock.elapsedRealtime();
-            mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
         }
         return result;
     }
 
+
+    // ---------- InfoCallback
+
+    /** {@inheritDoc} */
+    public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
+        mShowingBatteryInfo = showBatteryInfo;
+        mPluggedIn = pluggedIn;
+        mBatteryLevel = batteryLevel;
+        updateStatusLines();
+    }
+
+    /** {@inheritDoc} */
+    public void onTimeChanged() {
+        refreshTimeAndDateDisplay();
+    }
+
+    /** {@inheritDoc} */
+    public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+        mCarrier.setText(LockScreen.getCarrierString(plmn, spn));
+    }
+
+    // ---------- SimStateCallback
+
+    /** {@inheritDoc} */
+    public void onSimStateChanged(IccCard.State simState) {
+    }
+
+
+
+
     /** {@inheritDoc} */
     public void onOrientationChange(boolean inPortrait) {
         if (inPortrait != mCreatedInPortrait) {
@@ -241,8 +398,7 @@
     /** {@inheritDoc} */
     public void onResume() {
         // reset header
-        mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
-        mUnlockIcon.setVisibility(View.VISIBLE);
+        resetStatusInfo();
 
         // reset lock pattern
         mLockPatternView.enableInput();
@@ -262,10 +418,11 @@
         // the footer depends on how many total attempts the user has failed
         if (mCallback.isVerifyUnlockOnly()) {
             updateFooter(FooterMode.VerifyUnlocked);
-        } else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
-            updateFooter(FooterMode.Normal);
-        } else {
+        } else if (mEnableFallback &&
+                (mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
             updateFooter(FooterMode.ForgotLockPattern);
+        } else {
+            updateFooter(FooterMode.Normal);
         }
     }
 
@@ -274,6 +431,15 @@
         mUpdateMonitor.removeCallback(this);
     }
 
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (hasWindowFocus) {
+            // when timeout dialog closes we want to update our state
+            onResume();
+        }
+    }
+
     private class UnlockPatternListener
             implements LockPatternView.OnPatternListener {
 
@@ -284,15 +450,25 @@
         public void onPatternCleared() {
         }
 
+        public void onPatternCellAdded(List<Cell> pattern) {
+            // To guard against accidental poking of the wakelock, look for
+            // 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);
+            }
+        }
+
         public void onPatternDetected(List<LockPatternView.Cell> pattern) {
             if (mLockPatternUtils.checkPattern(pattern)) {
                 mLockPatternView
                         .setDisplayMode(LockPatternView.DisplayMode.Correct);
-                mUnlockIcon.setVisibility(View.GONE);
-                mUnlockHeader.setText("");
+                mInstructions = "";
+                updateStatusLines();
                 mCallback.keyguardDone(true);
             } else {
-                mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
+                if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+                    mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
+                }
                 mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
                 if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
                     mTotalFailedPatternAttempts++;
@@ -304,8 +480,9 @@
                     handleAttemptLockout(deadline);
                     return;
                 }
-                mUnlockIcon.setVisibility(View.VISIBLE);
-                mUnlockHeader.setText(R.string.lockscreen_pattern_wrong);
+                // TODO mUnlockIcon.setVisibility(View.VISIBLE);
+                mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong);
+                updateStatusLines();
                 mLockPatternView.postDelayed(
                         mCancelPatternRunnable,
                         PATTERN_CLEAR_TIMEOUT_MS);
@@ -322,20 +499,25 @@
             @Override
             public void onTick(long millisUntilFinished) {
                 int secondsRemaining = (int) (millisUntilFinished / 1000);
-                mUnlockHeader.setText(getContext().getString(
+                mInstructions = getContext().getString(
                         R.string.lockscreen_too_many_failed_attempts_countdown,
-                        secondsRemaining));
+                        secondsRemaining);
+                updateStatusLines();
             }
 
             @Override
             public void onFinish() {
                 mLockPatternView.setEnabled(true);
-                mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
-                mUnlockIcon.setVisibility(View.VISIBLE);
+                mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions);
+                updateStatusLines();
+                // TODO mUnlockIcon.setVisibility(View.VISIBLE);
                 mFailedPatternAttemptsSinceLastTimeout = 0;
-                updateFooter(FooterMode.ForgotLockPattern);
+                if (mEnableFallback) {
+                    updateFooter(FooterMode.ForgotLockPattern);
+                } else {
+                    updateFooter(FooterMode.Normal);
+                }
             }
         }.start();
     }
-
 }