Merge "A new clock widget to create lock screen appwidgets" into jb-mr1-dev
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 2af65b9..3dd640c 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -80,6 +80,13 @@
     public static final String ACTION_APPWIDGET_PICK = "android.appwidget.action.APPWIDGET_PICK";
 
     /**
+     * Similar to ACTION_APPWIDGET_PICK, but used from keyguard
+     * @hide
+     */
+    public static final String
+            ACTION_KEYGUARD_APPWIDGET_PICK = "android.appwidget.action.KEYGUARD_APPWIDGET_PICK";
+
+    /**
      * Send this from your {@link AppWidgetHost} activity when you want to bind an AppWidget to
      * display and bindAppWidgetIdIfAllowed returns false.
      * <p>
@@ -224,13 +231,6 @@
     public static final String EXTRA_CATEGORY_FILTER = "categoryFilter";
 
     /**
-     * An intent extra to pass to the AppWidget picker which allows the picker to filter
-     * the list based on the {@link AppWidgetProviderInfo#widgetFeatures}.
-     * @hide
-     */
-    public static final String EXTRA_FEATURES_FILTER = "featuresFilter";
-
-    /**
      * An intent extra to pass to the AppWidget picker to specify whether or not to sort
      * the list of caller-specified extra AppWidgets along with the rest of the AppWidgets
      * @hide
diff --git a/core/java/com/android/internal/policy/IFaceLockInterface.aidl b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
index a017722..017801b 100644
--- a/core/java/com/android/internal/policy/IFaceLockInterface.aidl
+++ b/core/java/com/android/internal/policy/IFaceLockInterface.aidl
@@ -23,7 +23,6 @@
     void startUi(IBinder containingWindowToken, int x, int y, int width, int height,
             boolean useLiveliness);
     void stopUi();
-    void makeInvisible();
     void registerCallback(IFaceLockCallback cb);
     void unregisterCallback(IFaceLockCallback cb);
 }
diff --git a/core/java/com/android/internal/widget/FaceUnlockView.java b/core/java/com/android/internal/widget/FaceUnlockView.java
new file mode 100644
index 0000000..e3c1247
--- /dev/null
+++ b/core/java/com/android/internal/widget/FaceUnlockView.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+public class FaceUnlockView extends RelativeLayout {
+    private static final String TAG = "FaceUnlockView";
+
+    public FaceUnlockView(Context context) {
+        this(context, null);
+    }
+
+    public FaceUnlockView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    private int resolveMeasured(int measureSpec, int desired)
+    {
+        int result = 0;
+        int specSize = MeasureSpec.getSize(measureSpec);
+        switch (MeasureSpec.getMode(measureSpec)) {
+            case MeasureSpec.UNSPECIFIED:
+                result = desired;
+                break;
+            case MeasureSpec.AT_MOST:
+                result = Math.max(specSize, desired);
+                break;
+            case MeasureSpec.EXACTLY:
+            default:
+                result = specSize;
+        }
+        return result;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int minimumWidth = getSuggestedMinimumWidth();
+        final int minimumHeight = getSuggestedMinimumHeight();
+        int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
+        int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
+
+        final int chosenSize = Math.min(viewWidth, viewHeight);
+        final int newWidthMeasureSpec =
+                MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
+        final int newHeightMeasureSpec =
+                MeasureSpec.makeMeasureSpec(chosenSize, MeasureSpec.AT_MOST);
+
+        super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec);
+    }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f8c3b4d..3ee3c8c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -129,6 +129,11 @@
      */
     public static final int ID_DEFAULT_STATUS_WIDGET = -2;
 
+    /**
+     * Intent extra that's used to tag the default widget when using the picker
+     */
+    public static final String EXTRA_DEFAULT_WIDGET = "com.android.settings.DEFAULT_WIDGET";
+
     protected final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
     protected final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
     protected final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 92aa06a..a5aa713 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1901,6 +1901,13 @@
         android:description="@string/permdesc_bindGadget"
         android:protectionLevel="signature|system" />
 
+    <!-- Private permission, to restrict who can bring up a dialog to add a new
+         keyguard widget
+         @hide -->
+    <permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:protectionLevel="signature|system" />
+
     <!-- Internal permission allowing an application to query/set which
          applications can bind AppWidgets.
          @hide -->
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index bb455bd..67ac1d5 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -50,14 +50,14 @@
 
         <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
             android:id="@+id/keyguard_security_container"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_width="@dimen/keyguard_security_width"
+            android:layout_height="@dimen/keyguard_security_height"
             androidprv:layout_childType="challenge"
             androidprv:layout_centerWithinArea="0.55">
             <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
                 android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:clipChildren="false"
                 android:clipToPadding="false"
                 android:paddingLeft="@dimen/keyguard_security_view_margin"
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index ed55e61..a3c8105 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -36,7 +36,8 @@
 
         <FrameLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent">
+            android:layout_height="match_parent"
+            androidprv:layout_childType="widgets">
             <include layout="@layout/keyguard_widget_pager"
                 android:id="@+id/app_widget_container"
                 android:layout_width="match_parent"
@@ -52,21 +53,18 @@
         <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
             android:id="@+id/keyguard_security_container"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
+            android:layout_height="@dimen/keyguard_security_height"
             androidprv:layout_childType="challenge"
-            android:layout_marginLeft="@dimen/kg_edge_swipe_region_size"
-            android:layout_marginRight="@dimen/kg_edge_swipe_region_size"
             android:background="@drawable/kg_bouncer_bg_white"
+            android:padding="0dp"
             android:gravity="bottom|center_horizontal">
             <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
                 android:id="@+id/view_flipper"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
                 android:clipChildren="false"
                 android:clipToPadding="false"
-                android:paddingLeft="@dimen/keyguard_security_view_margin"
                 android:paddingTop="@dimen/keyguard_security_view_margin"
-                android:paddingRight="@dimen/keyguard_security_view_margin"
                 android:gravity="center">
             </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
         </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>
diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml
index 3b29db8..7fd370b 100644
--- a/core/res/res/layout-port/keyguard_widget_pager.xml
+++ b/core/res/res/layout-port/keyguard_widget_pager.xml
@@ -25,7 +25,7 @@
     android:paddingLeft="25dp"
     android:paddingRight="25dp"
     android:paddingTop="25dp"
-    android:paddingBottom="64dp"
+    android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
     android:clipChildren="false"
     android:clipToPadding="false"
     androidprv:pageSpacing="10dp">
diff --git a/core/res/res/layout/keyguard_face_unlock_view.xml b/core/res/res/layout/keyguard_face_unlock_view.xml
index ae7984c..976d0c6 100644
--- a/core/res/res/layout/keyguard_face_unlock_view.xml
+++ b/core/res/res/layout/keyguard_face_unlock_view.xml
@@ -30,10 +30,10 @@
         android:layout_height="wrap_content"
         />
 
-    <RelativeLayout
+    <com.android.internal.widget.FaceUnlockView
         android:id="@+id/face_unlock_area_view"
         android:layout_width="match_parent"
-        android:layout_height="@*android:dimen/face_unlock_height"
+        android:layout_height="0dp"
         android:background="@*android:drawable/intro_bg"
         android:gravity="center"
         android:layout_weight="1">
@@ -55,8 +55,7 @@
             android:background="#00000000"
             android:src="@*android:drawable/ic_facial_backup"
         />
-
-    </RelativeLayout>
+    </com.android.internal.widget.FaceUnlockView>
 
     <include layout="@layout/keyguard_emergency_carrier_area"
         android:id="@+id/keyguard_selector_fade_container"
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
index a184415..b6faf5b 100644
--- a/core/res/res/layout/keyguard_password_view.xml
+++ b/core/res/res/layout/keyguard_password_view.xml
@@ -22,73 +22,61 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="center">
+    android:gravity="bottom"
+    >
 
-    <FrameLayout
+    <Space
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_weight="1">
+        android:layout_weight="1"
+        />
 
-        <include layout="@layout/keyguard_message_area"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
 
-        <LinearLayout
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"
-            android:orientation="vertical"
-            android:layout_gravity="center">
+    <!-- Password entry field -->
+    <!-- Note: the entire container is styled to look like the edit field,
+         since the backspace/IME switcher looks better inside -->
+     <LinearLayout
+         android:layout_height="wrap_content"
+         android:layout_width="match_parent"
+         android:orientation="horizontal"
+         android:background="#70000000"
+         android:layout_marginTop="8dp"
+         android:layout_marginBottom="8dp"
+         >
 
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
+         <EditText android:id="@+id/passwordEntry"
+             android:layout_width="0dip"
+             android:layout_height="wrap_content"
+             android:layout_weight="1"
+             android:gravity="center_horizontal"
+             android:layout_gravity="center_vertical"
+             android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+             android:singleLine="true"
+             android:textStyle="normal"
+             android:inputType="textPassword"
+             android:textSize="36sp"
+             android:background="@null"
+             android:textAppearance="?android:attr/textAppearanceMedium"
+             android:textColor="#ffffffff"
+             android:imeOptions="flagForceAscii|actionDone"
+             />
 
-                <!-- Password entry field -->
-                <!-- Note: the entire container is styled to look like the edit field,
-                     since the backspace/IME switcher looks better inside -->
-                <LinearLayout
-                    android:layout_gravity="center_vertical|fill_horizontal"
-                    android:layout_height="wrap_content"
-                    android:layout_width="match_parent"
-                    android:orientation="horizontal"
-                    android:background="#70000000"
-                    android:layout_marginStart="4dip"
-                    android:layout_marginEnd="4dip">
+         <ImageView android:id="@+id/switch_ime_button"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:src="@*android:drawable/ic_lockscreen_ime"
+             android:clickable="true"
+             android:padding="8dip"
+             android:layout_gravity="center"
+             android:background="?android:attr/selectableItemBackground"
+             android:visibility="gone"
+             />
 
-                    <EditText android:id="@+id/passwordEntry"
-                        android:layout_width="0dip"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:gravity="center_horizontal"
-                        android:layout_gravity="center_vertical"
-                        android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-                        android:singleLine="true"
-                        android:textStyle="normal"
-                        android:inputType="textPassword"
-                        android:textSize="36sp"
-                        android:background="@null"
-                        android:textAppearance="?android:attr/textAppearanceMedium"
-                        android:textColor="#ffffffff"
-                        android:imeOptions="flagForceAscii|actionDone"
-                        />
-
-                    <ImageView android:id="@+id/switch_ime_button"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:src="@*android:drawable/ic_lockscreen_ime"
-                        android:clickable="true"
-                        android:padding="8dip"
-                        android:layout_gravity="center"
-                        android:background="?android:attr/selectableItemBackground"
-                        android:visibility="gone"
-                        />
-
-                </LinearLayout>
-            </LinearLayout>
         </LinearLayout>
-    </FrameLayout>
+
     <include layout="@layout/keyguard_emergency_carrier_area"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_pin_view.xml b/core/res/res/layout/keyguard_pin_view.xml
index d62570b..2529196 100644
--- a/core/res/res/layout/keyguard_pin_view.xml
+++ b/core/res/res/layout/keyguard_pin_view.xml
@@ -21,8 +21,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_pin_view"
-    android:layout_width="350dp"
-    android:layout_height="350dp"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:orientation="vertical"
     >
     <include layout="@layout/keyguard_message_area"
@@ -35,7 +35,7 @@
         android:orientation="horizontal"
         android:layout_weight="1"
         >
-        <TextView android:id="@+id/passwordEntry"
+        <TextView android:id="@+id/pinEntry"
             android:editable="true"
             android:layout_width="0dip"
             android:layout_height="match_parent"
@@ -59,6 +59,7 @@
             android:paddingLeft="24dp"
             android:paddingRight="24dp"
             android:background="?android:attr/selectableItemBackground"
+            android:contentDescription="@string/keyboardview_keycode_delete"
             />
     </LinearLayout>
     <View
@@ -78,7 +79,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="1"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -87,7 +88,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="2"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -96,7 +97,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="3"
             />
     </LinearLayout>
@@ -112,7 +113,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="4"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -121,7 +122,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="5"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -130,7 +131,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="6"
             />
     </LinearLayout>
@@ -146,7 +147,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="7"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -155,7 +156,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="8"
             />
         <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
@@ -164,7 +165,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="9"
             />
     </LinearLayout>
@@ -185,7 +186,7 @@
             android:layout_width="0px"
             android:layout_height="match_parent"
             android:layout_weight="1"
-            androidprv:textView="@+id/passwordEntry"
+            androidprv:textView="@+id/pinEntry"
             androidprv:digit="0"
             />
         <ImageButton
@@ -196,6 +197,7 @@
             android:layout_height="match_parent"
             android:layout_weight="1"
             android:src="@drawable/sym_keyboard_return_holo"
+            android:contentDescription="@string/keyboardview_keycode_enter"
             />
     </LinearLayout>
 
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 07f62ed..36f2628 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -50,4 +50,10 @@
     <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
     <dimen name="kg_secure_padding_height">0dp</dimen>
 
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+
 </resources>
diff --git a/core/res/res/values-sw380dp/dimens.xml b/core/res/res/values-sw380dp/dimens.xml
new file mode 100644
index 0000000..fc0e85d
--- /dev/null
+++ b/core/res/res/values-sw380dp/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">340dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 0d01df4..52c230b 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -98,10 +98,10 @@
     <dimen name="kg_widget_pager_horizontal_padding">24dp</dimen>
 
     <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">24dp</dimen>
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
 
     <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">16dp</dimen>
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
 
     <!-- Top margin for the runway lights. We add a negative margin in large
         devices to account for the widget pager padding -->
diff --git a/core/res/res/values-sw720dp/dimens.xml b/core/res/res/values-sw720dp/dimens.xml
index d6d2b66..ccdb4be 100644
--- a/core/res/res/values-sw720dp/dimens.xml
+++ b/core/res/res/values-sw720dp/dimens.xml
@@ -91,10 +91,10 @@
     <dimen name="kg_widget_pager_horizontal_padding">80dp</dimen>
 
     <!-- Top padding for the widget pager -->
-    <dimen name="kg_widget_pager_top_padding">32dp</dimen>
+    <dimen name="kg_widget_pager_top_padding">0dp</dimen>
 
     <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">36dp</dimen>
+    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
 
     <!-- Top margin for the runway lights. We add a negative margin in large
         devices to account for the widget pager padding -->
@@ -112,4 +112,9 @@
     <!-- Size of the text under the avator on the multiuser lockscreen. -->
     <dimen name="keyguard_avatar_name_size">12sp</dimen>
 
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">420dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">420dp</dimen>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6505ad0..186c8b3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5816,6 +5816,8 @@
         <!-- Scrim. This will block access to child views that
              come before it in the child list in bouncer mode. -->
         <enum name="scrim" value="4" />
+        <!-- The home for widgets. All widgets will be descendents of this. -->
+        <enum name="widgets" value="5" />
     </attr>
 
     <declare-styleable name="SlidingChallengeLayout">
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b830e79..4966b97 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -294,7 +294,7 @@
     <dimen name="kg_widget_pager_top_padding">0dp</dimen>
 
     <!-- Bottom padding for the widget pager -->
-    <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
+    <dimen name="kg_widget_pager_bottom_padding">64dp</dimen>
 
     <!-- Top margin for the runway lights. We add a negative margin in large
         devices to account for the widget pager padding -->
@@ -303,6 +303,12 @@
     <!-- Touch slop for the global toggle accessibility gesture -->
     <dimen name="accessibility_touch_slop">80dip</dimen>
 
+    <!-- Width of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_width">320dp</dimen>
+
+    <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
+    <dimen name="keyguard_security_height">400dp</dimen>
+
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_margin">8dp</dimen>
 
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index d1df2a4..053fc85 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -18,7 +18,7 @@
 -->
 <resources>
     <integer name="kg_carousel_angle">75</integer>
-    <integer name="kg_security_flip_duration">75</integer>
-    <integer name="kg_security_fade_duration">75</integer>
+    <integer name="kg_security_flip_duration">100</integer>
+    <integer name="kg_security_fade_duration">100</integer>
     <integer name="kg_glowpad_rotation_offset">0</integer>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 159eec1..51d6429 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2065,6 +2065,15 @@
     <!-- This can be used in any application wanting to disable the text "Emergency number" -->
     <string name="emergency_call_dialog_number_for_display">Emergency number</string>
 
+    <!-- String to display if the clock status widget is selected (it is the default) [CHAR LIMIT=22] -->
+    <string name="widget_default" msgid="8269383575996003796">Clock</string>
+
+    <!-- Package name for default widget [DO NOT TRANSLATE] -->
+    <string name="widget_default_package_name">com.android.deskclock</string>
+
+    <!-- Class name for default widget [DO NOT TRANSLATE] -->
+    <string name="widget_default_class_name">com.android.deskclock.DeskClock</string>
+
     <!--
        *** touch based lock / unlock ***
                                           --> <skip />
@@ -2276,14 +2285,12 @@
     <string name="keyguard_accessibility_add_widget">Add widget.</string>
     <!-- Accessibility description of the empty sidget slot (place holder for a new widget). [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_widget_empty_slot">Empty</string>
-    <!-- Accessibility description of the unlock area. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_unlock_area">Unlock area.</string>
     <!-- Accessibility description of the event of expanding an unlock area. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_unlock_area_expanded">Unlock area expanded.</string>
     <!-- Accessibility description of the event of collapsing an unlock area. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_unlock_area_collapsed">Unlock area collapsed.</string>
     <!-- Accessibility description of a lock screen widget. [CHAR_LIMIT=none] -->
-    <string name="keyguard_accessibility_widget">%1$s widget.</string>
+    <string name="keyguard_accessibility_widget"><xliff:g id="widget_index">%1$s</xliff:g> widget.</string>
     <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
     <string name="keyguard_accessibility_user_selector">User selector</string>
     <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
@@ -2292,6 +2299,28 @@
     <string name="keyguard_accessibility_camera">Camera</string>
     <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
     <string name="keygaurd_accessibility_media_controls">Media controls</string>
+    <!-- Accessibility description of widget reordering start. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_reorder_start">Widget reordering started.</string>
+    <!-- Accessibility description of widget reordering end. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_reorder_end">Widget reordering ended.</string>
+    <!-- Accessibility description of the a widget deletion event. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_deleted">Widget <xliff:g id="widget_index">%1$s</xliff:g> deleted.</string>
+    <!-- Accessibility description of the button to expand the lock area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_expand_lock_area">Expand unlock area.</string>
+    <!-- Accessibility description of the slide unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_slide_unlock">Slide unlock.</string>
+    <!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
+    <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_face_unlock">Face unlock.</string>
+    <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string>
+    <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_password_unlock">Password unlock.</string>
+    <!-- Accessibility description of the unlock pattern area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_pattern_area">Pattern area.</string>
+    <!-- Accessibility description of the unlock slide area. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_slide_area">Slide area.</string>
 
     <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
     <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7ebf7e7..5af60c8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,6 +479,9 @@
   <java-symbol type="string" name="emailTypeOther" />
   <java-symbol type="string" name="emailTypeWork" />
   <java-symbol type="string" name="emergency_call_dialog_number_for_display" />
+  <java-symbol type="string" name="widget_default" />
+  <java-symbol type="string" name="widget_default_package_name" />
+  <java-symbol type="string" name="widget_default_class_name" />
   <java-symbol type="string" name="emergency_calls_only" />
   <java-symbol type="string" name="enable_accessibility_canceled" />
   <java-symbol type="string" name="eventTypeAnniversary" />
@@ -1269,6 +1272,7 @@
   <java-symbol type="id" name="option3" />
   <java-symbol type="id" name="password" />
   <java-symbol type="id" name="passwordEntry" />
+  <java-symbol type="id" name="pinEntry" />
   <java-symbol type="id" name="pinDel" />
   <java-symbol type="id" name="pinDisplay" />
   <java-symbol type="id" name="owner_info" />
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 1bbc7df..5db7ffc 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -74,4 +74,5 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
 </manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 561e33e..245f537 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -65,6 +65,8 @@
     public static final long LONG_TIMEOUT = 50 * 1000;
     // 2 minutes timer between wifi stop and start
     public static final long  WIFI_STOP_START_INTERVAL = 2 * 60 * 1000;
+    // Set ping test timer to be 3 minutes
+    public static final long PING_TIMER = 3 * 60 *1000;
     public static final int SUCCESS = 0;  // for Wifi tethering state change
     public static final int FAILURE = 1;
     public static final int INIT = -1;
@@ -517,37 +519,36 @@
      * @return true if the ping test is successful, false otherwise.
      */
     public boolean pingTest(String[] pingServerList) {
-        boolean result = false;
         String[] hostList = {"www.google.com", "www.yahoo.com",
                 "www.bing.com", "www.facebook.com", "www.ask.com"};
         if (pingServerList != null) {
             hostList = pingServerList;
         }
-        try {
-            // assume the chance that all servers are down is very small
-            for (int i = 0; i < hostList.length; i++ ) {
-                String host = hostList[i];
-                log("Start ping test, ping " + host);
-                Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
-                int status = p.waitFor();
-                if (status == 0) {
-                    // if any of the ping test is successful, return true
-                    result = true;
-                    break;
-                } else {
-                    result = false;
-                    log("ping " + host + " failed.");
+
+        long startTime = System.currentTimeMillis();
+        while ((System.currentTimeMillis() - startTime) < PING_TIMER) {
+            try {
+                // assume the chance that all servers are down is very small
+                for (int i = 0; i < hostList.length; i++ ) {
+                    String host = hostList[i];
+                    log("Start ping test, ping " + host);
+                    Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
+                    int status = p.waitFor();
+                    if (status == 0) {
+                        // if any of the ping test is successful, return true
+                        return true;
+                    }
                 }
+            } catch (UnknownHostException e) {
+                log("Ping test Fail: Unknown Host");
+            } catch (IOException e) {
+                log("Ping test Fail:  IOException");
+            } catch (InterruptedException e) {
+                log("Ping test Fail: InterruptedException");
             }
-        } catch (UnknownHostException e) {
-            log("Ping test Fail: Unknown Host");
-        } catch (IOException e) {
-            log("Ping test Fail:  IOException");
-        } catch (InterruptedException e) {
-            log("Ping test Fail: InterruptedException");
         }
-        log("return");
-        return result;
+        // ping test timeout
+        return false;
     }
 
     /**
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 79d928c..7bfb594 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -28,6 +28,7 @@
 import android.os.Environment;
 import android.os.PowerManager;
 import android.provider.Settings;
+import android.view.KeyEvent;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
@@ -289,6 +290,11 @@
 
             // Turn screen on again
             mAct.turnScreenOn();
+            // Wait for 2 seconds for the lock screen
+            sleep(2 * 1000, "wait 2 seconds for lock screen");
+            // Disable lock screen by inject menu key event
+            mRunner.sendKeyDownUpSync(KeyEvent.KEYCODE_MENU);
+
             // Measure the time for Wi-Fi to get connected
             long startTime = System.currentTimeMillis();
             assertTrue("Wait for Wi-Fi enable timeout after wake up",
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 463343d..a3538a9 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -15,7 +15,7 @@
 <li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
 <li><a href="#pricing">10. Set prices for your apps</a></li>
 <li><a href="#localize">11. Start localization early</a></li>
-<li><a href="#localize">12. Prepare promotional graphics</a></li>
+<li><a href="#graphics">12. Prepare promotional graphics</a></li>
 <li><a href="#apk">13. Build the release-ready APK</a></li>
 <li><a href="#product-page">14. Complete the product details</a></li>
 <li><a href="#badges">15. Use Google Play badges</a></li>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 8374b10..0623a9e 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1191,6 +1191,11 @@
                 return;
             }
 
+            if (mRadius > 0 || mRadiusArray != null) {
+                mOpaque = false;
+                return;
+            }
+
             if (mStrokeWidth > 0 && !isOpaque(mStrokeColor)) {
                 mOpaque = false;
                 return;
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index e0e11be..791d3d0 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -22,7 +22,7 @@
 /**
  * Represents a geographical boundary, also known as a geofence.
  *
- * <p>Currently only circular geofences are supported.
+ * <p>Currently only circular geofences are supported and they do not support altitude changes.
  */
 public final class Geofence implements Parcelable {
     /** @hide */
@@ -34,10 +34,10 @@
     private final float mRadius;
 
     /**
-     * Create a horizontal, circular geofence.
+     * Create a circular geofence (on a flat, horizontal plane).
      *
-     * @param latitude latitude in degrees, between -90 and +90 inclusive
-     * @param longitude longitude in degrees, between -180 and +180 inclusive
+     * @param latitude latitude in degrees
+     * @param longitude longitude in degrees
      * @param radius radius in meters
      * @return a new geofence
      * @throws IllegalArgumentException if any parameters are out of range
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 59a5624..653e8d1 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -811,6 +811,10 @@
     /**
      * Register for fused location updates using a LocationRequest and callback.
      *
+     * <p>Upon a location update, the system delivers the new {@link Location} to the
+     * provided {@link LocationListener}, by calling its {@link
+     * LocationListener#onLocationChanged} method.</p>
+     *
      * <p>The system will automatically select and enable the best providers
      * to compute a location for your application. It may use only passive
      * locations, or just a single location source, or it may fuse together
@@ -869,6 +873,10 @@
     /**
      * Register for fused location updates using a LocationRequest and a pending intent.
      *
+     * <p>Upon a location update, the system delivers the new {@link Location} with your provided
+     * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
+     * in the intent's extras.</p>
+     *
      * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
      *
      * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index 8e0061d..737e17f 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -33,8 +33,8 @@
  * Criteria} class allows providers to be selected based on
  * user-specified criteria.
  *
- * @deprecated Use the {@link LocationRequest} class to request location
- * instead of enumerating providers.
+ * @deprecated Use the {@link Criteria} class to request location instead of
+ * enumerating providers.
  */
 @Deprecated
 public class LocationProvider {
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index e940c85..8fdde92 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -41,8 +41,7 @@
             android:fadingEdge="horizontal"
             android:scrollbars="none"
             android:layout_gravity="right"
-            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
-            android:importantForAccessibility="no">
+            android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index 12599f8..7335f86 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -45,8 +45,7 @@
             android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
             android:layout_gravity="bottom|left"
             android:clipToPadding="false"
-            android:clipChildren="false"
-            android:importantForAccessibility="no">
+            android:clipChildren="false">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index 8afed22..3951bba 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -49,8 +49,7 @@
             android:fadingEdgeLength="20dip"
             android:layout_gravity="bottom|left"
             android:clipToPadding="false"
-            android:clipChildren="false"
-            android:importantForAccessibility="no">
+            android:clipChildren="false">
 
             <LinearLayout android:id="@+id/recents_linear_layout"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c34ca3e..7f7a51c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -174,7 +174,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skærmen er nu låst i stående retning."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Dagdrømme"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Oplader, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d5af0cd..d619de1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -176,7 +176,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Activar Daydreams"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Activar protector"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avión"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e8bc08d..19de9b6 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -174,7 +174,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Suspender"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Salvapantallas"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index a12ccf0..babbcce 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -176,7 +176,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Écran de veille interactif"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"En charge (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a05aa8f..c454bb1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -174,7 +174,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Śnij na jawie"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Wygaszacz ekranu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Ładowanie (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1ca085c..1b8370b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -174,7 +174,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"O ecrã está bloqueado na orientação vertical."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Sonho"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avião"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"A carregar, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index fba3da5..7e2d030 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -172,7 +172,7 @@
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrini imefungwa sasa katika uelekezo wa mandhari."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrini imefungwa katika uelekeo wa picha."</string>
     <string name="jelly_bean_dream_name" msgid="5992026543636816792">"BeanFlinger"</string>
-    <string name="start_dreams" msgid="7219575858348719790">"Ndoto ya mchana"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Hali Tulivu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modi ya ndege"</string>
     <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"Inachaji, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 599b7e2..cc9c601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -202,21 +202,18 @@
             Log.e(TAG, "Couldn't get user info", e);
         }
         final int userId = userInfo.id;
+        final String userName = userInfo.name;
 
         final Context context = currentUserContext;
         mUserInfoTask = new AsyncTask<Void, Void, Pair<String, Drawable>>() {
             @Override
             protected Pair<String, Drawable> doInBackground(Void... params) {
-                final Cursor cursor = context.getContentResolver().query(
-                        Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
-                        null, null, null);
                 final UserManager um =
                         (UserManager) mContext.getSystemService(Context.USER_SERVICE);
 
                 // Fall back to the UserManager nickname if we can't read the name from the local
                 // profile below.
-                String nickName = um.getUserName();
-                String name = nickName;
+                String name = userName;
                 Drawable avatar = null;
                 Bitmap rawAvatar = um.getUserIcon(userId);
                 if (rawAvatar != null) {
@@ -225,17 +222,23 @@
                     avatar = mContext.getResources().getDrawable(R.drawable.ic_qs_default_user);
                 }
 
-                // Try and read the display name from the local profile
-                if (cursor != null) {
-                    try {
-                        if (cursor.moveToFirst()) {
-                            name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+                // If it's a single-user device, get the profile name, since the nickname is not
+                // usually valid
+                if (um.getUsers().size() <= 1) {
+                    // Try and read the display name from the local profile
+                    final Cursor cursor = context.getContentResolver().query(
+                            Profile.CONTENT_URI, new String[] {Phone._ID, Phone.DISPLAY_NAME},
+                            null, null, null);
+                    if (cursor != null) {
+                        try {
+                            if (cursor.moveToFirst()) {
+                                name = cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME));
+                            }
+                        } finally {
+                            cursor.close();
                         }
-                    } finally {
-                        cursor.close();
                     }
                 }
-
                 return new Pair<String, Drawable>(name, avatar);
             }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index fefd4fb..de028a4 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -412,7 +412,17 @@
     boolean mForceStatusBar;
     boolean mForceStatusBarFromKeyguard;
     boolean mHideLockScreen;
-    boolean mDismissKeyguard;
+
+    // States of keyguard dismiss.
+    private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
+    private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
+    private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
+    int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+
+    /** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
+     * be done once per window. */
+    private WindowState mWinDismissingKeyguard;
+
     boolean mShowingLockscreen;
     boolean mShowingDream;
     boolean mDreamingLockscreen;
@@ -2921,6 +2931,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
         mTopFullscreenOpaqueWindowState = null;
         mForceStatusBar = false;
@@ -2928,12 +2939,13 @@
         
         mHideLockScreen = false;
         mAllowLockscreenWhenOn = false;
-        mDismissKeyguard = false;
+        mDismissKeyguard = DISMISS_KEYGUARD_NONE;
         mShowingLockscreen = false;
         mShowingDream = false;
     }
 
     /** {@inheritDoc} */
+    @Override
     public void applyPostLayoutPolicyLw(WindowState win,
                                 WindowManager.LayoutParams attrs) {
         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw="
@@ -2953,10 +2965,11 @@
             boolean applyWindow = attrs.type >= FIRST_APPLICATION_WINDOW
                     && attrs.type <= LAST_APPLICATION_WINDOW;
             if (attrs.type == TYPE_DREAM) {
-                mShowingDream = true;
-                if (!mDreamingLockscreen) {
-                    applyWindow = true;
-                } else if (win.isVisibleLw() && win.hasDrawnLw()) {
+                // If the lockscreen was showing when the dream started then wait
+                // for the dream to draw before hiding the lockscreen.
+                if (!mDreamingLockscreen
+                        || (win.isVisibleLw() && win.hasDrawnLw())) {
+                    mShowingDream = true;
                     applyWindow = true;
                 }
             }
@@ -2971,9 +2984,12 @@
                     mHideLockScreen = true;
                     mForceStatusBarFromKeyguard = false;
                 }
-                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
+                if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
+                        && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                     if (DEBUG_LAYOUT) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
-                    mDismissKeyguard = true;
+                    mDismissKeyguard = mWinDismissingKeyguard == win ?
+                            DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
+                    mWinDismissingKeyguard = win;
                     mForceStatusBarFromKeyguard = false;
                 }
                 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
@@ -2984,6 +3000,7 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public int finishPostLayoutPolicyLw() {
         int changes = 0;
         boolean topIsFullscreen = false;
@@ -2992,8 +3009,10 @@
                 ? mTopFullscreenOpaqueWindowState.getAttrs()
                 : null;
 
-        // If we are not currently showing a dream, then update the lockscreen
-        // state that will apply if a dream is shown next time.
+        // If we are not currently showing a dream then remember the current
+        // lockscreen state.  We will use this to determine whether the dream
+        // started while the lockscreen was showing and remember this state
+        // while the dream is showing.
         if (!mShowingDream) {
             mDreamingLockscreen = mShowingLockscreen;
         }
@@ -3023,7 +3042,9 @@
                     if (mStatusBar.hideLw(true)) {
                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
 
-                        mHandler.post(new Runnable() { public void run() {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
                             try {
                                 IStatusBarService statusbar = getStatusBarService();
                                 if (statusbar != null) {
@@ -3051,7 +3072,7 @@
         if (mKeyguard != null) {
             if (localLOGV) Log.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard="
                     + mHideLockScreen);
-            if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
+            if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !mKeyguardMediator.isSecure()) {
                 if (mKeyguard.hideLw(true)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
@@ -3059,6 +3080,7 @@
                 }
                 if (mKeyguardMediator.isShowing()) {
                     mHandler.post(new Runnable() {
+                        @Override
                         public void run() {
                             mKeyguardMediator.keyguardDone(false, false);
                         }
@@ -3071,7 +3093,25 @@
                             | FINISH_LAYOUT_REDO_WALLPAPER;
                 }
                 mKeyguardMediator.setHidden(true);
+            } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
+                // This is the case of keyguard isSecure() and not mHideLockScreen.
+                if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
+                    // Only launch the next keyguard unlock window once per window.
+                    if (mKeyguard.showLw(true)) {
+                        changes |= FINISH_LAYOUT_REDO_LAYOUT
+                                | FINISH_LAYOUT_REDO_CONFIG
+                                | FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                    mKeyguardMediator.setHidden(false);
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mKeyguardMediator.dismiss();
+                        }
+                    });
+                }
             } else {
+                mWinDismissingKeyguard = null;
                 if (mKeyguard.showLw(true)) {
                     changes |= FINISH_LAYOUT_REDO_LAYOUT
                             | FINISH_LAYOUT_REDO_CONFIG
@@ -4549,6 +4589,7 @@
                 pw.print(" mForceStatusBarFromKeyguard=");
                 pw.println(mForceStatusBarFromKeyguard);
         pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
+                pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
                 pw.print(" mHomePressed="); pw.println(mHomePressed);
         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
                 pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
index b38a9ed..3dd0a8f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -21,12 +21,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Point;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
@@ -47,10 +50,11 @@
     private final Handler mHandler = new Handler();
     private final KeyguardActivityLauncher mActivityLauncher;
     private final Callbacks mCallbacks;
+    private final WindowManager mWindowManager;
+    private final Point mRenderedSize = new Point();
 
     private View mWidgetView;
     private long mLaunchCameraStart;
-    private boolean mRendered;
     private boolean mActive;
     private boolean mChallengeActive;
     private boolean mTransitioning;
@@ -81,6 +85,7 @@
 
         mCallbacks = callbacks;
         mActivityLauncher = activityLauncher;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     }
 
     public static CameraWidgetFrame create(Context context, Callbacks callbacks,
@@ -141,16 +146,22 @@
     }
 
     public void render() {
-        if (mRendered) return;
-
         try {
             int width = getRootView().getWidth();
             int height = getRootView().getHeight();
-            if (DEBUG) Log.d(TAG, String.format("render [%sx%s] %s",
-                    width, height, Integer.toHexString(hashCode())));
+            if (mRenderedSize.x == width && mRenderedSize.y == height) {
+                if (DEBUG) Log.d(TAG, String.format("already rendered at size=%sx%s",
+                        width, height));
+                return;
+            }
             if (width == 0 || height == 0) {
                 return;
             }
+            if (DEBUG) Log.d(TAG, String.format("render size=%sx%s instance=%s at %s",
+                    width, height,
+                    Integer.toHexString(hashCode()),
+                    SystemClock.uptimeMillis()));
+
             Bitmap offscreen = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
             Canvas c = new Canvas(offscreen);
             mWidgetView.measure(
@@ -159,7 +170,7 @@
             mWidgetView.layout(0, 0, width, height);
             mWidgetView.draw(c);
             ((ImageView)getChildAt(0)).setImageBitmap(offscreen);
-            mRendered = true;
+            mRenderedSize.set(width, height);
         } catch (Throwable t) {
             Log.w(TAG, "Error rendering camera widget", t);
             removeAllViews();
@@ -200,6 +211,7 @@
                 scaleX, scaleY,
                 startCenter, finishCenter));
 
+        enableWindowExitAnimation(false);
         animate()
             .scaleX(scale)
             .scaleY(scale)
@@ -305,11 +317,27 @@
         setScaleX(1);
         setScaleY(1);
         setTranslationY(0);
+        enableWindowExitAnimation(true);
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        if (DEBUG) Log.d(TAG, String.format("onSizeChanged new=%sx%s old=%sx%s at %s",
+                w, h, oldw, oldh, SystemClock.uptimeMillis()));
         mHandler.post(mRenderRunnable);
+        super.onSizeChanged(w, h, oldw, oldh);
+    }
+
+    private void enableWindowExitAnimation(boolean isEnabled) {
+        View root = getRootView();
+        ViewGroup.LayoutParams lp = root.getLayoutParams();
+        if (!(lp instanceof WindowManager.LayoutParams))
+            return;
+        WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
+        int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
+        if (newWindowAnimations != wlp.windowAnimations) {
+            wlp.windowAnimations = newWindowAnimations;
+            mWindowManager.updateViewLayout(root, wlp);
+        }
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
index cae598c..faf0ca0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/FaceUnlock.java
@@ -151,13 +151,6 @@
         }
 
         boolean mWasRunning = mIsRunning;
-        try {
-            if (mService != null) {
-                mService.makeInvisible();
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Caught exception making Face Unlock invisible: " + e.toString());
-        }
 
         stopUi();
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
index 9c21830..db36bcc 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
@@ -87,16 +87,20 @@
         }
     }
 
+    protected abstract int getPasswordTextViewId();
     protected abstract void resetState();
 
     @Override
     protected void onFinishInflate() {
         mLockPatternUtils = new LockPatternUtils(mContext);
 
-        mPasswordEntry = (TextView) findViewById(R.id.passwordEntry);
+        mPasswordEntry = (TextView) findViewById(getPasswordTextViewId());
         mPasswordEntry.setOnEditorActionListener(this);
         mPasswordEntry.addTextChangedListener(this);
 
+        // Set selected property on so the view can send accessibility events.
+        mPasswordEntry.setSelected(true);
+
         // Poke the wakelock any time the text is selected or modified
         mPasswordEntry.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 3a01e64..3b2ded2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -25,19 +25,22 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
@@ -48,13 +51,13 @@
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.widget.RemoteViews.OnClickHandler;
-import android.widget.TextView;
 
 import com.android.internal.R;
 import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.List;
 
 public class KeyguardHostView extends KeyguardViewBase {
@@ -66,11 +69,6 @@
     // also referenced in SecuritySettings.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
 
-    // transport control states
-    private static final int TRANSPORT_GONE = 0;
-    private static final int TRANSPORT_INVISIBLE = 1;
-    private static final int TRANSPORT_VISIBLE = 2;
-
     private AppWidgetHost mAppWidgetHost;
     private KeyguardWidgetPager mAppWidgetContainer;
     private KeyguardSecurityViewFlipper mSecurityViewContainer;
@@ -90,7 +88,6 @@
     private KeyguardViewStateManager mViewStateManager;
 
     private Rect mTempRect = new Rect();
-    private int mTransportState = TRANSPORT_GONE;
 
     /*package*/ interface TransportCallback {
         void onListenerDetached();
@@ -144,7 +141,7 @@
     private int getWidgetPosition(int id) {
         final int children = mAppWidgetContainer.getChildCount();
         for (int i = 0; i < children; i++) {
-            if (mAppWidgetContainer.getChildAt(i).getId() == id) {
+            if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) {
                 return i;
             }
         }
@@ -153,6 +150,8 @@
 
     @Override
     protected void onFinishInflate() {
+        mViewStateManager = new KeyguardViewStateManager();
+
         // Grab instances of and make any necessary changes to the main layouts. Create
         // view state manager and wire up necessary listeners / callbacks.
         mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
@@ -162,8 +161,8 @@
 
         addDefaultWidgets();
         addWidgetsFromSettings();
+        mSwitchPageRunnable.run();
 
-        mViewStateManager = new KeyguardViewStateManager();
         SlidingChallengeLayout slider =
                 (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
         if (slider != null) {
@@ -217,7 +216,6 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mAppWidgetHost.startListening();
-        post(mSwitchPageRunnable);
     }
 
     @Override
@@ -676,13 +674,10 @@
         // Find and show this child.
         final int childCount = mSecurityViewContainer.getChildCount();
 
-        // Do flip animation to the next screen
-        if (false) {
-            mSecurityViewContainer.setInAnimation(
-                    AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_in));
-            mSecurityViewContainer.setOutAnimation(
-                    AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_animate_out));
-        }
+        mSecurityViewContainer.setInAnimation(
+                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in));
+        mSecurityViewContainer.setOutAnimation(
+                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out));
         final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
         for (int i = 0; i < childCount; i++) {
             if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
@@ -864,7 +859,8 @@
         @Override
         LockPatternUtils getLockPatternUtils() {
             return mLockPatternUtils;
-        }};
+        }
+    };
 
     private void addDefaultWidgets() {
         LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -888,14 +884,22 @@
 
                     @Override
                     public void run() {
-                        Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
-                        intent.addFlags(
-                                Intent.FLAG_ACTIVITY_NEW_TASK
-                                | Intent.FLAG_ACTIVITY_SINGLE_TOP
-                                | Intent.FLAG_ACTIVITY_CLEAR_TOP
-                                | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                        mContext.startActivityAsUser(intent,
-                                new UserHandle(UserHandle.USER_CURRENT));
+                        int defaultIconId = 0;
+                        Resources res = KeyguardHostView.this.getContext().getResources();
+                        ComponentName clock = new ComponentName(
+                                res.getString(R.string.widget_default_package_name),
+                                res.getString(R.string.widget_default_class_name));
+                        try {
+                            ActivityInfo activityInfo =
+                                    mContext.getPackageManager().getActivityInfo(clock, 0);
+                            if (activityInfo != null) {
+                                defaultIconId = activityInfo.icon;
+                            }
+                        } catch (PackageManager.NameNotFoundException e) {
+                            defaultIconId = 0;
+                        }
+                        launchPickActivityIntent(R.string.widget_default, defaultIconId, clock,
+                                LockPatternUtils.EXTRA_DEFAULT_WIDGET);
                     }
                 });
                 mCallback.dismiss(false);
@@ -906,6 +910,85 @@
         initializeTransportControl();
     }
 
+    private void launchPickActivityIntent(int defaultLabelId, int defaultIconId,
+            ComponentName defaultComponentName, String defaultTag) {
+        // Create intent to pick widget
+        Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
+
+        int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+        if (appWidgetId != -1) {
+            pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+            pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_SORT, false);
+            pickIntent.putExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER,
+                    AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
+
+            // Add an custom entry for the default
+            AppWidgetProviderInfo defaultInfo = new AppWidgetProviderInfo();
+            ArrayList<AppWidgetProviderInfo> extraInfos = new ArrayList<AppWidgetProviderInfo>();
+            defaultInfo.label = getResources().getString(defaultLabelId);
+            defaultInfo.icon = defaultIconId;
+            defaultInfo.provider = defaultComponentName;
+            extraInfos.add(defaultInfo);
+
+            ArrayList<Bundle> extraExtras = new ArrayList<Bundle>();
+            Bundle b = new Bundle();
+            b.putBoolean(defaultTag, true);
+            extraExtras.add(b);
+
+            // Launch the widget picker
+            pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, extraInfos);
+            pickIntent.putExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, extraExtras);
+            pickIntent.putExtra(Intent.EXTRA_INTENT, getBaseIntent());
+            pickIntent.addFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_SINGLE_TOP
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            mContext.startActivityAsUser(pickIntent,
+                    new UserHandle(UserHandle.USER_CURRENT));
+        } else {
+            Log.e(TAG, "Unable to allocate an AppWidget id in lock screen");
+        }
+    }
+
+    private Intent getBaseIntent() {
+        Intent baseIntent = new Intent(Intent.ACTION_MAIN, null);
+        baseIntent.addCategory(Intent.CATEGORY_DEFAULT);
+
+        Bundle options = new Bundle();
+        options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD);
+        baseIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
+        return baseIntent;
+    }
+
+    private void removeTransportFromWidgetPager() {
+        int page = getWidgetPosition(R.id.keyguard_transport_control);
+        if (page != -1) {
+            mAppWidgetContainer.removeWidget(mTransportControl);
+
+            // XXX keep view attached so we still get show/hide events from AudioManager
+            KeyguardHostView.this.addView(mTransportControl);
+            mTransportControl.setVisibility(View.GONE);
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
+            mTransportControl.post(mSwitchPageRunnable);
+        }
+    }
+
+    private void addTransportToWidgetPager() {
+        if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
+            KeyguardHostView.this.removeView(mTransportControl);
+            // insert to left of camera if it exists, otherwise after right-most widget
+            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
+            int position = 0; // handle no widget case
+            if (lastWidget >= 0) {
+                position = isCameraPage(lastWidget) ? lastWidget : lastWidget + 1;
+            }
+            mAppWidgetContainer.addWidget(mTransportControl, position);
+            mTransportControl.setVisibility(View.VISIBLE);
+        }
+    }
+
     private void initializeTransportControl() {
         mTransportControl =
             (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
@@ -917,24 +1000,14 @@
             mTransportControl.setKeyguardCallback(new TransportCallback() {
                 @Override
                 public void onListenerDetached() {
-                    int page = getWidgetPosition(R.id.keyguard_transport_control);
-                    if (page != -1) {
-                        mAppWidgetContainer.removeView(mTransportControl);
-                        // XXX keep view attached so we still get show/hide events from AudioManager
-                        KeyguardHostView.this.addView(mTransportControl);
-                        mTransportControl.setVisibility(View.GONE);
-                        mTransportState = TRANSPORT_GONE;
-                        mTransportControl.post(mSwitchPageRunnable);
-                    }
+                    removeTransportFromWidgetPager();
+                    mTransportControl.post(mSwitchPageRunnable);
                 }
 
                 @Override
                 public void onListenerAttached() {
-                    if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
-                        KeyguardHostView.this.removeView(mTransportControl);
-                        mAppWidgetContainer.addView(mTransportControl, 0);
-                        mTransportControl.setVisibility(View.VISIBLE);
-                    }
+                    // Transport will be added when playstate changes...
+                    mTransportControl.post(mSwitchPageRunnable);
                 }
 
                 @Override
@@ -1027,7 +1100,7 @@
         saveStickyWidgetIndex();
         Parcelable superState = super.onSaveInstanceState();
         SavedState ss = new SavedState(superState);
-        ss.transportState = mTransportState;
+        ss.transportState = mViewStateManager.getTransportState();
         return ss;
     }
 
@@ -1040,7 +1113,7 @@
         }
         SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
-        mTransportState = ss.transportState;
+        mViewStateManager.setTransportState(ss.transportState);
         post(mSwitchPageRunnable);
     }
 
@@ -1054,12 +1127,14 @@
     }
 
     private void showAppropriateWidgetPage() {
-        boolean isMusicPlaying =
-                mTransportControl.isMusicPlaying() || mTransportState == TRANSPORT_VISIBLE;
+        int state = mViewStateManager.getTransportState();
+        boolean isMusicPlaying = mTransportControl.isMusicPlaying()
+                || state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
         if (isMusicPlaying) {
-            mTransportState = TRANSPORT_VISIBLE;
-        } else if (mTransportState == TRANSPORT_VISIBLE) {
-            mTransportState = TRANSPORT_INVISIBLE;
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
+            addTransportToWidgetPager();
+        } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
+            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
         }
         int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
         mAppWidgetContainer.setCurrentPage(pageToShow);
@@ -1081,7 +1156,7 @@
         // if music playing, show transport
         if (isMusicPlaying) {
             if (DEBUG) Log.d(TAG, "Music playing, show transport");
-            return mAppWidgetContainer.indexOfChild(mTransportControl);
+            return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
         }
 
         // if we have a valid sticky widget, show it
@@ -1119,6 +1194,10 @@
     }
 
     private void enableUserSelectorIfNecessary() {
+        if (!UserManager.supportsMultipleUsers()) {
+            return; // device doesn't support multi-user mode
+        }
+
         // if there are multiple users, we need to enable to multi-user switcher
         UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         List<UserInfo> users = mUm.getUsers(true);
@@ -1201,4 +1280,10 @@
         return false;
     }
 
+    /**
+     *  Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public void dismiss() {
+        showNextSecurityScreenOrFinish(false);
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
index ca78cf9..5e331e1 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -16,6 +16,9 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Handler;
@@ -39,11 +42,15 @@
     static final int BATTERY_LOW_ICON = 0; //R.drawable.ic_lock_idle_low_battery;
 
     static final int SECURITY_MESSAGE_DURATION = 5000;
-    static final String SEPARATOR = " ";
+    protected static final int FADE_DURATION = 750;
+    static final String SEPARATOR = "  ";
 
     // are we showing battery information?
     boolean mShowingBatteryInfo = false;
 
+    // is the bouncer up?
+    boolean mShowingBouncer = false;
+
     // last known plugged in state
     boolean mPluggedIn = false;
 
@@ -68,7 +75,11 @@
         public void run() {
             mMessage = null;
             mShowingMessage = false;
-            update();
+            if (mShowingBouncer) {
+                hideMessage(FADE_DURATION, true);
+            } else {
+                update();
+            }
         }
     };
 
@@ -103,6 +114,18 @@
         }
 
         @Override
+        public void showBouncer(int duration) {
+            mMessageArea.hideMessage(duration, false);
+            mMessageArea.mShowingBouncer = true;
+        }
+
+        @Override
+        public void hideBouncer(int duration) {
+            mMessageArea.showMessage(duration);
+            mMessageArea.mShowingBouncer = false;
+        }
+
+        @Override
         public void setTimeout(int timeoutMs) {
             mMessageArea.mTimeout = timeoutMs;
         }
@@ -139,6 +162,7 @@
     }
 
     public void securityMessageChanged() {
+        setAlpha(1f);
         mShowingMessage = true;
         update();
         mHandler.removeCallbacks(mClearMessageRunnable);
@@ -212,4 +236,23 @@
         return string;
     }
 
+    private void hideMessage(int duration, boolean thenUpdate) {
+        Animator anim = ObjectAnimator.ofFloat(this, "alpha", 0f);
+        anim.setDuration(duration);
+        if (thenUpdate) {
+            anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                        public void onAnimationEnd(Animator animation) {
+                        update();
+                    }
+                });
+        }
+        anim.start();
+    }
+
+    private void showMessage(int duration) {
+        Animator anim = ObjectAnimator.ofFloat(this, "alpha", 1f);
+        anim.setDuration(duration);
+        anim.start();
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
index bea9aec..1255712 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
@@ -47,6 +47,11 @@
     }
 
     @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
@@ -59,6 +64,7 @@
                     verifyPasswordAndUnlock();
                 }
             });
+            ok.setOnHoverListener(new NumPadKey.LiftToActivateListener(getContext()));
         }
 
         // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index b6334f0..b35450c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -60,6 +60,11 @@
     }
 
     @Override
+    protected int getPasswordTextViewId() {
+        return R.id.passwordEntry;
+    }
+
+    @Override
     public boolean needsInput() {
         return true;
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
index f6a90c5..04ab0a2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityContainer.java
@@ -1,11 +1,20 @@
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 
+import com.android.internal.R;
+
 public class KeyguardSecurityContainer extends FrameLayout {
 
+    private float mBackgroundAlpha;
+    private Drawable mBackgroundDrawable;
+
     public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -16,5 +25,44 @@
 
     public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        mBackgroundDrawable = context.getResources().getDrawable(R.drawable.kg_bouncer_bg_white);
+    }
+
+    public void setBackgroundAlpha(float alpha) {
+        if (Float.compare(mBackgroundAlpha, alpha) != 0) {
+            mBackgroundAlpha = alpha;
+            invalidate();
+        }
+    }
+
+    public float getBackgroundAlpha() {
+        return mBackgroundAlpha;
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        if (mBackgroundAlpha > 0.0f && mBackgroundDrawable != null) {
+            Drawable bg = mBackgroundDrawable;
+            bg.setAlpha((int) (mBackgroundAlpha * 255));
+            bg.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
+            bg.draw(canvas);
+        }
+        super.dispatchDraw(canvas);
+    }
+
+    public void showBouncer(int duration) {
+        SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+        message.showBouncer(duration);
+        Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 1f);
+        anim.setDuration(duration);
+        anim.start();
+    }
+
+    public void hideBouncer(int duration) {
+        SecurityMessageDisplay message = new KeyguardMessageArea.Helper(this);
+        message.hideBouncer(duration);
+        Animator anim = ObjectAnimator.ofFloat(this, "BackgroundAlpha", 0f);
+        anim.setDuration(duration);
+        anim.start();
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index b4bd6e9..7100f1c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -327,6 +327,14 @@
     }
 
     @Override
+    public void showBouncer(int duration) {
+    }
+
+    @Override
+    public void hideBouncer(int duration) {
+    }
+
+    @Override
     public void setTimeout(int timeout_ms) {
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
index 89f220a..d284602 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardTransportControlView.java
@@ -40,6 +40,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 
@@ -49,14 +50,13 @@
 /**
  * This is the widget responsible for showing music controls in keyguard.
  */
-public class KeyguardTransportControlView extends KeyguardWidgetFrame implements OnClickListener {
+public class KeyguardTransportControlView extends FrameLayout implements OnClickListener {
 
     private static final int MSG_UPDATE_STATE = 100;
     private static final int MSG_SET_METADATA = 101;
     private static final int MSG_SET_TRANSPORT_CONTROLS = 102;
     private static final int MSG_SET_ARTWORK = 103;
     private static final int MSG_SET_GENERATION_ID = 104;
-    private static final int MAXDIM = 512;
     private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
     protected static final boolean DEBUG = false;
     protected static final String TAG = "TransportControlView";
@@ -260,14 +260,6 @@
         mAttached = false;
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-//        int dim = Math.min(MAXDIM, Math.max(getWidth(), getHeight()));
-//        Log.v(TAG, "setting max bitmap size: " + dim + "x" + dim);
-//        mAudioManager.remoteControlDisplayUsesBitmapSize(mIRCD, dim, dim);
-    }
-
     class Metadata {
         private String artist;
         private String trackTitle;
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 9fa14f5..b224c08 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -65,6 +65,7 @@
     private FrameLayout mKeyguardHost;
     private KeyguardHostView mKeyguardView;
 
+    private boolean mScreenOn = false;
     private LockPatternUtils mLockPatternUtils;
 
     public interface ShowListener {
@@ -302,6 +303,7 @@
 
     public synchronized void onScreenTurnedOff() {
         if (DEBUG) Log.d(TAG, "onScreenTurnedOff()");
+        mScreenOn = false;
         if (mKeyguardView != null) {
             mKeyguardView.onScreenTurnedOff();
         }
@@ -310,6 +312,7 @@
     public synchronized void onScreenTurnedOn(
             final KeyguardViewManager.ShowListener showListener) {
         if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
+        mScreenOn = true;
         if (mKeyguardView != null) {
             mKeyguardView.onScreenTurnedOn();
 
@@ -398,6 +401,15 @@
     }
 
     /**
+     * Dismisses the keyguard by going to the next screen or making it gone.
+     */
+    public synchronized void dismiss() {
+        if (mScreenOn) {
+            mKeyguardView.dismiss();
+        }
+    }
+
+    /**
      * @return Whether the keyguard is showing
      */
     public synchronized boolean isShowing() {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index bc12e96..53cbb39 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -813,9 +813,7 @@
     }
 
     /**
-     * Enable the keyguard if the settings are appropriate.  Return true if all
-     * work that will happen is done; returns false if the caller can wait for
-     * the keyguard to be shown.
+     * Enable the keyguard if the settings are appropriate.
      */
     private void doKeyguardLocked(Bundle options) {
         // if another app is disabling us, don't show
@@ -867,6 +865,13 @@
     }
 
     /**
+     * Dismiss the keyguard through the security layers.
+     */
+    public void dismiss() {
+        mKeyguardViewManager.dismiss();
+    }
+
+    /**
      * Send message to keyguard telling it to reset its state.
      * @param options options about how to show the keyguard
      * @see #handleReset()
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
index 85245ba..c89e880 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -32,6 +32,13 @@
     private static final int SCREEN_ON_RING_HINT_DELAY = 300;
     Handler mMainQueue = new Handler(Looper.myLooper());
 
+    // transport control states
+    static final int TRANSPORT_GONE = 0;
+    static final int TRANSPORT_INVISIBLE = 1;
+    static final int TRANSPORT_VISIBLE = 2;
+
+    private int mTransportState = TRANSPORT_GONE;
+
     int mLastScrollState = SlidingChallengeLayout.SCROLL_STATE_IDLE;
 
     // Paged view state
@@ -58,6 +65,13 @@
         return false;
     }
 
+    public boolean isChallengeOverlapping() {
+        if (mChallengeLayout != null) {
+            return mChallengeLayout.isChallengeOverlapping();
+        }
+        return false;
+    }
+
     public void setSecurityViewContainer(KeyguardSecurityView container) {
         mKeyguardSecurityContainer = container;
     }
@@ -79,6 +93,14 @@
         mChallengeLayout.showBouncer();
     }
 
+    public void fadeOutSecurity(int duration) {
+        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
+    }
+
+    public void fadeInSecurity(int duration) {
+        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
+    }
+
     public void onPageSwitch(View newPage, int newPageIndex) {
         // Reset the previous page size and ensure the current page is sized appropriately.
         // We only modify the page state if it is not currently under control by the slider.
@@ -207,4 +229,12 @@
 
         mMainQueue.postDelayed(mHideHintsRunnable, SCREEN_ON_HINT_DURATION);
     }
+
+    public void setTransportState(int state) {
+        mTransportState = state;
+    }
+
+    public int getTransportState() {
+        return mTransportState;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
index cf16ef2..2e83b42 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetCarousel.java
@@ -15,9 +15,19 @@
  */
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
 
 import com.android.internal.R;
 
@@ -26,6 +36,8 @@
     private float mAdjacentPagesAngle;
     private static float MAX_SCROLL_PROGRESS = 1.3f;
     private static float CAMERA_DISTANCE = 10000;
+    protected AnimatorSet mChildrenTransformsAnimator;
+    float[] mTmpTransform = new float[3];
 
     public KeyguardWidgetCarousel(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -51,10 +63,10 @@
         float scrollProgress = getScrollProgress(screenCenter, child, index);
         if (!isOverScrollChild(index, scrollProgress)) {
             scrollProgress = getBoundedScrollProgress(screenCenter, child, index);
-            float alpha = 1 - Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
+            float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS);
             return alpha;
         } else {
-            return 1f;
+            return 1.0f;
         }
     }
 
@@ -67,22 +79,22 @@
             for (int i = 0; i < getChildCount(); i++) {
                 KeyguardWidgetFrame child = getWidgetPageAt(i);
                 if (child != null) {
-                    float alpha = getAlphaForPage(screenCenter, i);
-                    child.setBackgroundAlpha(alpha);
-                    child.setContentAlpha(alpha);
+                    child.setBackgroundAlpha(getOutlineAlphaForPage(screenCenter, i));
+                    child.setContentAlpha(getAlphaForPage(screenCenter, i));
                 }
             }
         }
-
     }
 
     @Override
     protected void screenScrolled(int screenCenter) {
         mScreenCenter = screenCenter;
         updatePageAlphaValues(screenCenter);
+        if (isReordering(false)) return;
         for (int i = 0; i < getChildCount(); i++) {
             KeyguardWidgetFrame v = getWidgetPageAt(i);
             float scrollProgress = getScrollProgress(screenCenter, v, i);
+            float boundedProgress = getBoundedScrollProgress(screenCenter, v, i);
             if (v == mDragView || v == null) continue;
             v.setCameraDistance(CAMERA_DISTANCE);
 
@@ -90,17 +102,15 @@
                 v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
                 v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
             } else {
-                scrollProgress = getBoundedScrollProgress(screenCenter, v, i);
                 int width = v.getMeasuredWidth();
-                float pivotX = (width / 2f) + scrollProgress * (width / 2f);
+                float pivotX = (width / 2f) + boundedProgress * (width / 2f);
                 float pivotY = v.getMeasuredHeight() / 2;
-                float rotationY = - mAdjacentPagesAngle * scrollProgress;
+                float rotationY = - mAdjacentPagesAngle * boundedProgress;
                 v.setPivotX(pivotX);
                 v.setPivotY(pivotY);
                 v.setRotationY(rotationY);
                 v.setOverScrollAmount(0f, false);
             }
-
             float alpha = v.getAlpha();
             // If the view has 0 alpha, we set it to be invisible so as to prevent
             // it from accepting touches
@@ -111,4 +121,139 @@
             }
         }
     }
+
+    void animatePagesToNeutral() {
+        if (mChildrenTransformsAnimator != null) {
+            mChildrenTransformsAnimator.cancel();
+            mChildrenTransformsAnimator = null;
+        }
+
+        int count = getChildCount();
+        PropertyValuesHolder alpha;
+        PropertyValuesHolder outlineAlpha;
+        PropertyValuesHolder rotationY;
+        ArrayList<Animator> anims = new ArrayList<Animator>();
+
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+            if (!inVisibleRange) {
+                child.setRotationY(0f);
+            }
+            alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f);
+            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha",
+                    KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
+            rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f);
+            ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY);
+            child.setVisibility(VISIBLE);
+            if (!inVisibleRange) {
+                a.setInterpolator(mSlowFadeInterpolator);
+            }
+            anims.add(a);
+        }
+
+        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+        mChildrenTransformsAnimator = new AnimatorSet();
+        mChildrenTransformsAnimator.playTogether(anims);
+
+        mChildrenTransformsAnimator.setDuration(duration);
+        mChildrenTransformsAnimator.start();
+    }
+
+    private void getTransformForPage(int screenCenter, int index, float[] transform) {
+        View child = getChildAt(index);
+        float boundedProgress = getBoundedScrollProgress(screenCenter, child, index);
+        float rotationY = - mAdjacentPagesAngle * boundedProgress;
+        int width = child.getMeasuredWidth();
+        float pivotX = (width / 2f) + boundedProgress * (width / 2f);
+        float pivotY = child.getMeasuredHeight() / 2;
+
+        transform[0] = pivotX;
+        transform[1] = pivotY;
+        transform[2] = rotationY;
+    }
+
+    Interpolator mFastFadeInterpolator = new Interpolator() {
+        Interpolator mInternal = new DecelerateInterpolator(1.5f);
+        float mFactor = 2.5f;
+        @Override
+        public float getInterpolation(float input) {
+            return mInternal.getInterpolation(Math.min(mFactor * input, 1f));
+        }
+    };
+
+    Interpolator mSlowFadeInterpolator = new Interpolator() {
+        Interpolator mInternal = new AccelerateInterpolator(1.5f);
+        float mFactor = 1.3f;
+        @Override
+        public float getInterpolation(float input) {
+            input -= (1 - 1 / mFactor);
+            input = mFactor * Math.max(input, 0f);
+            return mInternal.getInterpolation(input);
+        }
+    };
+
+    void animatePagesToCarousel() {
+        if (mChildrenTransformsAnimator != null) {
+            mChildrenTransformsAnimator.cancel();
+            mChildrenTransformsAnimator = null;
+        }
+
+        int count = getChildCount();
+        PropertyValuesHolder alpha;
+        PropertyValuesHolder outlineAlpha;
+        PropertyValuesHolder rotationY;
+        PropertyValuesHolder pivotX;
+        PropertyValuesHolder pivotY;
+        ArrayList<Animator> anims = new ArrayList<Animator>();
+
+        for (int i = 0; i < count; i++) {
+            KeyguardWidgetFrame child = getWidgetPageAt(i);
+            float finalAlpha = getAlphaForPage(mScreenCenter, i);
+            float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i);
+            getTransformForPage(mScreenCenter, i, mTmpTransform);
+
+            boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1);
+
+            ObjectAnimator a;
+            alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha);
+            outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha);
+            pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]);
+            pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]);
+            rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]);
+
+            if (inVisibleRange) {
+                // for the central pages we animate into a rotated state
+                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha,
+                        pivotX, pivotY, rotationY);
+            } else {
+                a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha);
+                a.setInterpolator(mFastFadeInterpolator);
+            }
+            anims.add(a);
+        }
+
+        int duration = REORDERING_ZOOM_IN_OUT_DURATION;
+        mChildrenTransformsAnimator = new AnimatorSet();
+        mChildrenTransformsAnimator.playTogether(anims);
+
+        mChildrenTransformsAnimator.setDuration(duration);
+        mChildrenTransformsAnimator.start();
+    }
+
+    protected void reorderStarting() {
+        mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+        animatePagesToNeutral();
+    }
+
+    protected boolean zoomIn(final Runnable onCompleteRunnable) {
+        animatePagesToCarousel();
+        return super.zoomIn(onCompleteRunnable);
+    }
+
+    @Override
+    protected void onEndReordering() {
+        super.onEndReordering();
+        mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION);
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index e9c90a7..b1ff049 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -62,7 +62,7 @@
     private float mBackgroundAlphaMultiplier = 1.0f;
     private Drawable mBackgroundDrawable;
     private Rect mBackgroundRect = new Rect();
-    private static int mSmallWidgetHeight;
+    private int mSmallWidgetHeight;
 
     // Multiple callers may try and adjust the alpha of the frame. When a caller shows
     // the outlines, we give that caller control, and nobody else can fade them out.
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index 800ccc0..667b2d6 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -24,7 +24,10 @@
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -33,7 +36,6 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
-
 import com.android.internal.widget.LockPatternUtils;
 
 import java.util.ArrayList;
@@ -46,7 +48,7 @@
     protected static float OVERSCROLL_MAX_ROTATION = 30;
     private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
 
-    private KeyguardViewStateManager mViewStateManager;
+    protected KeyguardViewStateManager mViewStateManager;
     private LockPatternUtils mLockPatternUtils;
 
     // Related to the fading in / out background outlines
@@ -58,15 +60,20 @@
     protected int mScreenCenter;
     private boolean mHasLayout = false;
     private boolean mHasMeasure = false;
-    private boolean mShowHintsOnLayout = false;
+    boolean showHintsAfterLayout = false;
 
     private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
+    private static final String TAG = "KeyguardWidgetPager";
 
     private int mPage = 0;
     private Callbacks mCallbacks;
 
     private boolean mCameraWidgetEnabled;
 
+    // Background threads to deal with persistence
+    private HandlerThread mBgPersistenceWorkerThread;
+    private Handler mBgPersistenceWorkerHandler;
+
     public KeyguardWidgetPager(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -85,6 +92,9 @@
 
         Resources r = getResources();
         mCameraWidgetEnabled = r.getBoolean(R.bool.kg_enable_camera_default_widget);
+        mBgPersistenceWorkerThread = new HandlerThread("KeyguardWidgetPager Persistence");
+        mBgPersistenceWorkerThread.start();
+        mBgPersistenceWorkerHandler = new Handler(mBgPersistenceWorkerThread.getLooper());
     }
 
     public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
@@ -179,17 +189,28 @@
 
 
     public void onRemoveView(View v) {
-        int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        mLockPatternUtils.removeAppWidget(appWidgetId);
+        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+        mBgPersistenceWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.removeAppWidget(appWidgetId);
+            }
+        });
     }
 
-    public void onAddView(View v, int index) {
-        int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
-        getVisiblePages(mTempVisiblePagesRange);
-        boundByReorderablePages(true, mTempVisiblePagesRange);
+    public void onAddView(View v, final int index) {
+        final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
+        final int[] pagesRange = new int[mTempVisiblePagesRange.length];
+        getVisiblePages(pagesRange);
+        boundByReorderablePages(true, pagesRange);
         // Subtract from the index to take into account pages before the reorderable
         // pages (e.g. the "add widget" page)
-        mLockPatternUtils.addAppWidget(appWidgetId, index - mTempVisiblePagesRange[0]);
+        mBgPersistenceWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
+            }
+        });
     }
 
     /*
@@ -226,25 +247,40 @@
         }
     }
 
-    // We enforce that all children are KeyguardWidgetFrames
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
     @Override
     public void addView(View child, int index) {
         enforceKeyguardWidgetFrame(child);
         super.addView(child, index);
     }
 
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
     @Override
     public void addView(View child, int width, int height) {
         enforceKeyguardWidgetFrame(child);
         super.addView(child, width, height);
     }
 
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
     @Override
     public void addView(View child, LayoutParams params) {
         enforceKeyguardWidgetFrame(child);
         super.addView(child, params);
     }
 
+    /**
+     * Use addWidget() instead.
+     * @deprecated
+     */
     @Override
     public void addView(View child, int index, LayoutParams params) {
         enforceKeyguardWidgetFrame(child);
@@ -272,7 +308,9 @@
         if (mViewStateManager != null) {
             mViewStateManager.onPageBeginMoving();
         }
-        showOutlinesAndSidePages();
+        if (!isReordering(false)) {
+            showOutlinesAndSidePages();
+        }
         userActivity();
     }
 
@@ -281,17 +319,22 @@
         if (mViewStateManager != null) {
             mViewStateManager.onPageEndMoving();
         }
-        hideOutlinesAndSidePages();
+
+        // In the reordering case, the pages will be faded appropriately on completion
+        // of the zoom in animation.
+        if (!isReordering(false)) {
+            hideOutlinesAndSidePages();
+        }
     }
 
-    private void enablePageLayers() {
+    protected void enablePageLayers() {
         int children = getChildCount();
         for (int i = 0; i < children; i++) {
             getWidgetPageAt(i).enableHardwareLayersForContent();
         }
     }
 
-    private void disablePageLayers() {
+    protected void disablePageLayers() {
         int children = getChildCount();
         for (int i = 0; i < children; i++) {
             getWidgetPageAt(i).disableHardwareLayersForContent();
@@ -414,17 +457,21 @@
         return true;
     }
     boolean isMusicWidgetVisible() {
-        // TODO: Make proper test once we have music in the list
-        return false;
+        return mViewStateManager.getTransportState() != KeyguardViewStateManager.TRANSPORT_GONE;
     }
     boolean isCameraWidgetVisible() {
         return mCameraWidgetEnabled;
     }
 
+    protected void reorderStarting() {
+        showOutlinesAndSidePages();
+    }
+
     @Override
     protected void onStartReordering() {
         super.onStartReordering();
-        showOutlinesAndSidePages();
+        enablePageLayers();
+        reorderStarting();
     }
 
     @Override
@@ -434,7 +481,6 @@
     }
 
     void showOutlinesAndSidePages() {
-        enablePageLayers();
         animateOutlinesAndSidePages(true);
     }
 
@@ -447,7 +493,7 @@
             showOutlinesAndSidePages();
         } else {
             // The layout hints depend on layout being run once
-            mShowHintsOnLayout = true;
+            showHintsAfterLayout = true;
         }
     }
 
@@ -458,16 +504,17 @@
         mHasLayout = false;
     }
 
+    @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (mShowHintsOnLayout) {
+        if (showHintsAfterLayout) {
             post(new Runnable() {
                 @Override
                 public void run() {
                     showOutlinesAndSidePages();
                 }
             });
-            mShowHintsOnLayout = false;
+            showHintsAfterLayout = false;
         }
         mHasLayout = true;
     }
@@ -504,17 +551,22 @@
     }
 
     void animateOutlinesAndSidePages(final boolean show) {
+        animateOutlinesAndSidePages(show, -1);
+    }
+
+    void animateOutlinesAndSidePages(final boolean show, int duration) {
         if (mChildrenOutlineFadeAnimation != null) {
             mChildrenOutlineFadeAnimation.cancel();
             mChildrenOutlineFadeAnimation = null;
         }
-
         int count = getChildCount();
         PropertyValuesHolder alpha;
         ArrayList<Animator> anims = new ArrayList<Animator>();
 
-        int duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
-            CHILDREN_OUTLINE_FADE_OUT_DURATION;
+        if (duration == -1) {
+            duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
+                CHILDREN_OUTLINE_FADE_OUT_DURATION;
+        }
 
         int curPage = getNextPage();
         for (int i = 0; i < count; i++) {
@@ -541,6 +593,12 @@
         mChildrenOutlineFadeAnimation.setDuration(duration);
         mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
+            public void onAnimationStart(Animator animation) {
+                if (show) {
+                    enablePageLayers();
+                }
+            }
+            @Override
             public void onAnimationEnd(Animator animation) {
                 if (!show) {
                     disablePageLayers();
@@ -589,9 +647,37 @@
     @Override
     public boolean onLongClick(View v) {
         // Disallow long pressing to reorder if the challenge is showing
-        if (!mViewStateManager.isChallengeShowing() && startReordering()) {
+        boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
+                mViewStateManager.isChallengeOverlapping();
+        if (!isChallengeOverlapping && startReordering()) {
             return true;
         }
         return false;
     }
+
+    public void removeWidget(View view) {
+        if (view instanceof KeyguardWidgetFrame) {
+            removeView(view);
+        } else {
+            // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
+            // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
+            int pos = getWidgetPageIndex(view);
+            if (pos != -1) {
+                KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
+                frame.removeView(view);
+                removeView(frame);
+            } else {
+                Slog.w(TAG, "removeWidget() can't find:" + view);
+            }
+        }
+    }
+
+    public int getWidgetPageIndex(View view) {
+        if (view instanceof KeyguardWidgetFrame) {
+            return indexOfChild(view);
+        } else {
+            // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
+            return indexOfChild((KeyguardWidgetFrame)view.getParent());
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
index a207f5d..b38eb28 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
@@ -35,8 +39,9 @@
 
     public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
     public static final int VERTICAL = LinearLayout.VERTICAL;
+    protected static final int ANIMATE_BOUNCE_DURATION = 750;
 
-    private View mChallengeView;
+    private KeyguardSecurityContainer mChallengeView;
     private View mUserSwitcherView;
     private View mScrimView;
     private OnBouncerStateChangedListener mBouncerListener;
@@ -87,7 +92,19 @@
         if (mIsBouncing) return;
         mIsBouncing = true;
         if (mScrimView != null) {
-            mScrimView.setVisibility(GONE);
+            if (mChallengeView != null) {
+                mChallengeView.showBouncer(ANIMATE_BOUNCE_DURATION);
+            }
+
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 1f);
+            anim.setDuration(ANIMATE_BOUNCE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mScrimView.setVisibility(VISIBLE);
+                }
+            });
+            anim.start();
         }
         if (mBouncerListener != null) {
             mBouncerListener.onBouncerStateChanged(true);
@@ -99,7 +116,19 @@
         if (!mIsBouncing) return;
         mIsBouncing = false;
         if (mScrimView != null) {
-            mScrimView.setVisibility(GONE);
+            if (mChallengeView != null) {
+                mChallengeView.hideBouncer(ANIMATE_BOUNCE_DURATION);
+            }
+
+            Animator anim = ObjectAnimator.ofFloat(mScrimView, "alpha", 0f);
+            anim.setDuration(ANIMATE_BOUNCE_DURATION);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mScrimView.setVisibility(INVISIBLE);
+                }
+            });
+            anim.start();
         }
         if (mBouncerListener != null) {
             mBouncerListener.onBouncerStateChanged(false);
@@ -131,7 +160,8 @@
             mScrimView.setOnClickListener(null);
         }
         mScrimView = scrim;
-        mScrimView.setVisibility(mIsBouncing ? VISIBLE : GONE);
+        mScrimView.setAlpha(mIsBouncing ? 1.0f : 0.0f);
+        mScrimView.setVisibility(mIsBouncing ? VISIBLE : INVISIBLE);
         mScrimView.setFocusable(true);
         mScrimView.setOnClickListener(mScrimClickListener);
     }
@@ -165,7 +195,11 @@
                     throw new IllegalStateException(
                             "There may only be one child of type challenge");
                 }
-                mChallengeView = child;
+                if (!(child instanceof KeyguardSecurityContainer)) {
+                    throw new IllegalArgumentException(
+                            "Challenge must be a KeyguardSecurityContainer");
+                }
+                mChallengeView = (KeyguardSecurityContainer) child;
             } else if (lp.childType == LayoutParams.CHILD_TYPE_USER_SWITCHER) {
                 if (mUserSwitcherView != null) {
                     throw new IllegalStateException(
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
index 060cc03..ca36007 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
@@ -22,7 +22,9 @@
 import android.text.style.TextAppearanceSpan;
 import android.util.AttributeSet;
 import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Button;
 import android.widget.TextView;
 
@@ -72,6 +74,7 @@
         setTextViewResId(a.getResourceId(R.styleable.NumPadKey_textView, 0));
 
         setOnClickListener(mListener);
+        setOnHoverListener(new LiftToActivateListener(context));
 
         mEnableHaptics = new LockPatternUtils(context).isTactileFeedbackEnabled();
 
@@ -113,4 +116,45 @@
                     | HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
         }
     }
+
+    /**
+     * Hover listener that implements lift-to-activate interaction for
+     * accessibility. May be added to multiple views.
+     */
+    static class LiftToActivateListener implements View.OnHoverListener {
+        /** Manager used to query accessibility enabled state. */
+        private final AccessibilityManager mAccessibilityManager;
+
+        public LiftToActivateListener(Context context) {
+            mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+                    Context.ACCESSIBILITY_SERVICE);
+        }
+
+        @Override
+        public boolean onHover(View v, MotionEvent event) {
+            // When touch exploration is turned on, lifting a finger while
+            // inside the view bounds should perform a click action.
+            if (mAccessibilityManager.isEnabled()
+                    && mAccessibilityManager.isTouchExplorationEnabled()) {
+                switch (event.getActionMasked()) {
+                    case MotionEvent.ACTION_HOVER_ENTER:
+                        // Lift-to-type temporarily disables double-tap
+                        // activation.
+                        v.setClickable(false);
+                        break;
+                    case MotionEvent.ACTION_HOVER_EXIT:
+                        final int x = (int) event.getX();
+                        final int y = (int) event.getY();
+                        if ((x > v.getPaddingLeft()) && (y > v.getPaddingTop())
+                                && (x < v.getWidth() - v.getPaddingRight())
+                                && (y < v.getHeight() - v.getPaddingBottom())) {
+                            v.performClick();
+                        }
+                        v.setClickable(true);
+                        break;
+                }
+            }
+            return false;
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
index 657a31f..c93b11a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -1995,7 +1995,7 @@
     }
 
     // "Zooms out" the PagedView to reveal more side pages
-    boolean zoomOut() {
+    protected boolean zoomOut() {
         if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
             mZoomInOutAnim.cancel();
         }
@@ -2072,15 +2072,15 @@
 
         // If we haven't flung-to-delete the current child, then we just animate the drag view
         // back into position
+        final Runnable onCompleteRunnable = new Runnable() {
+            @Override
+            public void run() {
+                onEndReordering();
+            }
+        };
         if (!mIsFlingingToDelete) {
             mPostReorderingPreZoomInRunnable = new Runnable() {
                 public void run() {
-                    Runnable onCompleteRunnable = new Runnable() {
-                        @Override
-                        public void run() {
-                            onEndReordering();
-                        }
-                    };
                     zoomIn(onCompleteRunnable);
                 };
             };
@@ -2091,11 +2091,13 @@
             snapToPage(indexOfChild(mDragView), 0);
             // Animate the drag view back to the front position
             animateDragViewToOriginalPosition();
+        } else {
+            zoomIn(onCompleteRunnable);
         }
     }
 
     // "Zooms in" the PagedView to highlight the current page
-    boolean zoomIn(final Runnable onCompleteRunnable) {
+    protected boolean zoomIn(final Runnable onCompleteRunnable) {
         if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
             mZoomInOutAnim.cancel();
         }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
index ec6472f..7760279 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SecurityMessageDisplay.java
@@ -24,4 +24,8 @@
     public void setMessage(int resId, boolean important, Object... formatArgs);
 
     public void setTimeout(int timeout_ms);
+
+    public void showBouncer(int animationDuration);
+
+    public void hideBouncer(int animationDuration);
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
index 35eccbb..2e735a0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -16,11 +16,15 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
@@ -61,10 +65,12 @@
     private Drawable mHandleDrawable;
     private Drawable mFrameDrawable;
     private Drawable mDragIconDrawable;
+    private boolean mEdgeCaptured;
 
     // Initialized during measurement from child layoutparams
     private View mChallengeView;
     private View mScrimView;
+    private View mWidgetsView;
 
     // Range: 0 (fully hidden) to 1 (fully visible)
     private float mChallengeOffset = 1.f;
@@ -110,9 +116,14 @@
 
     float mHandleAlpha;
     float mFrameAlpha;
+    float mFrameAnimationTarget = Float.MIN_VALUE;
     private ObjectAnimator mHandleAnimation;
     private ObjectAnimator mFrameAnimation;
 
+    private final Rect mTempRect = new Rect();
+
+    private boolean mHasGlowpad;
+
     static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
             new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
         @Override
@@ -237,12 +248,12 @@
         mMinVelocity = vc.getScaledMinimumFlingVelocity();
         mMaxVelocity = vc.getScaledMaximumFlingVelocity();
 
-        mDragHandleEdgeSlop = getResources().getDimensionPixelSize(
-                R.dimen.kg_edge_swipe_region_size);
+        final Resources res = getResources();
+        mDragHandleEdgeSlop = res.getDimensionPixelSize(R.dimen.kg_edge_swipe_region_size);
 
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 
-        final float density = getResources().getDisplayMetrics().density;
+        final float density = res.getDisplayMetrics().density;
 
         // top half of the lock icon, plus another 25% to be sure
         mDragHandleClosedAbove = (int) (DRAG_HANDLE_CLOSED_ABOVE * density + 0.5f);
@@ -251,7 +262,7 @@
         mDragHandleOpenBelow = (int) (DRAG_HANDLE_OPEN_BELOW * density + 0.5f);
 
         // how much space to account for in the handle when closed
-        mChallengeBottomBound = mDragHandleClosedBelow;
+        mChallengeBottomBound = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
 
         setWillNotDraw(false);
     }
@@ -293,21 +304,43 @@
         mHandleAnimation.start();
     }
 
-    void animateFrame(boolean visible, boolean full) {
+    void animateFrame(final boolean visible, final boolean full) {
         if (mFrameDrawable == null) return;
 
-        if (mFrameAnimation != null) {
-            mFrameAnimation.cancel();
-            mFrameAnimation = null;
-        }
         final float targetAlpha = visible ? (full ? 1.f : 0.5f) : 0.f;
-        if (targetAlpha == mFrameAlpha) {
+        if (mFrameAnimation != null && targetAlpha != mFrameAnimationTarget) {
+            mFrameAnimation.cancel();
+            mFrameAnimationTarget = Float.MIN_VALUE;
+        }
+        if (targetAlpha == mFrameAlpha || targetAlpha == mFrameAnimationTarget) {
             return;
         }
+        mFrameAnimationTarget = targetAlpha;
 
         mFrameAnimation = ObjectAnimator.ofFloat(this, FRAME_ALPHA, targetAlpha);
         mFrameAnimation.setInterpolator(sHandleFadeInterpolator);
         mFrameAnimation.setDuration(HANDLE_ANIMATE_DURATION);
+        mFrameAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mFrameAnimationTarget = Float.MIN_VALUE;
+
+                if (!visible && full && mChallengeView != null) {
+                    // Mess with padding/margin to remove insets on the bouncer frame.
+                    mChallengeView.setPadding(0, 0, 0, 0);
+                    LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
+                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
+                    mChallengeView.setLayoutParams(lp);
+                }
+                mFrameAnimation = null;
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mFrameAnimationTarget = Float.MIN_VALUE;
+                mFrameAnimation = null;
+            }
+        });
         mFrameAnimation.start();
     }
 
@@ -370,7 +403,9 @@
             mScrollState = state;
 
             animateHandle(state == SCROLL_STATE_IDLE && !mChallengeShowing);
-            animateFrame(false , false);
+            if (!mIsBouncing) {
+                animateFrame(false, false);
+            }
             if (mScrollListener != null) {
                 mScrollListener.onScrollStateChanged(state);
             }
@@ -380,6 +415,7 @@
     void completeChallengeScroll() {
         setChallengeShowing(mChallengeOffset != 0);
         setScrollState(SCROLL_STATE_IDLE);
+        mChallengeView.setLayerType(LAYER_TYPE_NONE, null);
     }
 
     void setScrimView(View scrim) {
@@ -461,7 +497,22 @@
         if (mScrimView != null) {
             mScrimView.setVisibility(VISIBLE);
         }
+
+        // Mess with padding/margin to inset the bouncer frame.
+        // We have more space available to us otherwise.
+        if (mChallengeView != null) {
+            if (mFrameDrawable == null || !mFrameDrawable.getPadding(mTempRect)) {
+                mTempRect.set(0, 0, 0, 0);
+            }
+            mChallengeView.setPadding(mTempRect.left, mTempRect.top, mTempRect.right,
+                    mTempRect.bottom);
+            final LayoutParams lp = (LayoutParams) mChallengeView.getLayoutParams();
+            lp.leftMargin = lp.rightMargin = getChallengeMargin(false);
+            mChallengeView.setLayoutParams(lp);
+        }
+
         animateFrame(true, true);
+
         if (mBouncerListener != null) {
             mBouncerListener.onBouncerStateChanged(true);
         }
@@ -470,17 +521,26 @@
     @Override
     public void hideBouncer() {
         if (!mIsBouncing) return;
-        setChallengeShowing(false);
+        showChallenge(false);
         mIsBouncing = false;
         if (mScrimView != null) {
             mScrimView.setVisibility(GONE);
         }
-        animateFrame(false, false);
+        animateFrame(false, true);
         if (mBouncerListener != null) {
             mBouncerListener.onBouncerStateChanged(false);
         }
     }
 
+    private int getChallengeMargin(boolean expanded) {
+        return expanded && mHasGlowpad ? 0 : mDragHandleEdgeSlop;
+    }
+
+    private float getChallengeAlpha() {
+        float x = mChallengeOffset - 1;
+        return x * x * x + 1.f;
+    }
+
     @Override
     public void requestDisallowInterceptTouchEvent(boolean allowIntercept) {
         // We'll intercept whoever we feel like! ...as long as it isn't a challenge view.
@@ -495,8 +555,6 @@
         }
         mVelocityTracker.addMovement(ev);
 
-        //Log.v(TAG, "onIntercept: " + ev);
-
         final int action = ev.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_DOWN:
@@ -518,13 +576,15 @@
 
                     if (!mIsBouncing &&
                             (isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
-                            (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING)) &&
+                            (isInChallengeView(x, y) &&
+                                (mScrollState == SCROLL_STATE_SETTLING || !mChallengeShowing))) &&
                             mActivePointerId == INVALID_POINTER) {
                         mActivePointerId = ev.getPointerId(i);
                         mGestureStartX = x;
                         mGestureStartY = y;
                         mGestureStartChallengeBottom = getChallengeBottom();
                         mDragging = true;
+                        mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
                     } else if (isInChallengeView(x, y)) {
                         mBlockDrag = true;
                     }
@@ -601,6 +661,7 @@
                             mActivePointerId = ev.getPointerId(i);
                             mGestureStartChallengeBottom = getChallengeBottom();
                             mDragging = true;
+                            mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
                             break;
                         }
                     }
@@ -631,6 +692,52 @@
     }
 
     /**
+     * The lifecycle of touch events is subtle and it's very easy to do something
+     * that will cause bugs that will be nasty to track when overriding this method.
+     * Normally one should always override onInterceptTouchEvent instead.
+     *
+     * To put it another way, don't try this at home.
+     */
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        boolean handled = false;
+        if (action == MotionEvent.ACTION_DOWN) {
+            // Defensive programming: if we didn't get the UP or CANCEL, reset anyway.
+            mEdgeCaptured = false;
+        }
+        if (mWidgetsView != null && !mIsBouncing && (mEdgeCaptured || isEdgeSwipeBeginEvent(ev))) {
+            // Normally we would need to do a lot of extra stuff here.
+            // We can only get away with this because we haven't padded in
+            // the widget pager or otherwise transformed it during layout.
+            // We also don't support things like splitting MotionEvents.
+
+            // We set handled to captured even if dispatch is returning false here so that
+            // we don't send a different view a busted or incomplete event stream.
+            handled = mEdgeCaptured |= mWidgetsView.dispatchTouchEvent(ev);
+        }
+
+        if (!handled && !mEdgeCaptured) {
+            handled = super.dispatchTouchEvent(ev);
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mEdgeCaptured = false;
+        }
+
+        return handled;
+    }
+
+    private boolean isEdgeSwipeBeginEvent(MotionEvent ev) {
+        if (ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
+            return false;
+        }
+
+        final float x = ev.getX();
+        return x < mDragHandleEdgeSlop || x >= getWidth() - mDragHandleEdgeSlop;
+    }
+
+    /**
      * We only want to add additional vertical space to the drag handle when the panel is fully
      * closed.
      */
@@ -699,14 +806,24 @@
                 }
                 // We're going to play silly games with the frame's background drawable later.
                 mFrameDrawable = mChallengeView.getBackground();
+
+                if (!mHasLayout) {
+                    // Set up the margin correctly based on our content for the first run.
+                    mHasGlowpad = child.findViewById(R.id.keyguard_selector_view) != null;
+                    lp.leftMargin = lp.rightMargin = getChallengeMargin(true);
+                }
             } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
                 setScrimView(child);
+            } else if (lp.childType == LayoutParams.CHILD_TYPE_WIDGETS) {
+                mWidgetsView = child;
             }
+
             if (child.getVisibility() == GONE) continue;
         }
 
-        // We want to measure the challenge view first, for various reasons that I'd rather
-        // not get into here.
+        // We want to measure the challenge view first, since the KeyguardWidgetPager
+        // needs to do things its measure pass that are dependent on the challenge view
+        // having been measured.
         if (mChallengeView != null) {
             measureChildWithMargins(mChallengeView, widthSpec, 0, heightSpec, 0);
         }
@@ -750,7 +867,7 @@
                 // we never want less than the handle size showing at the bottom.
                 final int bottom = layoutBottom + (int) ((childHeight - mChallengeBottomBound)
                         * (1 - mChallengeOffset));
-                child.setAlpha(mChallengeOffset / 2 + 0.5f);
+                child.setAlpha(getChallengeAlpha());
                 child.layout(left, bottom - childHeight, left + childWidth, bottom);
             } else {
                 // Non-challenge views lay out from the upper left, layered.
@@ -828,7 +945,7 @@
             }
 
             if (mDragIconDrawable != null) {
-                final int closedTop = getLayoutBottom() - mChallengeBottomBound;
+                final int closedTop = getLayoutBottom() - mDragHandleClosedBelow;
                 final int iconWidth = mDragIconDrawable.getIntrinsicWidth();
                 final int iconHeight = mDragIconDrawable.getIntrinsicHeight();
                 final int iconLeft = (challengeLeft + challengeRight - iconWidth) / 2;
@@ -886,7 +1003,7 @@
         mChallengeView.layout(mChallengeView.getLeft(),
                 bottom - mChallengeView.getHeight(), mChallengeView.getRight(), bottom);
 
-        mChallengeView.setAlpha(offset / 2 + 0.5f);
+        mChallengeView.setAlpha(getChallengeAlpha());
         if (mScrollListener != null) {
             mScrollListener.onScrollPositionChanged(offset, mChallengeView.getTop());
         }
@@ -978,6 +1095,7 @@
         public static final int CHILD_TYPE_NONE = 0;
         public static final int CHILD_TYPE_CHALLENGE = 2;
         public static final int CHILD_TYPE_SCRIM = 4;
+        public static final int CHILD_TYPE_WIDGETS = 5;
 
         public LayoutParams() {
             this(MATCH_PARENT, WRAP_CONTENT);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 4a54efe..0e171cd 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -889,7 +889,7 @@
         final boolean isSystemNotification = ("android".equals(pkg));
 
         userId = ActivityManager.handleIncomingUser(callingPid,
-                callingUid, userId, true, true, "enqueueNotification", pkg);
+                callingUid, userId, true, false, "enqueueNotification", pkg);
         final UserHandle user = new UserHandle(userId);
 
         // Limit the number of notifications that any given package except the android
@@ -1287,7 +1287,7 @@
     public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
         checkCallerIsSystemOrSameApp(pkg);
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, true, "cancelNotificationWithTag", pkg);
+                Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
         // Don't allow client applications to cancel foreground service notis.
         cancelNotification(pkg, tag, id, 0,
                 Binder.getCallingUid() == Process.SYSTEM_UID
@@ -1298,7 +1298,7 @@
         checkCallerIsSystemOrSameApp(pkg);
 
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, true, "cancelAllNotifications", pkg);
+                Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
 
         // Calling from user space, don't allow the canceling of actively
         // running foreground services.
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index a02fc8d..82dbf54 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -466,10 +466,13 @@
                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
                     onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                             UserHandle.USER_NULL));
-                } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
-                    onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL));
                 }
+                // TODO: Race condition causing problems when cleaning up on stopping a user.
+                // Comment this out for now.
+                // else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+                //     onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                //             UserHandle.USER_NULL));
+                // }
             }
         }, userFilter);
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5722326..d2cd646 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4575,7 +4575,7 @@
             int callingUid = Binder.getCallingUid();
             int origUserId = userId;
             userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
-                    type == ActivityManager.INTENT_SENDER_BROADCAST, true,
+                    type == ActivityManager.INTENT_SENDER_BROADCAST, false,
                     "getIntentSender", null);
             if (origUserId == UserHandle.USER_CURRENT) {
                 // We don't want to evaluate this until the pending intent is
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 637f2de..7958f9a 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2773,7 +2773,7 @@
                     // TODO: Remove once b/7094175 is fixed
                     || ((String)win.mAttrs.getTitle()).contains("Keyguard")
                 ) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
-                    + " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
+                    + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
 
             win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
 
@@ -3003,6 +3003,10 @@
             }
 
             mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+            if (DEBUG_LAYOUT) {
+                Slog.v(TAG, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
+            }
         }
 
         if (configChanged) {
@@ -8379,7 +8383,8 @@
             // windows, since that means "perform layout as normal,
             // just don't display").
             if (!gone || !win.mHaveFrame || win.mLayoutNeeded
-                    || win.isConfigChanged()
+                    || ((win.mAttrs.type == TYPE_KEYGUARD || win.mAttrs.type == TYPE_WALLPAPER) &&
+                        win.isConfigChanged())
                     || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
                 if (!win.mLayoutAttached) {
                     if (initial) {
@@ -9301,6 +9306,8 @@
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
             Surface.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
         }
 
         final WindowList defaultWindows = defaultDisplay.getWindowList();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index c195f45..0a9c3e5 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -282,7 +282,7 @@
         mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
         if (WindowManagerService.localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
-            + " token=" + token + " (" + mAttrs.token + ")");
+            + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
         try {
             c.asBinder().linkToDeath(deathRecipient, 0);
         } catch (RemoteException e) {