am 28e8f76c: Merge "Cannot click on partially visible views in touch exploration." into jb-mr1-dev

* commit '28e8f76c50b26efd657bc0740fee25ac18520f9e':
  Cannot click on partially visible views in touch exploration.
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index d56556f..be6a770 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -244,14 +244,22 @@
      *
      * @param newOptions The bundle of options, in addition to the size information,
      *          can be null.
-     * @param minWidth The minimum width that the widget will be displayed at.
-     * @param minHeight The maximum height that the widget will be displayed at.
-     * @param maxWidth The maximum width that the widget will be displayed at.
-     * @param maxHeight The maximum height that the widget will be displayed at.
+     * @param minWidth The minimum width in dips that the widget will be displayed at.
+     * @param minHeight The maximum height in dips that the widget will be displayed at.
+     * @param maxWidth The maximum width in dips that the widget will be displayed at.
+     * @param maxHeight The maximum height in dips that the widget will be displayed at.
      *
      */
     public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
             int maxHeight) {
+        updateAppWidgetSize(newOptions, minWidth, minHeight, maxWidth, maxHeight, false);
+    }
+
+    /**
+     * @hide
+     */
+    public void updateAppWidgetSize(Bundle newOptions, int minWidth, int minHeight, int maxWidth,
+            int maxHeight, boolean ignorePadding) {
         if (newOptions == null) {
             newOptions = new Bundle();
         }
@@ -265,10 +273,10 @@
         int xPaddingDips = (int) ((padding.left + padding.right) / density);
         int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
 
-        int newMinWidth = minWidth - xPaddingDips;
-        int newMinHeight = minHeight - yPaddingDips; 
-        int newMaxWidth = maxWidth - xPaddingDips;
-        int newMaxHeight = maxHeight - yPaddingDips;
+        int newMinWidth = minWidth - (ignorePadding ? 0 : xPaddingDips);
+        int newMinHeight = minHeight - (ignorePadding ? 0 : yPaddingDips);
+        int newMaxWidth = maxWidth - (ignorePadding ? 0 : xPaddingDips);
+        int newMaxHeight = maxHeight - (ignorePadding ? 0 : yPaddingDips);
 
         AppWidgetManager widgetManager = AppWidgetManager.getInstance(mContext);
 
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3ee3c8c..e5e1a2b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1073,11 +1073,7 @@
             }
             return appWidgetIds;
         }
-        if (appWidgetIdString == null) {
-            return new int[] { LockPatternUtils.ID_DEFAULT_STATUS_WIDGET };
-        } else {
-            return new int[0];
-        }
+        return new int[0];
     }
 
     private static String combineStrings(int[] list, String separator) {
diff --git a/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..84549ff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..219f3e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png
new file mode 100644
index 0000000..d4965d9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/kg_widget_delete_drop_target.png
Binary files differ
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index 67ac1d5..be1d5b6 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -33,6 +33,12 @@
         android:layout_height="match_parent"
         android:clipChildren="false">
 
+        <include layout="@layout/keyguard_widget_remove_drop_target"
+            android:id="@+id/keyguard_widget_pager_delete_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal" />
+
         <include layout="@layout/keyguard_widget_pager"
             android:id="@+id/app_widget_container"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout-land/keyguard_widget_pager.xml b/core/res/res/layout-land/keyguard_widget_pager.xml
index 975288f..02c6d0e 100644
--- a/core/res/res/layout-land/keyguard_widget_pager.xml
+++ b/core/res/res/layout-land/keyguard_widget_pager.xml
@@ -25,7 +25,6 @@
     android:paddingRight="25dp"
     android:paddingTop="25dp"
     android:paddingBottom="25dp"
-    android:clipChildren="false"
     android:clipToPadding="false"
     androidprv:pageSpacing="10dp">
 </com.android.internal.policy.impl.keyguard.KeyguardWidgetCarousel>
\ No newline at end of file
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index b3270e0..9921313 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -35,6 +35,16 @@
 
         <FrameLayout
             android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <include layout="@layout/keyguard_widget_remove_drop_target"
+                android:id="@+id/keyguard_widget_pager_delete_target"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top|center_horizontal" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
             androidprv:layout_childType="widgets">
             <include layout="@layout/keyguard_widget_pager"
diff --git a/core/res/res/layout-port/keyguard_widget_pager.xml b/core/res/res/layout-port/keyguard_widget_pager.xml
index 7fd370b..7f22709 100644
--- a/core/res/res/layout-port/keyguard_widget_pager.xml
+++ b/core/res/res/layout-port/keyguard_widget_pager.xml
@@ -26,7 +26,6 @@
     android:paddingRight="25dp"
     android:paddingTop="25dp"
     android:paddingBottom="@dimen/kg_widget_pager_bottom_padding"
-    android:clipChildren="false"
     android:clipToPadding="false"
     androidprv:pageSpacing="10dp">
 </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
index 5d858ae..809104d 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -34,6 +34,12 @@
         android:clipChildren="false"
         android:orientation="vertical">
 
+        <include layout="@layout/keyguard_widget_remove_drop_target"
+            android:id="@+id/keyguard_widget_pager_delete_target"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal" />
+
         <include layout="@layout/keyguard_widget_pager"
             android:id="@+id/app_widget_container"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
index ad61709..aed73e5 100644
--- a/core/res/res/layout/keyguard_sim_pin_view.xml
+++ b/core/res/res/layout/keyguard_sim_pin_view.xml
@@ -19,98 +19,198 @@
 <!-- This is the SIM PIN view that allows the user to enter a SIM PIN to unlock the device. -->
 <com.android.internal.policy.impl.keyguard.KeyguardSimPinView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_sim_pin_view"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal">
 
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_lockscreen_sim"/>
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        >
+        <TextView android:id="@+id/pinEntry"
+            android:editable="true"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+            android:singleLine="true"
+            android:cursorVisible="false"
+            android:background="@null"
+            android:textAppearance="@style/TextAppearance.NumPadKey"
+            android:imeOptions="flagForceAscii|actionDone"
+            />
+        <ImageButton android:id="@+id/delete_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:src="@*android:drawable/ic_input_delete"
+            android:clickable="true"
+            android:paddingTop="8dip"
+            android:paddingBottom="8dip"
+            android:paddingLeft="24dp"
+            android:paddingRight="24dp"
+            android:background="?android:attr/selectableItemBackground"
+            />
+    </LinearLayout>
+    <View
+        android:layout_width="wrap_content"
+        android:layout_height="1dp"
+        android:background="#55FFFFFF"
+        />
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
-        android:orientation="vertical">
-
-        <LinearLayout
-            android:layout_height="0dip"
-            android:layout_width="match_parent"
+        android:orientation="horizontal"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key1"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="vertical"
-            android:gravity="center">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:src="@drawable/ic_lockscreen_sim"/>
-
-            <include layout="@layout/keyguard_message_area_large"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-         </LinearLayout>
-
-        <!-- 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_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_marginEnd="4dip"
-            android:layout_marginStart="4dip"
-            android:gravity="center_vertical"
-            android:background="#70000000">
-
-            <!-- displays dots as user enters pin -->
-            <EditText android:id="@+id/sim_pin_entry"
-                android:layout_width="0dip"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:maxLines="1"
-                android:singleLine="true"
-                android:gravity="center_horizontal"
-                android:layout_gravity="center_vertical"
-                android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-                android:textStyle="normal"
-                android:inputType="textPassword"
-                android:textSize="36sp"
-                android:background="@null"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="#ffffffff"
-                android:imeOptions="flagForceAscii|actionDone"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="1"
             />
-
-            <ImageButton android:id="@+id/delete_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:src="@android:drawable/ic_input_delete"
-                android:clickable="true"
-                android:padding="8dip"
-                android:background="?android:attr/selectableItemBackground"
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key2"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="2"
             />
-        </LinearLayout>
-
-        <!-- Numeric keyboard -->
-        <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="4dip"
-            android:layout_marginEnd="4dip"
-            android:paddingTop="4dip"
-            android:paddingBottom="4dip"
-            android:background="#40000000"
-            android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
-            android:clickable="true"
-        />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key3"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="3"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key4"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="4"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key5"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="5"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key6"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="6"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key7"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="7"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key8"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="8"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key9"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="9"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        >
+        <Space
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key0"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="0"
+            />
+        <ImageButton
+            android:id="@+id/key_enter"
+            style="@style/Widget.Button.NumPadKey"
+            android:gravity="center"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:src="@drawable/sym_keyboard_return_holo"
+            />
     </LinearLayout>
 
     <include layout="@layout/keyguard_emergency_carrier_area"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
+                   android:id="@+id/keyguard_selector_fade_container"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:orientation="vertical"
+                   android:layout_gravity="bottom|center_horizontal"
+                   android:gravity="center_horizontal" />
 
 </com.android.internal.policy.impl.keyguard.KeyguardSimPinView>
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
index cc97005..7eec2ca 100644
--- a/core/res/res/layout/keyguard_sim_puk_view.xml
+++ b/core/res/res/layout/keyguard_sim_puk_view.xml
@@ -20,97 +20,197 @@
     carrier-provided PUK code and entering a new SIM PIN for it. -->
 <com.android.internal.policy.impl.keyguard.KeyguardSimPukView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_sim_puk_view"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
     android:gravity="center_horizontal">
 
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/ic_lockscreen_sim"/>
+
+    <include layout="@layout/keyguard_message_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        >
+        <TextView android:id="@+id/pinEntry"
+            android:editable="true"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
+            android:singleLine="true"
+            android:cursorVisible="false"
+            android:background="@null"
+            android:textAppearance="@style/TextAppearance.NumPadKey"
+            android:imeOptions="flagForceAscii|actionDone"
+            />
+        <ImageButton android:id="@+id/delete_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:src="@*android:drawable/ic_input_delete"
+            android:clickable="true"
+            android:paddingTop="8dip"
+            android:paddingBottom="8dip"
+            android:paddingLeft="24dp"
+            android:paddingRight="24dp"
+            android:background="?android:attr/selectableItemBackground"
+            />
+    </LinearLayout>
+    <View
+        android:layout_width="wrap_content"
+        android:layout_height="1dp"
+        android:background="#55FFFFFF"
+        />
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
-        android:orientation="vertical">
-
-        <LinearLayout
-            android:layout_height="0dip"
-            android:layout_width="match_parent"
+        android:orientation="horizontal"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key1"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="vertical"
-            android:gravity="center">
-
-            <ImageView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:src="@drawable/ic_lockscreen_sim"/>
-
-            <include layout="@layout/keyguard_message_area_large"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-         </LinearLayout>
-
-        <!-- 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_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layout_marginEnd="4dip"
-            android:layout_marginStart="4dip"
-            android:gravity="center_vertical"
-            android:background="#70000000">
-
-            <!-- displays dots as user enters pin -->
-            <EditText android:id="@+id/sim_pin_entry"
-                android:layout_width="0dip"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:maxLines="1"
-                android:singleLine="true"
-                android:gravity="center_horizontal"
-                android:layout_gravity="center_vertical"
-                android:layout_marginStart="@*android:dimen/keyguard_lockscreen_pin_margin_left"
-                android:textStyle="normal"
-                android:inputType="textPassword"
-                android:textSize="36sp"
-                android:background="@null"
-                android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="#ffffffff"
-                android:imeOptions="flagForceAscii|actionDone"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="1"
             />
-
-            <ImageButton android:id="@+id/delete_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:src="@android:drawable/ic_input_delete"
-                android:clickable="true"
-                android:padding="8dip"
-                android:background="?android:attr/selectableItemBackground"
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key2"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="2"
             />
-        </LinearLayout>
-
-        <!-- Numeric keyboard -->
-        <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="4dip"
-            android:layout_marginEnd="4dip"
-            android:paddingTop="4dip"
-            android:paddingBottom="4dip"
-            android:background="#40000000"
-            android:keyBackground="@*android:drawable/btn_keyboard_key_ics"
-            android:clickable="true"
-        />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key3"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="3"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key4"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="4"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key5"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="5"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key6"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="6"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:orientation="horizontal"
+        android:layout_weight="1"
+        >
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key7"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="7"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key8"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="8"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key9"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="9"
+            />
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="horizontal"
+        >
+        <Space
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            />
+        <view class="com.android.internal.policy.impl.keyguard.NumPadKey"
+            android:id="@+id/key0"
+            style="@style/Widget.Button.NumPadKey"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            androidprv:textView="@+id/pinEntry"
+            androidprv:digit="0"
+            />
+        <ImageButton
+            android:id="@+id/key_enter"
+            style="@style/Widget.Button.NumPadKey"
+            android:gravity="center"
+            android:layout_width="0px"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:src="@drawable/sym_keyboard_return_holo"
+            />
     </LinearLayout>
 
     <include layout="@layout/keyguard_emergency_carrier_area"
-        android:id="@+id/keyguard_selector_fade_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_gravity="bottom|center_horizontal"
-        android:gravity="center_horizontal" />
+                   android:id="@+id/keyguard_selector_fade_container"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content"
+                   android:orientation="vertical"
+                   android:layout_gravity="bottom|center_horizontal"
+                   android:gravity="center_horizontal" />
 </com.android.internal.policy.impl.keyguard.KeyguardSimPukView>
diff --git a/core/res/res/layout/keyguard_widget_remove_drop_target.xml b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
new file mode 100644
index 0000000..c4fe9e0
--- /dev/null
+++ b/core/res/res/layout/keyguard_widget_remove_drop_target.xml
@@ -0,0 +1,32 @@
+<?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.
+*/
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:gravity="center"
+    android:padding="20dp"
+    android:paddingLeft="40dp"
+    android:paddingRight="40dp"
+    android:drawableLeft="@drawable/kg_widget_delete_drop_target"
+    android:drawablePadding="4dp"
+    android:textColor="#FFF"
+    android:textSize="13sp"
+    android:shadowColor="#000"
+    android:shadowDy="1.0"
+    android:shadowRadius="1.0"
+    android:visibility="gone" />
\ No newline at end of file
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 36f2628..8f1bd9a 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -56,4 +56,9 @@
     <!-- Bottom padding for the widget pager -->
     <dimen name="kg_widget_pager_bottom_padding">0dp</dimen>
 
+    <!-- If the height if keyguard drops below this threshold (most likely
+    due to the appearance of the IME), then drop the multiuser selector.
+    Landscape's layout allows this to be smaller than for portrait. -->
+    <dimen name="kg_squashed_layout_threshold">400dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 148560a..3b7d73a 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -404,6 +404,12 @@
     -->
     <integer name="config_longPressOnPowerBehavior">1</integer>
 
+    <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_package_name"></string>
+
+    <!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
+    <string name="widget_default_class_name"></string>
+
     <!-- Indicate whether the SD card is accessible without removing the battery. -->
     <bool name="config_batterySdCardAccessibility">false</bool>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4966b97..3a24cc1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -330,4 +330,9 @@
     <!-- Size of the region along the edge of the screen that will accept
          swipes to scroll the widget area. -->
     <dimen name="kg_edge_swipe_region_size">24dp</dimen>
+
+    <!-- If the height if keyguard drops below this threshold (most likely
+    due to the appearance of the IME), then drop the multiuser selector. -->
+    <dimen name="kg_squashed_layout_threshold">600dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 51d6429..06e927b 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2065,15 +2065,6 @@
     <!-- 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 />
@@ -3976,6 +3967,9 @@
        you will be asked to unlock your phone using an email account.\n\n
        Try again in <xliff:g id="number">%d</xliff:g> seconds.
     </string>
+    <!-- Sequence of characters used to separate message strings in keyguard. Typically just em-dash
+         with spaces on either side. [CHAR LIMIT=3] -->
+    <string name="kg_text_message_separator" product="default"> \u2014 </string>
 
     <!-- Message shown in dialog when user is attempting to set the music volume above the
     recommended maximum level for headphones -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 05edbcc..a12c14c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -479,7 +479,6 @@
   <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" />
@@ -1235,6 +1234,7 @@
   <java-symbol type="dimen" name="keyguard_avatar_frame_stroke_width" />
   <java-symbol type="dimen" name="keyguard_avatar_frame_shadow_radius" />
   <java-symbol type="dimen" name="kg_edge_swipe_region_size" />
+  <java-symbol type="dimen" name="kg_squashed_layout_threshold" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
   <java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -1319,6 +1319,7 @@
   <java-symbol type="id" name="keyguard_sim_puk_view" />
   <java-symbol type="id" name="keyguard_account_view" />
   <java-symbol type="id" name="keyguard_selector_fade_container" />
+  <java-symbol type="id" name="keyguard_widget_pager_delete_target" />
   <java-symbol type="id" name="app_widget_container" />
   <java-symbol type="id" name="view_flipper" />
   <java-symbol type="id" name="emergency_call_button" />
@@ -1327,9 +1328,7 @@
   <java-symbol type="id" name="lockPatternView" />
   <java-symbol type="id" name="forgot_password_button" />
   <java-symbol type="id" name="glow_pad_view" />
-  <java-symbol type="id" name="sim_pin_entry" />
   <java-symbol type="id" name="delete_button" />
-  <java-symbol type="id" name="sim_pin_entry" />
   <java-symbol type="id" name="keyguard_user_avatar" />
   <java-symbol type="id" name="keyguard_user_name" />
   <java-symbol type="id" name="keyguard_transport_control" />
@@ -1478,6 +1477,7 @@
   <java-symbol type="string" name="kg_failed_attempts_almost_at_login" />
   <java-symbol type="string" name="kg_enter_confirm_pin_hint" />
   <java-symbol type="string" name="kg_invalid_confirm_pin_hint" />
+  <java-symbol type="string" name="kg_text_message_separator" />
 
   <!-- From services -->
   <java-symbol type="anim" name="screen_rotate_0_enter" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 983328d..5eeef93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -224,6 +224,8 @@
             (0 != (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT))
                 ? (mVertical ? mBackAltLandIcon : mBackAltIcon)
                 : (mVertical ? mBackLandIcon : mBackIcon));
+
+        setDisabledFlags(mDisabledFlags, true);
     }
 
     public void setDisabledFlags(int disabledFlags) {
@@ -237,7 +239,8 @@
 
         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
         final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
-        final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0);
+        final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
+                && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
 
         if (SLIPPERY_WHEN_DISABLED) {
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 2728bfc..893df26 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CameraWidgetFrame.java
@@ -53,13 +53,14 @@
     private final Callbacks mCallbacks;
     private final WindowManager mWindowManager;
     private final Point mRenderedSize = new Point();
+    private final int[] mScreenLocation = new int[2];
 
     private View mWidgetView;
     private long mLaunchCameraStart;
     private boolean mActive;
-    private boolean mChallengeActive;
     private boolean mTransitioning;
     private boolean mDown;
+    private boolean mWindowFocused;
 
     private final Runnable mLaunchCameraRunnable = new Runnable() {
         @Override
@@ -186,7 +187,7 @@
     }
 
     private void transitionToCamera() {
-        if (mTransitioning || mChallengeActive || mDown) return;
+        if (mTransitioning || mDown) return;
 
         mTransitioning = true;
 
@@ -233,7 +234,7 @@
     public void onClick(View v) {
         if (DEBUG) Log.d(TAG, "clicked");
         if (mTransitioning) return;
-        if (mActive && !mChallengeActive) {
+        if (mActive) {
             cancelTransitionToCamera();
             transitionToCamera();
         }
@@ -242,6 +243,7 @@
     @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
+        mWindowFocused = hasWindowFocus;
         if (DEBUG) Log.d(TAG, "onWindowFocusChanged: " + hasWindowFocus);
         if (!hasWindowFocus) {
             mTransitioning = false;
@@ -265,13 +267,29 @@
     }
 
     @Override
-    public boolean onUserInteraction(int action) {
-        if (mTransitioning) return true;
-        if (DEBUG) Log.d(TAG, "onUserInteraction " + action);
+    public boolean onUserInteraction(MotionEvent event) {
+        if (!mWindowFocused) {
+            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: !mWindowFocused");
+            return true;
+        }
+        if (mTransitioning) {
+            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: mTransitioning");
+            return true;
+        }
+
+        getLocationOnScreen(mScreenLocation);
+        int rawBottom = mScreenLocation[1] + getHeight();
+        if (event.getRawY() > rawBottom) {
+            if (DEBUG) Log.d(TAG, "onUserInteraction eaten: below widget");
+            return true;
+        }
+
+        int action = event.getAction();
         mDown = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE;
-        if (mActive && !mChallengeActive) {
+        if (mActive) {
             rescheduleTransitionToCamera();
         }
+        if (DEBUG) Log.d(TAG, "onUserInteraction observed, not eaten");
         return false;
     }
 
@@ -282,20 +300,6 @@
         super.onFocusLost();
     }
 
-    @Override
-    public void onChallengeActive(boolean challengeActive) {
-        if (DEBUG) Log.d(TAG, "onChallengeActive: " + challengeActive);
-        mChallengeActive = challengeActive;
-        if (mTransitioning) return;
-        if (mActive) {
-            if (mChallengeActive) {
-                cancelTransitionToCamera();
-            } else {
-                rescheduleTransitionToCamera();
-            }
-        }
-    }
-
     public void onScreenTurnedOff() {
         if (DEBUG) Log.d(TAG, "onScreenTurnedOff");
         reset();
@@ -321,7 +325,6 @@
         if (DEBUG) Log.d(TAG, "reset");
         mLaunchCameraStart = 0;
         mTransitioning = false;
-        mChallengeActive = false;
         mDown = false;
         cancelTransitionToCamera();
         animate().cancel();
@@ -347,6 +350,7 @@
         WindowManager.LayoutParams wlp = (WindowManager.LayoutParams) lp;
         int newWindowAnimations = isEnabled ? com.android.internal.R.style.Animation_LockScreen : 0;
         if (newWindowAnimations != wlp.windowAnimations) {
+            if (DEBUG) Log.d(TAG, "setting windowAnimations to: " + newWindowAnimations);
             wlp.windowAnimations = newWindowAnimations;
             mWindowManager.updateViewLayout(root, wlp);
         }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
index b031baf..f3ea992 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/CarrierText.java
@@ -27,6 +27,8 @@
 import com.android.internal.widget.LockPatternUtils;
 
 public class CarrierText extends TextView {
+    private static CharSequence mSeparator;
+
     private LockPatternUtils mLockPatternUtils;
 
     private KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {
@@ -82,6 +84,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mSeparator = getResources().getString(R.string.kg_text_message_separator);
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mCallback);
         setSelected(true); // Allow marquee to work.
     }
@@ -202,7 +205,7 @@
         final boolean plmnValid = !TextUtils.isEmpty(plmn);
         final boolean spnValid = !TextUtils.isEmpty(spn);
         if (plmnValid && spnValid) {
-            return plmn + "|" + spn;
+            return new StringBuilder().append(plmn).append(mSeparator).append(spn).toString();
         } else if (plmnValid) {
             return plmn;
         } else if (spnValid) {
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 db36bcc..71526d2 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardAbsKeyInputView.java
@@ -130,6 +130,15 @@
         return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
     }
 
+    /*
+     * Override this if you have a different string for "wrong password"
+     *
+     * Note that PIN/PUK have their own implementation of verifyPasswordAndUnlock and so don't need this
+     */
+    protected int getWrongPasswordStringId() {
+        return R.string.kg_wrong_password;
+    }
+
     protected void verifyPasswordAndUnlock() {
         String entry = mPasswordEntry.getText().toString();
         if (mLockPatternUtils.checkPassword(entry)) {
@@ -144,7 +153,7 @@
                 long deadline = mLockPatternUtils.setLockoutAttemptDeadline();
                 handleAttemptLockout(deadline);
             }
-            mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pin, true);
+            mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
         }
         mPasswordEntry.setText("");
     }
@@ -164,6 +173,7 @@
 
             @Override
             public void onFinish() {
+                mSecurityMessageDisplay.setMessage("", false);
                 resetState();
             }
         }.start();
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 ca3d0a2..d286564 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -29,8 +29,6 @@
 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;
@@ -50,7 +48,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AnimationUtils;
 import android.widget.RemoteViews.OnClickHandler;
 
@@ -59,7 +56,6 @@
 import com.android.internal.widget.LockPatternUtils;
 
 import java.io.File;
-import java.util.ArrayList;
 import java.util.List;
 
 public class KeyguardHostView extends KeyguardViewBase {
@@ -68,10 +64,10 @@
     // Use this to debug all of keyguard
     public static boolean DEBUG = KeyguardViewMediator.DEBUG;
 
-    // also referenced in SecuritySettings.java
     static final int APPWIDGET_HOST_ID = 0x4B455947;
 
     private AppWidgetHost mAppWidgetHost;
+    private AppWidgetManager mAppWidgetManager;
     private KeyguardWidgetPager mAppWidgetContainer;
     private KeyguardSecurityViewFlipper mSecurityViewContainer;
     private KeyguardSelectorView mKeyguardSelectorView;
@@ -113,6 +109,7 @@
         mLockPatternUtils = new LockPatternUtils(context);
         mAppWidgetHost = new AppWidgetHost(
                 context, APPWIDGET_HOST_ID, mOnClickHandler, Looper.myLooper());
+        mAppWidgetManager = AppWidgetManager.getInstance(mContext);
         mSecurityModel = new KeyguardSecurityModel(context);
 
         // The following enables the MENU key to work for testing automation
@@ -153,15 +150,13 @@
     protected void onFinishInflate() {
         // Grab instances of and make any necessary changes to the main layouts. Create
         // view state manager and wire up necessary listeners / callbacks.
+        View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
         mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
         mAppWidgetContainer.setVisibility(VISIBLE);
         mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
+        mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
         mAppWidgetContainer.setMinScale(0.5f);
 
-        addDefaultWidgets();
-        addWidgetsFromSettings();
-        mSwitchPageRunnable.run();
-
         SlidingChallengeLayout slider =
                 (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
         if (slider != null) {
@@ -183,8 +178,11 @@
             setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
         }
 
-        showPrimarySecurityScreen(false);
+        addDefaultWidgets();
+        addWidgetsFromSettings();
+        mSwitchPageRunnable.run();
 
+        showPrimarySecurityScreen(false);
         updateSecurityViews();
     }
 
@@ -549,8 +547,6 @@
         };
     };
 
-    private KeyguardStatusViewManager mKeyguardStatusViewManager;
-
     // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
     // This avoids unwanted asynchronous events from messing with the state.
     private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
@@ -590,6 +586,8 @@
         }
     };
 
+    protected boolean mShowSecurityWhenReturn;
+
     @Override
     public void reset() {
         mIsVerifyUnlockOnly = false;
@@ -715,6 +713,7 @@
         // biometric unlock to start next time keyguard is shown.
         KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
         saveStickyWidgetIndex();
+        checkAppWidgetConsistency();
         showPrimarySecurityScreen(true);
         getSecurityView(mCurrentSecuritySelection).onPause();
         CameraWidgetFrame cameraPage = findCameraPage();
@@ -812,15 +811,16 @@
         }
     }
 
-    private void addWidget(int appId, int pageIndex) {
-        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-        AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
+    private boolean addWidget(int appId, int pageIndex) {
+        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
         if (appWidgetInfo != null) {
             AppWidgetHostView view = getAppWidgetHost().createView(mContext, appId, appWidgetInfo);
             addWidget(view, pageIndex);
+            return true;
         } else {
             Log.w(TAG, "AppWidgetInfo for app widget id " + appId + " was null, deleting");
             mLockPatternUtils.removeAppWidget(appId);
+            return false;
         }
     }
 
@@ -842,11 +842,11 @@
                 SlidingChallengeLayout slider = locateSlider();
                 if (slider != null) {
                     slider.setHandleAlpha(1);
-                    slider.showChallenge(true);
                 }
+                mShowSecurityWhenReturn = true;
             }
 
-            private SlidingChallengeLayout locateSlider() {
+            public SlidingChallengeLayout locateSlider() {
                 return (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
             }
         };
@@ -890,22 +890,7 @@
 
                     @Override
                     public void run() {
-                        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);
+                        launchPickActivityIntent();
                     }
                 });
                 mCallback.dismiss(false);
@@ -916,8 +901,7 @@
         initializeTransportControl();
     }
 
-    private void launchPickActivityIntent(int defaultLabelId, int defaultIconId,
-            ComponentName defaultComponentName, String defaultTag) {
+    private void launchPickActivityIntent() {
         // Create intent to pick widget
         Intent pickIntent = new Intent(AppWidgetManager.ACTION_KEYGUARD_APPWIDGET_PICK);
 
@@ -928,22 +912,6 @@
             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
@@ -1024,6 +992,22 @@
         }
     }
 
+    private int getAddPageIndex() {
+        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
+        int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
+        // This shouldn't happen, but just to be safe!
+        if (addPageIndex < 0) {
+            addPageIndex = 0;
+        }
+        return addPageIndex;
+    }
+
+    private void addDefaultStatusWidget(int index) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
+        mAppWidgetContainer.addWidget(statusWidget, index);
+    }
+
     private void addWidgetsFromSettings() {
         DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -1036,23 +1020,17 @@
             }
         }
 
-        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
-        int addPageIndex = mAppWidgetContainer.indexOfChild(addWidget);
-        // This shouldn't happen, but just to be safe!
-        if (addPageIndex < 0) {
-            addPageIndex = 0;
-        }
+        int addPageIndex = getAddPageIndex();
 
         // Add user-selected widget
         final int[] widgets = mLockPatternUtils.getAppWidgets();
+
         if (widgets == null) {
             Log.d(TAG, "Problem reading widgets");
         } else {
             for (int i = widgets.length -1; i >= 0; i--) {
                 if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
-                    LayoutInflater inflater = LayoutInflater.from(mContext);
-                    View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
-                    mAppWidgetContainer.addWidget(statusWidget, addPageIndex + 1);
+                    addDefaultStatusWidget(addPageIndex + 1);
                 } else {
                     // We add the widgets from left to right, starting after the first page after
                     // the add page. We count down, since the order will be persisted from right
@@ -1061,6 +1039,42 @@
                 }
             }
         }
+        checkAppWidgetConsistency();
+    }
+
+    public void checkAppWidgetConsistency() {
+        final int childCount = mAppWidgetContainer.getChildCount();
+        boolean widgetPageExists = false;
+        for (int i = 0; i < childCount; i++) {
+            if (isWidgetPage(i)) {
+                widgetPageExists = true;
+                break;
+            }
+        }
+        if (!widgetPageExists) {
+            final int addPageIndex = getAddPageIndex();
+
+            Resources res = getContext().getResources();
+            ComponentName defaultAppWidget = new ComponentName(
+                    res.getString(R.string.widget_default_package_name),
+                    res.getString(R.string.widget_default_class_name));
+
+            // Note: we don't support configuring the widget
+            int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
+            boolean bindSuccessful = false;
+            try {
+                mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
+                bindSuccessful = true;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
+            }
+            // Use the built-in status/clock view if we can't inflate the default widget
+            if (!(bindSuccessful && addWidget(appWidgetId, addPageIndex + 1))) {
+                addDefaultStatusWidget(addPageIndex + 1);
+            }
+            mAppWidgetContainer.onAddView(
+                    mAppWidgetContainer.getChildAt(addPageIndex + 1), addPageIndex + 1);
+        }
     }
 
     Runnable mSwitchPageRunnable = new Runnable() {
@@ -1129,6 +1143,14 @@
         if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
         if (!hasWindowFocus) {
             saveStickyWidgetIndex();
+        } else if (mShowSecurityWhenReturn) {
+            SlidingChallengeLayout slider =
+                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
+            if (slider != null) {
+                slider.setHandleAlpha(1);
+                slider.showChallenge(true);
+            }
+            mShowSecurityWhenReturn = false;
         }
     }
 
@@ -1155,6 +1177,15 @@
         return null;
     }
 
+    private boolean isWidgetPage(int pageIndex) {
+        View v = mAppWidgetContainer.getChildAt(pageIndex);
+        if (v != null && v instanceof KeyguardWidgetFrame) {
+            KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
+            return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
+        }
+        return false;
+    }
+
     private boolean isCameraPage(int pageIndex) {
         View v = mAppWidgetContainer.getChildAt(pageIndex);
         return v != null && v instanceof CameraWidgetFrame;
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 5e331e1..f6f3fab 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMessageArea.java
@@ -43,7 +43,6 @@
 
     static final int SECURITY_MESSAGE_DURATION = 5000;
     protected static final int FADE_DURATION = 750;
-    static final String SEPARATOR = "  ";
 
     // are we showing battery information?
     boolean mShowingBatteryInfo = false;
@@ -143,6 +142,8 @@
         }
     };
 
+    private CharSequence mSeparator;
+
     public KeyguardMessageArea(Context context) {
         this(context, null);
     }
@@ -158,6 +159,8 @@
         mUpdateMonitor.registerCallback(mInfoCallback);
         mHandler = new Handler(Looper.myLooper());
 
+        mSeparator = getResources().getString(R.string.kg_text_message_separator);
+
         update();
     }
 
@@ -186,23 +189,23 @@
         setText(status);
     }
 
-
-    private CharSequence concat(Object... args) {
+    private CharSequence concat(CharSequence... args) {
         StringBuilder b = new StringBuilder();
-        for (int i = 0; i < args.length; i++) {
-            final Object arg = args[i];
-            if (arg instanceof CharSequence) {
-                b.append((CharSequence)args[i]);
-                b.append(SEPARATOR);
-            } else if (arg instanceof String) {
-                b.append((String)args[i]);
-                b.append(SEPARATOR);
+        if (!TextUtils.isEmpty(args[0])) {
+            b.append(args[0]);
+        }
+        for (int i = 1; i < args.length; i++) {
+            CharSequence text = args[i];
+            if (!TextUtils.isEmpty(text)) {
+                if (b.length() > 0) {
+                    b.append(mSeparator);
+                }
+                b.append(text);
             }
         }
         return b.toString();
     }
 
-
     CharSequence getCurrentMessage() {
         return mShowingMessage ? mMessage : null;
     }
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 b7d9990..cea3fb0 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPINView.java
@@ -65,7 +65,9 @@
                 @Override
                 public void onClick(View v) {
                     doHapticKeyClick();
-                    verifyPasswordAndUnlock();
+                    if (mPasswordEntry.isEnabled()) {
+                        verifyPasswordAndUnlock();
+                    }
                 }
             });
             ok.setOnHoverListener(new NumPadKey.LiftToActivateListener(getContext()));
@@ -78,16 +80,22 @@
             pinDelete.setVisibility(View.VISIBLE);
             pinDelete.setOnClickListener(new OnClickListener() {
                 public void onClick(View v) {
-                    CharSequence str = mPasswordEntry.getText();
-                    if (str.length() > 0) {
-                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                    // check for time-based lockouts
+                    if (mPasswordEntry.isEnabled()) {
+                        CharSequence str = mPasswordEntry.getText();
+                        if (str.length() > 0) {
+                            mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                        }
                     }
                     doHapticKeyClick();
                 }
             });
             pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
                 public boolean onLongClick(View v) {
-                    mPasswordEntry.setText("");
+                    // check for time-based lockouts
+                    if (mPasswordEntry.isEnabled()) {
+                        mPasswordEntry.setText("");
+                    }
                     doHapticKeyClick();
                     return true;
                 }
@@ -104,4 +112,9 @@
     @Override
     public void showUsabilityHint() {
     }
+
+    @Override
+    public int getWrongPasswordStringId() {
+        return R.string.kg_wrong_pin;
+    }
 }
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 64bbdd3..23ea2e9 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -195,4 +195,9 @@
     @Override
     public void showUsabilityHint() {
     }
+
+    @Override
+    public int getWrongPasswordStringId() {
+        return R.string.kg_wrong_password;
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
index fcf45ff..ab364ee 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPinView.java
@@ -16,47 +16,32 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import com.android.internal.telephony.ITelephony;
+
+import android.content.Context;
 import android.app.Activity;
 import android.app.Dialog;
 import android.app.ProgressDialog;
-import android.content.Context;
-import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-
-import com.android.internal.telephony.ITelephony;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
-import com.android.internal.R;
-
 import android.text.Editable;
+import android.text.InputType;
 import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
 import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
+import com.android.internal.R;
+
 /**
- * Displays a dialer like interface to unlock the SIM PIN.
+ * Displays a PIN pad for unlocking.
  */
-public class KeyguardSimPinView extends LinearLayout
+public class KeyguardSimPinView extends KeyguardAbsKeyInputView
         implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
 
-    private EditText mPinEntry;
     private ProgressDialog mSimUnlockProgressDialog = null;
-    private KeyguardSecurityCallback mCallback;
-    private PasswordEntryKeyboardView mKeyboardView;
-    private PasswordEntryKeyboardHelper mKeyboardHelper;
-    private LockPatternUtils mLockPatternUtils;
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-
     private volatile boolean mSimCheckInProgress;
 
     public KeyguardSimPinView(Context context) {
@@ -65,68 +50,69 @@
 
     public KeyguardSimPinView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(getContext());
     }
 
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
+    public void resetState() {
+        mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mPinEntry = (EditText) findViewById(R.id.sim_pin_entry);
-        mPinEntry.setOnEditorActionListener(this);
-        mPinEntry.addTextChangedListener(this);
-
-        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
-        mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
-                new int[] {
-                R.xml.kg_password_kbd_numeric,
-                com.android.internal.R.xml.password_kbd_qwerty,
-                com.android.internal.R.xml.password_kbd_qwerty_shifted,
-                com.android.internal.R.xml.password_kbd_symbols,
-                com.android.internal.R.xml.password_kbd_symbols_shift
-                });
-        mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
-        mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
-
-        final View deleteButton = findViewById(R.id.delete_button);
-        if (deleteButton != null) {
-            deleteButton.setOnClickListener(new OnClickListener() {
+        final View ok = findViewById(R.id.key_enter);
+        if (ok != null) {
+            ok.setOnClickListener(new View.OnClickListener() {
+                @Override
                 public void onClick(View v) {
-                    mKeyboardHelper.handleBackspace();
+                    doHapticKeyClick();
+                    verifyPasswordAndUnlock();
                 }
             });
         }
 
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
-        mSecurityMessageDisplay.setTimeout(0);
-        reset();
-    }
+        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+        // not a separate view
+        View pinDelete = findViewById(R.id.delete_button);
+        if (pinDelete != null) {
+            pinDelete.setVisibility(View.VISIBLE);
+            pinDelete.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    CharSequence str = mPasswordEntry.getText();
+                    if (str.length() > 0) {
+                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                    }
+                    doHapticKeyClick();
+                }
+            });
+            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    mPasswordEntry.setText("");
+                    doHapticKeyClick();
+                    return true;
+                }
+            });
+        }
 
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        return mPinEntry.requestFocus(direction, previouslyFocusedRect);
-    }
+        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
 
-    public void reset() {
-        // start fresh
-        mSecurityMessageDisplay.setMessage(R.string.kg_sim_pin_instructions, true);
-
-        // make sure that the number of entered digits is consistent when we
-        // erase the SIM unlock code, including orientation changes.
-        mPinEntry.setText("");
-        mPinEntry.requestFocus();
+        mPasswordEntry.requestFocus();
     }
 
     @Override
     public void showUsabilityHint() {
     }
 
-    /** {@inheritDoc} */
-    public void cleanUp() {
+    @Override
+    public void onPause() {
         // dismiss the dialog.
         if (mSimUnlockProgressDialog != null) {
             mSimUnlockProgressDialog.dismiss();
@@ -167,19 +153,6 @@
         }
     }
 
-    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-        // Check if this was the result of hitting the enter key
-        mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-        if (event.getAction() == MotionEvent.ACTION_DOWN && (
-                actionId == EditorInfo.IME_NULL
-                || actionId == EditorInfo.IME_ACTION_DONE
-                || actionId == EditorInfo.IME_ACTION_NEXT)) {
-            checkPin();
-            return true;
-        }
-        return false;
-    }
-
     private Dialog getSimUnlockProgressDialog() {
         if (mSimUnlockProgressDialog == null) {
             mSimUnlockProgressDialog = new ProgressDialog(mContext);
@@ -195,11 +168,14 @@
         return mSimUnlockProgressDialog;
     }
 
-    private void checkPin() {
-        if (mPinEntry.getText().length() < 4) {
+    @Override
+    protected void verifyPasswordAndUnlock() {
+        String entry = mPasswordEntry.getText().toString();
+        
+        if (entry.length() < 4) {
             // otherwise, display a message to the user, and don't submit.
             mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint, true);
-            mPinEntry.setText("");
+            mPasswordEntry.setText("");
             mCallback.userActivity(0);
             return;
         }
@@ -208,7 +184,7 @@
 
         if (!mSimCheckInProgress) {
             mSimCheckInProgress = true; // there should be only one
-            new CheckSimPin(mPinEntry.getText().toString()) {
+            new CheckSimPin(mPasswordEntry.getText().toString()) {
                 void onSimCheckResponse(final boolean success) {
                     post(new Runnable() {
                         public void run() {
@@ -223,7 +199,7 @@
                             } else {
                                 mSecurityMessageDisplay.setMessage
                                     (R.string.kg_password_wrong_pin_code, true);
-                                mPinEntry.setText("");
+                                mPasswordEntry.setText("");
                             }
                             mCallback.userActivity(0);
                             mSimCheckInProgress = false;
@@ -233,40 +209,5 @@
             }.start();
         }
     }
-
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    public boolean needsInput() {
-        return false; // This view provides its own keypad
-    }
-
-    public void onPause() {
-
-    }
-
-    public void onResume() {
-        reset();
-    }
-
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        if (mCallback != null) {
-            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-        }
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-    }
-
-    @Override
-    public void afterTextChanged(Editable s) {
-    }
-
 }
+
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
index 0465805..e5b4b73 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSimPukView.java
@@ -19,49 +19,30 @@
 import android.app.Dialog;
 import android.app.ProgressDialog;
 import android.content.Context;
-import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.text.Editable;
+import android.text.InputType;
 import android.text.TextWatcher;
+import android.text.method.DigitsKeyListener;
 import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
+
 import com.android.internal.R;
 
-public class KeyguardSimPukView extends LinearLayout implements View.OnClickListener,
-    KeyguardSecurityView, OnEditorActionListener, TextWatcher {
-
-    private View mDeleteButton;
+/**
+ * Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
+ */
+public class KeyguardSimPukView extends KeyguardAbsKeyInputView
+        implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
 
     private ProgressDialog mSimUnlockProgressDialog = null;
-    private KeyguardSecurityCallback mCallback;
-
-    private SecurityMessageDisplay mSecurityMessageDisplay;
-
-    private PasswordEntryKeyboardView mKeyboardView;
-
-    private PasswordEntryKeyboardHelper mKeyboardHelper;
-
-    private LockPatternUtils mLockPatternUtils;
-
     private volatile boolean mCheckInProgress;
-
-    private TextView mSimPinEntry;
-
     private String mPukText;
-
     private String mPinText;
     private StateMachine mStateMachine = new StateMachine();
 
@@ -95,10 +76,11 @@
                         com.android.internal.R.string.lockscreen_sim_unlock_progress_dialog_message;
                     updateSim();
                 } else {
+                    state = ENTER_PIN; // try again?
                     msg = R.string.kg_invalid_confirm_pin_hint;
                 }
             }
-            mSimPinEntry.setText(null);
+            mPasswordEntry.setText(null);
             if (msg != 0) {
                 mSecurityMessageDisplay.setMessage(msg, true);
             }
@@ -109,7 +91,7 @@
             mPukText="";
             state = ENTER_PUK;
             mSecurityMessageDisplay.setMessage(R.string.kg_puk_enter_puk_hint, true);
-            mSimPinEntry.requestFocus();
+            mPasswordEntry.requestFocus();
         }
     }
 
@@ -119,62 +101,71 @@
 
     public KeyguardSimPukView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mLockPatternUtils = new LockPatternUtils(getContext());
     }
 
-    public void setKeyguardCallback(KeyguardSecurityCallback callback) {
-        mCallback = callback;
-        mLockPatternUtils = new LockPatternUtils(getContext());
+    public void resetState() {
+        mStateMachine.reset();
+        mPasswordEntry.setEnabled(true);
+    }
+
+    @Override
+    protected int getPasswordTextViewId() {
+        return R.id.pinEntry;
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mSimPinEntry = (TextView) findViewById(R.id.sim_pin_entry);
-        mSimPinEntry.setOnEditorActionListener(this);
-        mSimPinEntry.addTextChangedListener(this);
-        mDeleteButton = findViewById(R.id.delete_button);
-        mDeleteButton.setOnClickListener(this);
-        mKeyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
-        mKeyboardHelper = new PasswordEntryKeyboardHelper(mContext, mKeyboardView, this, false,
-                new int[] {
-                R.xml.kg_password_kbd_numeric,
-                com.android.internal.R.xml.password_kbd_qwerty,
-                com.android.internal.R.xml.password_kbd_qwerty_shifted,
-                com.android.internal.R.xml.password_kbd_symbols,
-                com.android.internal.R.xml.password_kbd_symbols_shift
-                });
-        mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
-        mKeyboardHelper.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
 
-        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
+        final View ok = findViewById(R.id.key_enter);
+        if (ok != null) {
+            ok.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    doHapticKeyClick();
+                    verifyPasswordAndUnlock();
+                }
+            });
+        }
+
+        // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
+        // not a separate view
+        View pinDelete = findViewById(R.id.delete_button);
+        if (pinDelete != null) {
+            pinDelete.setVisibility(View.VISIBLE);
+            pinDelete.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    CharSequence str = mPasswordEntry.getText();
+                    if (str.length() > 0) {
+                        mPasswordEntry.setText(str.subSequence(0, str.length()-1));
+                    }
+                    doHapticKeyClick();
+                }
+            });
+            pinDelete.setOnLongClickListener(new View.OnLongClickListener() {
+                public boolean onLongClick(View v) {
+                    mPasswordEntry.setText("");
+                    doHapticKeyClick();
+                    return true;
+                }
+            });
+        }
+
+        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
+        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+
+        mPasswordEntry.requestFocus();
+
         mSecurityMessageDisplay.setTimeout(0); // don't show ownerinfo/charging status by default
-        reset();
-    }
-
-    @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        return mSimPinEntry.requestFocus(direction, previouslyFocusedRect);
-    }
-
-    public boolean needsInput() {
-        return false; // This view provides its own keypad
-    }
-
-    public void onPause() {
-
-    }
-
-    public void onResume() {
-        reset();
     }
 
     @Override
     public void showUsabilityHint() {
     }
 
-    /** {@inheritDoc} */
-    public void cleanUp() {
+    @Override
+    public void onPause() {
         // dismiss the dialog.
         if (mSimUnlockProgressDialog != null) {
             mSimUnlockProgressDialog.dismiss();
@@ -218,23 +209,11 @@
         }
     }
 
-    public void onClick(View v) {
-        if (v == mDeleteButton) {
-            mSimPinEntry.requestFocus();
-            final Editable digits = mSimPinEntry.getEditableText();
-            final int len = digits.length();
-            if (len > 0) {
-                digits.delete(len-1, len);
-            }
-        }
-        mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-    }
-
     private Dialog getSimUnlockProgressDialog() {
         if (mSimUnlockProgressDialog == null) {
             mSimUnlockProgressDialog = new ProgressDialog(mContext);
-            mSimUnlockProgressDialog.setMessage(mContext.getString(
-                    R.string.kg_sim_unlock_progress_dialog_message));
+            mSimUnlockProgressDialog.setMessage(
+                    mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
             mSimUnlockProgressDialog.setIndeterminate(true);
             mSimUnlockProgressDialog.setCancelable(false);
             if (!(mContext instanceof Activity)) {
@@ -247,8 +226,8 @@
 
     private boolean checkPuk() {
         // make sure the puk is at least 8 digits long.
-        if (mSimPinEntry.getText().length() >= 8) {
-            mPukText = mSimPinEntry.getText().toString();
+        if (mPasswordEntry.getText().length() >= 8) {
+            mPukText = mPasswordEntry.getText().toString();
             return true;
         }
         return false;
@@ -256,16 +235,16 @@
 
     private boolean checkPin() {
         // make sure the PIN is between 4 and 8 digits
-        int length = mSimPinEntry.getText().length();
+        int length = mPasswordEntry.getText().length();
         if (length >= 4 && length <= 8) {
-            mPinText = mSimPinEntry.getText().toString();
+            mPinText = mPasswordEntry.getText().toString();
             return true;
         }
         return false;
     }
 
     public boolean confirmPin() {
-        return mPinText.equals(mSimPinEntry.getText().toString());
+        return mPinText.equals(mPasswordEntry.getText().toString());
     }
 
     private void updateSim() {
@@ -295,46 +274,9 @@
     }
 
     @Override
-    public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
-        // Check if this was the result of hitting the enter key
-        mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE
-                || actionId == EditorInfo.IME_ACTION_NEXT) {
-                mStateMachine.next();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public void setLockPatternUtils(LockPatternUtils utils) {
-        mLockPatternUtils = utils;
-    }
-
-    @Override
-    public void reset() {
-        mStateMachine.reset();
-    }
-
-    @Override
-    public KeyguardSecurityCallback getCallback() {
-        return mCallback;
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        if (mCallback != null) {
-            mCallback.userActivity(KeyguardViewManager.DIGIT_PRESS_WAKE_MILLIS);
-        }
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before, int count) {
-    }
-
-    @Override
-    public void afterTextChanged(Editable s) {
+    protected void verifyPasswordAndUnlock() {
+        mStateMachine.next();
     }
 }
+
+
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 fe4ac5b..d0fa81e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -520,8 +520,22 @@
             mSystemReady = true;
             mUpdateMonitor.registerCallback(mUpdateCallback);
 
-            // Disable alternate unlock right after boot until things have settled.
-            mUpdateMonitor.setAlternateUnlockEnabled(false);
+            // Suppress biometric unlock right after boot until things have settled if it is the
+            // selected security method, otherwise unsuppress it.  It must be unsuppressed if it is
+            // not the selected security method for the following reason:  if the user starts
+            // without a screen lock selected, the biometric unlock would be suppressed the first
+            // time they try to use it.
+            //
+            // Note that the biometric unlock will still not show if it is not the selected method.
+            // Calling setAlternateUnlockEnabled(true) simply says don't suppress it if it is the
+            // selected method.
+            if (mLockPatternUtils.usingBiometricWeak()
+                    && mLockPatternUtils.isBiometricWeakInstalled()) {
+                if (DEBUG) Log.d(TAG, "suppressing biometric unlock during boot");
+                mUpdateMonitor.setAlternateUnlockEnabled(false);
+            } else {
+                mUpdateMonitor.setAlternateUnlockEnabled(true);
+            }
 
             doKeyguardLocked();
         }
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 c89e880..ddded8e 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewStateManager.java
@@ -101,10 +101,21 @@
         ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
     }
 
-    public void onPageSwitch(View newPage, int newPageIndex) {
+    public void onPageSwitching(View newPage, int newPageIndex) {
+        if (mPagedView != null && mChallengeLayout instanceof SlidingChallengeLayout) {
+            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
+            ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
+        }
+    }
+
+    public void onPageSwitched(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.
         // This prevents conflicts.
+
+        // If the page hasn't switched, don't bother with any of this
+        if (mCurrentPage != newPageIndex) return;
+
         if (mPagedView != null && mChallengeLayout != null) {
             KeyguardWidgetFrame prevPage = mPagedView.getWidgetPageAt(mCurrentPage);
             if (prevPage != null && mCurrentPage != mPageListeningToSlider) {
@@ -162,7 +173,6 @@
             if (!challengeOverlapping) {
                 frame.resetSize();
             }
-            frame.onChallengeActive(mChallengeLayout.isChallengeShowing());
             frame.hideFrame(this);
 
             if (challengeOverlapping) {
@@ -196,8 +206,6 @@
             }
             // View is on the move.  Pause the security view until it completes.
             mKeyguardSecurityContainer.onPause();
-
-            frame.onChallengeActive(true);
         }
         mLastScrollState = scrollState;
     }
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 b1ff049..9ffabf8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -20,6 +20,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
@@ -42,6 +43,10 @@
             new PorterDuffXfermode(PorterDuff.Mode.ADD);
 
     static final float OUTLINE_ALPHA_MULTIPLIER = 0.6f;
+    static final int HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR = 0x99FF0000;
+
+    // Temporarily disable this for the time being until we know why the gfx is messing up
+    static final boolean ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY = true;
 
     private int mGradientColor;
     private LinearGradient mForegroundGradient;
@@ -62,7 +67,20 @@
     private float mBackgroundAlphaMultiplier = 1.0f;
     private Drawable mBackgroundDrawable;
     private Rect mBackgroundRect = new Rect();
+    private int mLastMeasuredWidth = -1;
+    private int mLastMeasuredHeight = 1;
+
+    // These variables are all needed in order to size things properly before we're actually
+    // measured.
     private int mSmallWidgetHeight;
+    private int mSmallFrameHeight;
+    private boolean mWidgetLockedSmall = false;
+    private int mMaxChallengeTop = -1;
+
+    // This will hold the width value before we've actually been measured
+    private int mFrameHeight;
+
+    private boolean mIsHoveringOverDeleteDropTarget;
 
     // 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.
@@ -98,8 +116,13 @@
         cancelLongPress();
     }
 
-    public void setMaxChallengeTop(int top) {
-        mSmallWidgetHeight = top - getPaddingTop();
+    void setIsHoveringOverDeleteDropTarget(boolean isHovering) {
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            if (mIsHoveringOverDeleteDropTarget != isHovering) {
+                mIsHoveringOverDeleteDropTarget = isHovering;
+                invalidate();
+            }
+        }
     }
 
     @Override
@@ -163,6 +186,12 @@
         c.drawRect(mForegroundRect, mGradientPaint);
     }
 
+    private void drawHoveringOverDeleteOverlay(Canvas c) {
+        if (mIsHoveringOverDeleteDropTarget) {
+            c.drawColor(HOVER_OVER_DELETE_DROP_TARGET_OVERLAY_COLOR);
+        }
+    }
+
     protected void drawBg(Canvas canvas) {
         if (mBackgroundAlpha > 0.0f) {
             Drawable bg = mBackgroundDrawable;
@@ -175,9 +204,16 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            canvas.save();
+        }
         drawBg(canvas);
         super.dispatchDraw(canvas);
         drawGradientOverlay(canvas);
+        if (ENABLE_HOVER_OVER_DELETE_DROP_TARGET_OVERLAY) {
+            drawHoveringOverDeleteOverlay(canvas);
+            canvas.restore();
+        }
     }
 
     /**
@@ -220,8 +256,10 @@
         View content = getContent();
         if (content instanceof AppWidgetHostView) {
             return ((AppWidgetHostView) content).getAppWidgetId();
-        } else {
+        } else if (content instanceof KeyguardStatusView) {
             return ((KeyguardStatusView) content).getAppWidgetId();
+        } else {
+            return AppWidgetManager.INVALID_APPWIDGET_ID;
         }
     }
 
@@ -260,22 +298,6 @@
     }
 
     /**
-     * Set the top location of the challenge.
-     *
-     * @param top The top of the challenge, in _local_ coordinates, or -1 to indicate the challenge
-     *              is down.
-     */
-    private void setChallengeTop(int top, boolean updateWidgetSize) {
-        // The widget starts below the padding, and extends to the top of the challengs.
-        int widgetHeight = top - getPaddingTop();
-        int frameHeight = top + getPaddingBottom();
-        setFrameHeight(frameHeight);
-        if (updateWidgetSize) {
-            setWidgetHeight(widgetHeight);
-        }
-    }
-
-    /**
      * Depending on whether the security is up, the widget size needs to change
      * 
      * @param height The height of the widget, -1 for full height
@@ -295,28 +317,51 @@
         }
     }
 
+    public void setMaxChallengeTop(int top) {
+        boolean dirty = mMaxChallengeTop != top;
+        mSmallWidgetHeight = top - getPaddingTop();
+        mSmallFrameHeight = top + getPaddingBottom();
+        if (dirty && mIsSmall) {
+            setWidgetHeight(mSmallWidgetHeight);
+            setFrameHeight(mSmallFrameHeight);
+        } else if (dirty && mWidgetLockedSmall) {
+            setWidgetHeight(mSmallWidgetHeight);
+        }
+    }
+
     public boolean isSmall() {
         return mIsSmall;
     }
 
     public void adjustFrame(int challengeTop) {
-        setChallengeTop(challengeTop, false);
+        int frameHeight = challengeTop + getPaddingBottom();
+        setFrameHeight(frameHeight);
     }
 
     public void shrinkWidget() {
         mIsSmall = true;
-        setChallengeTop(mSmallWidgetHeight, true);
+        setWidgetHeight(mSmallWidgetHeight);
+        setFrameHeight(mSmallFrameHeight);
+    }
+
+    public void setWidgetLockedSmall(boolean locked) {
+        if (locked) {
+            setWidgetHeight(mSmallWidgetHeight);
+        }
+        mWidgetLockedSmall = locked;
     }
 
     public void resetSize() {
         mIsSmall = false;
+        if (!mWidgetLockedSmall) {
+            setWidgetHeight(LayoutParams.MATCH_PARENT);
+        }
         setFrameHeight(getMeasuredHeight());
-        setWidgetHeight(LayoutParams.MATCH_PARENT);
     }
 
     public void setFrameHeight(int height) {
-        height = Math.min(height, getMeasuredHeight());
-        mBackgroundRect.set(0, 0, getMeasuredWidth(), height);
+        mFrameHeight = height;
+        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(mFrameHeight, getMeasuredHeight()));
         invalidate();
     }
 
@@ -356,10 +401,38 @@
                 mGradientColor, 0, Shader.TileMode.CLAMP);
         mRightToLeftGradient = new LinearGradient(x1, 0f, x0, 0f,
                 mGradientColor, 0, Shader.TileMode.CLAMP);
-        mBackgroundRect.set(0, 0, w, h);
+
+        if (!mIsSmall) {
+            mFrameHeight = h;
+        }
+
+        mBackgroundRect.set(0, 0, getMeasuredWidth(), Math.min(h, mFrameHeight));
         invalidate();
     }
 
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        performAppWidgetSizeCallbacksIfNecessary();
+    }
+
+    private void performAppWidgetSizeCallbacksIfNecessary() {
+        View content = getContent();
+        if (!(content instanceof AppWidgetHostView)) return;
+
+        boolean sizeDirty = content.getMeasuredWidth() != mLastMeasuredWidth ||
+                content.getMeasuredHeight() != mLastMeasuredHeight;
+        if (sizeDirty) {
+
+        }
+
+        AppWidgetHostView awhv = (AppWidgetHostView) content;
+        float density = getResources().getDisplayMetrics().density;
+
+        int width = (int) (content.getMeasuredWidth() / density);
+        int height = (int) (content.getMeasuredHeight() / density);
+        awhv.updateAppWidgetSize(null, width, height, width, height, true);
+    }
+
     void setOverScrollAmount(float r, boolean left) {
         if (Float.compare(mOverScrollAmount, r) != 0) {
             mOverScrollAmount = r;
@@ -373,12 +446,8 @@
         // hook for subclasses
     }
 
-    public boolean onUserInteraction(int action) {
+    public boolean onUserInteraction(MotionEvent event) {
         // hook for subclasses
         return false;
     }
-
-    public void onChallengeActive(boolean challengeActive) {
-        // hook for subclasses
-    }
 }
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 f04c4df..acb2913 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -21,6 +21,8 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Handler;
@@ -31,9 +33,9 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
@@ -117,7 +119,14 @@
     }
 
     @Override
-    public void onPageSwitch(View newPage, int newPageIndex) {
+    public void onPageSwitching(View newPage, int newPageIndex) {
+        if (mViewStateManager != null) {
+            mViewStateManager.onPageSwitching(newPage, newPageIndex);
+        }
+    }
+
+    @Override
+    public void onPageSwitched(View newPage, int newPageIndex) {
         boolean showingStatusWidget = false;
         if (newPage instanceof ViewGroup) {
             ViewGroup vg = (ViewGroup) newPage;
@@ -156,7 +165,7 @@
             }
         }
         if (mViewStateManager != null) {
-            mViewStateManager.onPageSwitch(newPage, newPageIndex);
+            mViewStateManager.onPageSwitched(newPage, newPageIndex);
         }
     }
 
@@ -177,7 +186,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
-        if (currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev.getAction())) {
+        if (currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev)) {
             return true;
         }
         return super.onTouchEvent(ev);
@@ -250,10 +259,23 @@
             FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                     LayoutParams.MATCH_PARENT);
             lp.gravity = Gravity.TOP;
+
             // The framework adds a default padding to AppWidgetHostView. We don't need this padding
             // for the Keyguard, so we override it to be 0.
             widget.setPadding(0,  0, 0, 0);
             frame.addView(widget, lp);
+
+            // We set whether or not this widget supports vertical resizing.
+            if (widget instanceof AppWidgetHostView) {
+                AppWidgetHostView awhv = (AppWidgetHostView) widget;
+                AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
+                if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
+                    frame.setWidgetLockedSmall(false);
+                } else {
+                    // Lock the widget to be small.
+                    frame.setWidgetLockedSmall(true);
+                }
+            }
         } else {
             frame = (KeyguardWidgetFrame) widget;
         }
@@ -549,20 +571,20 @@
             // coordinate relative to our children, hence we subtract the top padding.s
             maxChallengeTop = top - getPaddingTop();
             challengeShowing = scl.isChallengeShowing();
-        }
 
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            KeyguardWidgetFrame frame = getWidgetPageAt(i);
-            frame.setMaxChallengeTop(maxChallengeTop);
-
-            // On the very first measure pass, if the challenge is showing, we need to make sure
-            // that the widget on the current page is small.
-            if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
-                frame.shrinkWidget();
+            int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                KeyguardWidgetFrame frame = getWidgetPageAt(i);
+                frame.setMaxChallengeTop(maxChallengeTop);
+                // On the very first measure pass, if the challenge is showing, we need to make sure
+                // that the widget on the current page is small.
+                if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
+                    frame.shrinkWidget();
+                }
             }
         }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mHasMeasure = true;
     }
 
     void animateOutlinesAndSidePages(final boolean show) {
@@ -695,4 +717,10 @@
             return indexOfChild((KeyguardWidgetFrame)view.getParent());
         }
     }
+
+    @Override
+    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
+        KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
+        child.setIsHoveringOverDeleteDropTarget(isHovering);
+    }
 }
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 b38eb28..3bc39eb 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/MultiPaneChallengeLayout.java
@@ -47,6 +47,7 @@
     private OnBouncerStateChangedListener mBouncerListener;
 
     private final Rect mTempRect = new Rect();
+    private final Context mContext;
 
     private final OnClickListener mScrimClickListener = new OnClickListener() {
         @Override
@@ -66,6 +67,8 @@
     public MultiPaneChallengeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
+        mContext = context;
+
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.MultiPaneChallengeLayout, defStyleAttr, 0);
         mOrientation = a.getInt(R.styleable.MultiPaneChallengeLayout_orientation,
@@ -173,6 +176,8 @@
             throw new IllegalArgumentException(
                     "MultiPaneChallengeLayout must be measured with an exact size");
         }
+        float squashedLayoutThreshold =
+                mContext.getResources().getDimension(R.dimen.kg_squashed_layout_threshold);
 
         final int width = MeasureSpec.getSize(widthSpec);
         final int height = MeasureSpec.getSize(heightSpec);
@@ -208,28 +213,32 @@
                 mUserSwitcherView = child;
 
                 if (child.getVisibility() == GONE) continue;
+                if (height < squashedLayoutThreshold) {
+                    int zero = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
+                    measureChild(child, zero, zero);
+                } else {
+                    int adjustedWidthSpec = widthSpec;
+                    int adjustedHeightSpec = heightSpec;
+                    if (lp.maxWidth >= 0) {
+                        adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
+                                Math.min(lp.maxWidth, MeasureSpec.getSize(widthSpec)),
+                                MeasureSpec.EXACTLY);
+                    }
+                    if (lp.maxHeight >= 0) {
+                        adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
+                                Math.min(lp.maxHeight, MeasureSpec.getSize(heightSpec)),
+                                MeasureSpec.EXACTLY);
+                    }
+                    // measureChildWithMargins will resolve layout direction for the LayoutParams
+                    measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
 
-                int adjustedWidthSpec = widthSpec;
-                int adjustedHeightSpec = heightSpec;
-                if (lp.maxWidth >= 0) {
-                    adjustedWidthSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxWidth, MeasureSpec.getSize(widthSpec)),
-                            MeasureSpec.EXACTLY);
-                }
-                if (lp.maxHeight >= 0) {
-                    adjustedHeightSpec = MeasureSpec.makeMeasureSpec(
-                            Math.min(lp.maxHeight, MeasureSpec.getSize(heightSpec)),
-                            MeasureSpec.EXACTLY);
-                }
-                // measureChildWithMargins will resolve layout direction for the LayoutParams
-                measureChildWithMargins(child, adjustedWidthSpec, 0, adjustedHeightSpec, 0);
-
-                // Only subtract out space from one dimension. Favor vertical.
-                // Offset by 1.5x to add some balance along the other edge.
-                if (Gravity.isVertical(lp.gravity)) {
-                    heightUsed += child.getMeasuredHeight() * 1.5f;
-                } else if (Gravity.isHorizontal(lp.gravity)) {
-                    widthUsed += child.getMeasuredWidth() * 1.5f;
+                    // Only subtract out space from one dimension. Favor vertical.
+                    // Offset by 1.5x to add some balance along the other edge.
+                    if (Gravity.isVertical(lp.gravity)) {
+                        heightUsed += child.getMeasuredHeight() * 1.5f;
+                    } else if (Gravity.isHorizontal(lp.gravity)) {
+                        widthUsed += child.getMeasuredWidth() * 1.5f;
+                    }
                 }
             } else if (lp.childType == LayoutParams.CHILD_TYPE_SCRIM) {
                 setScrimView(child);
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 ca36007..7f51a84 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/NumPadKey.java
@@ -51,7 +51,8 @@
                     }
                 }
             }
-            if (mTextView != null) {
+            // check for time-based lockouts
+            if (mTextView != null && mTextView.isEnabled()) {
                 mTextView.append(String.valueOf(mDigit));
             }
             doHapticKeyClick();
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 6eeada5..00a0aed 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/PagedView.java
@@ -48,6 +48,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.widget.Scroller;
 
 import com.android.internal.R;
@@ -205,6 +206,7 @@
     protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
     private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 300;
     private float REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE = 0.1f;
+    private long REORDERING_DELETE_DROP_TARGET_FADE_DURATION = 150;
     private float mMinScale = 1f;
     protected View mDragView;
     private AnimatorSet mZoomInOutAnim;
@@ -228,18 +230,25 @@
     // Convenience/caching
     private Matrix mTmpInvMatrix = new Matrix();
     private float[] mTmpPoint = new float[2];
+    private Rect mTmpRect = new Rect();
 
     // Fling to delete
     private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
     private float FLING_TO_DELETE_FRICTION = 0.035f;
     // The degrees specifies how much deviation from the up vector to still consider a fling "up"
-    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 35f;
-    private int FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
     protected int mFlingToDeleteThresholdVelocity = -1400;
-    private boolean mIsFlingingToDelete = false;
+    // Drag to delete
+    private boolean mDeferringForDelete = false;
+    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
+    private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
+
+    // Drop to delete
+    private View mDeleteDropTarget;
 
     public interface PageSwitchListener {
-        void onPageSwitch(View newPage, int newPageIndex);
+        void onPageSwitching(View newPage, int newPageIndex);
+        void onPageSwitched(View newPage, int newPageIndex);
     }
 
     public PagedView(Context context) {
@@ -293,19 +302,23 @@
         setOnHierarchyChangeListener(this);
     }
 
+    void setDeleteDropTarget(View v) {
+        mDeleteDropTarget = v;
+    }
+
     // Convenience methods to map points from self to parent and vice versa
-    float[] mapPointFromSelfToParent(float x, float y) {
+    float[] mapPointFromViewToParent(View v, float x, float y) {
         mTmpPoint[0] = x;
         mTmpPoint[1] = y;
-        getMatrix().mapPoints(mTmpPoint);
-        mTmpPoint[0] += getLeft();
-        mTmpPoint[1] += getTop();
+        v.getMatrix().mapPoints(mTmpPoint);
+        mTmpPoint[0] += v.getLeft();
+        mTmpPoint[1] += v.getTop();
         return mTmpPoint;
     }
-    float[] mapPointFromParentToSelf(float x, float y) {
-        mTmpPoint[0] = x - getLeft();
-        mTmpPoint[1] = y - getTop();
-        getMatrix().invert(mTmpInvMatrix);
+    float[] mapPointFromParentToView(View v, float x, float y) {
+        mTmpPoint[0] = x - v.getLeft();
+        mTmpPoint[1] = y - v.getTop();
+        v.getMatrix().invert(mTmpInvMatrix);
         mTmpInvMatrix.mapPoints(mTmpPoint);
         return mTmpPoint;
     }
@@ -328,7 +341,7 @@
     public void setScaleX(float scaleX) {
         super.setScaleX(scaleX);
         if (isReordering(true)) {
-            float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
             mLastMotionX = p[0];
             mLastMotionY = p[1];
             updateDragViewTranslationDuringDrag();
@@ -356,7 +369,7 @@
     public void setPageSwitchListener(PageSwitchListener pageSwitchListener) {
         mPageSwitchListener = pageSwitchListener;
         if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
         }
     }
 
@@ -415,6 +428,7 @@
      * Sets the current page.
      */
     void setCurrentPage(int currentPage) {
+        notifyPageSwitching(currentPage);
         if (!mScroller.isFinished()) {
             mScroller.abortAnimation();
         }
@@ -428,7 +442,7 @@
         mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
         updateCurrentPageScroll();
         updateScrollingIndicator();
-        notifyPageSwitchListener();
+        notifyPageSwitched();
         invalidate();
     }
 
@@ -436,9 +450,15 @@
         mOnlyAllowEdgeSwipes = enable;
     }
 
-    protected void notifyPageSwitchListener() {
+    protected void notifyPageSwitching(int whichPage) {
         if (mPageSwitchListener != null) {
-            mPageSwitchListener.onPageSwitch(getPageAt(mCurrentPage), mCurrentPage);
+            mPageSwitchListener.onPageSwitching(getPageAt(whichPage), whichPage);
+        }
+    }
+
+    protected void notifyPageSwitched() {
+        if (mPageSwitchListener != null) {
+            mPageSwitchListener.onPageSwitched(getPageAt(mCurrentPage), mCurrentPage);
         }
     }
 
@@ -511,7 +531,7 @@
 
         // Update the last motion events when scrolling
         if (isReordering(true)) {
-            float[] p = mapPointFromParentToSelf(mParentDownMotionX, mParentDownMotionY);
+            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
             mLastMotionX = p[0];
             mLastMotionY = p[1];
             updateDragViewTranslationDuringDrag();
@@ -532,13 +552,14 @@
         } else if (mNextPage != INVALID_PAGE) {
             mCurrentPage = Math.max(0, Math.min(mNextPage, getPageCount() - 1));
             mNextPage = INVALID_PAGE;
-            notifyPageSwitchListener();
+            notifyPageSwitched();
 
             // We don't want to trigger a page end moving unless the page has settled
             // and the user has stopped scrolling
             if (mTouchState == TOUCH_STATE_REST) {
                 pageEndMoving();
             }
+
             onPostReorderingAnimationCompleted();
             return true;
         }
@@ -632,7 +653,7 @@
         // ensure that the cache is filled with good values.
         invalidateCachedOffsets();
 
-        if (mChildCountOnLastMeasure != getChildCount() && !mIsFlingingToDelete) {
+        if (mChildCountOnLastMeasure != getChildCount() && !mDeferringForDelete) {
             setCurrentPage(mCurrentPage);
         }
         mChildCountOnLastMeasure = getChildCount();
@@ -856,7 +877,6 @@
         final int pageCount = getChildCount();
         if (pageCount > 0) {
             getVisiblePages(mTempVisiblePagesRange);
-            boundByReorderablePages(isReordering(false), mTempVisiblePagesRange);
             final int leftScreen = mTempVisiblePagesRange[0];
             final int rightScreen = mTempVisiblePagesRange[1];
             if (leftScreen != -1 && rightScreen != -1) {
@@ -1038,7 +1058,7 @@
                 mDownScrollX = getScrollX();
                 mLastMotionX = x;
                 mLastMotionY = y;
-                float[] p = mapPointFromSelfToParent(x, y);
+                float[] p = mapPointFromViewToParent(this, x, y);
                 mParentDownMotionX = p[0];
                 mParentDownMotionY = p[1];
                 mLastMotionXRemainder = 0;
@@ -1270,7 +1290,7 @@
             mDownMotionX = mLastMotionX = ev.getX();
             mDownMotionY = mLastMotionY = ev.getY();
             mDownScrollX = getScrollX();
-            float[] p = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+            float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
             mParentDownMotionX = p[0];
             mParentDownMotionY = p[1];
             mLastMotionXRemainder = 0;
@@ -1322,7 +1342,7 @@
 
                 // Update the parent down so that our zoom animations take this new movement into
                 // account
-                float[] pt = mapPointFromSelfToParent(mLastMotionX, mLastMotionY);
+                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
                 mParentDownMotionX = pt[0];
                 mParentDownMotionY = pt[1];
                 updateDragViewTranslationDuringDrag();
@@ -1331,11 +1351,16 @@
                 final int dragViewIndex = indexOfChild(mDragView);
                 int bufferSize = (int) (REORDERING_SIDE_PAGE_BUFFER_PERCENTAGE *
                     getViewportWidth());
-                int leftBufferEdge = (int) (mapPointFromSelfToParent(mViewport.left, 0)[0]
+                int leftBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.left, 0)[0]
                         + bufferSize);
-                int rightBufferEdge = (int) (mapPointFromSelfToParent(mViewport.right, 0)[0]
+                int rightBufferEdge = (int) (mapPointFromViewToParent(this, mViewport.right, 0)[0]
                         - bufferSize);
 
+                // Change the drag view if we are hovering over the drop target
+                boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
+                        (int) mParentDownMotionX, (int) mParentDownMotionY);
+                setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
+
                 if (DEBUG) Log.d(TAG, "leftBufferEdge: " + leftBufferEdge);
                 if (DEBUG) Log.d(TAG, "rightBufferEdge: " + rightBufferEdge);
                 if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
@@ -1352,7 +1377,7 @@
                 }
 
                 final int pageUnderPointIndex = pageIndexToSnapTo;
-                if (pageUnderPointIndex > -1) {
+                if (pageUnderPointIndex > -1 && !isHoveringOverDelete) {
                     mTempVisiblePagesRange[0] = 0;
                     mTempVisiblePagesRange[1] = getPageCount() - 1;
                     boundByReorderablePages(true, mTempVisiblePagesRange);
@@ -1485,13 +1510,29 @@
                     snapToDestination();
                 }
             } else if (mTouchState == TOUCH_STATE_REORDERING) {
+                // Update the last motion position
+                mLastMotionX = ev.getX();
+                mLastMotionY = ev.getY();
+
+                // Update the parent down so that our zoom animations take this new movement into
+                // account
+                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
+                mParentDownMotionX = pt[0];
+                mParentDownMotionY = pt[1];
+                updateDragViewTranslationDuringDrag();
+                boolean handledFling = false;
                 if (!DISABLE_FLING_TO_DELETE) {
                     // Check the velocity and see if we are flinging-to-delete
                     PointF flingToDeleteVector = isFlingingToDelete();
                     if (flingToDeleteVector != null) {
                         onFlingToDelete(flingToDeleteVector);
+                        handledFling = true;
                     }
                 }
+                if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
+                        (int) mParentDownMotionY)) {
+                    onDropToDelete();
+                }
             } else {
                 onUnhandledTap(ev);
             }
@@ -1743,7 +1784,7 @@
     }
     protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) {
         mNextPage = whichPage;
-
+        notifyPageSwitching(whichPage);
         View focusedChild = getFocusedChild();
         if (focusedChild != null && whichPage != mCurrentPage &&
                 focusedChild == getPageAt(mCurrentPage)) {
@@ -1761,13 +1802,14 @@
         if (!mScroller.isFinished()) mScroller.abortAnimation();
         mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
 
-        notifyPageSwitchListener();
+        notifyPageSwitched();
 
         // Trigger a compute() to finish switching pages if necessary
         if (immediate) {
             computeScroll();
         }
 
+        mForceScreenScrolled = true;
         invalidate();
     }
 
@@ -1991,6 +2033,23 @@
             mZoomInOutAnim.playTogether(
                     ObjectAnimator.ofFloat(this, "scaleX", mMinScale),
                     ObjectAnimator.ofFloat(this, "scaleY", mMinScale));
+            mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    // Show the delete drop target
+                    if (mDeleteDropTarget != null) {
+                        mDeleteDropTarget.setVisibility(View.VISIBLE);
+                        mDeleteDropTarget.animate().alpha(1f)
+                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+                            .setListener(new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationStart(Animator animation) {
+                                    mDeleteDropTarget.setAlpha(0f);
+                                }
+                            });
+                    }
+                }
+            });
             mZoomInOutAnim.start();
             return true;
         }
@@ -2007,6 +2066,15 @@
         mTouchState = TOUCH_STATE_REORDERING;
         mIsReordering = true;
 
+        // Mark all the non-widget pages as invisible
+        getVisiblePages(mTempVisiblePagesRange);
+        boundByReorderablePages(true, mTempVisiblePagesRange);
+        for (int i = 0; i < getPageCount(); ++i) {
+            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+                getPageAt(i).setAlpha(0f);
+            }
+        }
+
         // We must invalidate to trigger a redraw to update the layers such that the drag view
         // is always drawn on top
         invalidate();
@@ -2028,6 +2096,15 @@
                     R.string.keyguard_accessibility_widget_reorder_end));
         }
         mIsReordering = false;
+
+        // Mark all the non-widget pages as visible again
+        getVisiblePages(mTempVisiblePagesRange);
+        boundByReorderablePages(true, mTempVisiblePagesRange);
+        for (int i = 0; i < getPageCount(); ++i) {
+            if (i < mTempVisiblePagesRange[0] || i > mTempVisiblePagesRange[1]) {
+                getPageAt(i).setAlpha(1f);
+            }
+        }
     }
 
     public boolean startReordering() {
@@ -2072,7 +2149,7 @@
                 onEndReordering();
             }
         };
-        if (!mIsFlingingToDelete) {
+        if (!mDeferringForDelete) {
             mPostReorderingPreZoomInRunnable = new Runnable() {
                 public void run() {
                     zoomIn(onCompleteRunnable);
@@ -2086,7 +2163,7 @@
             // Animate the drag view back to the front position
             animateDragViewToOriginalPosition();
         } else {
-            zoomIn(onCompleteRunnable);
+            // Handled in post-delete-animation-callbacks
         }
     }
 
@@ -2103,6 +2180,20 @@
                     ObjectAnimator.ofFloat(this, "scaleY", 1f));
             mZoomInOutAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
+                public void onAnimationStart(Animator animation) {
+                    // Hide the delete drop target
+                    if (mDeleteDropTarget != null) {
+                        mDeleteDropTarget.animate().alpha(0f)
+                            .setDuration(REORDERING_DELETE_DROP_TARGET_FADE_DURATION)
+                            .setListener(new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationEnd(Animator animation) {
+                                    mDeleteDropTarget.setVisibility(View.GONE);
+                                }
+                            });
+                    }
+                }
+                @Override
                 public void onAnimationCancel(Animator animation) {
                     mDragView = null;
                 }
@@ -2186,6 +2277,97 @@
         }
     };
 
+    private Runnable createPostDeleteAnimationRunnable(final View dragView) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                int dragViewIndex = indexOfChild(dragView);
+
+                // For each of the pages around the drag view, animate them from the previous
+                // position to the new position in the layout (as a result of the drag view moving
+                // in the layout)
+                // NOTE: We can make an assumption here because we have side-bound pages that we
+                //       will always have pages to animate in from the left
+                getVisiblePages(mTempVisiblePagesRange);
+                boundByReorderablePages(true, mTempVisiblePagesRange);
+                boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
+                boolean slideFromLeft = (isLastWidgetPage ||
+                        dragViewIndex > mTempVisiblePagesRange[0]);
+
+                // Setup the scroll to the correct page before we swap the views
+                if (slideFromLeft) {
+                    snapToPageImmediately(dragViewIndex - 1);
+                }
+
+                int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
+                int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
+                int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
+                int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
+                ArrayList<Animator> animations = new ArrayList<Animator>();
+                for (int i = lowerIndex; i <= upperIndex; ++i) {
+                    View v = getChildAt(i);
+                    // dragViewIndex < pageUnderPointIndex, so after we remove the
+                    // drag view all subsequent views to pageUnderPointIndex will
+                    // shift down.
+                    int oldX = 0;
+                    int newX = 0;
+                    if (slideFromLeft) {
+                        if (i == 0) {
+                            // Simulate the page being offscreen with the page spacing
+                            oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
+                                    - mPageSpacing;
+                        } else {
+                            oldX = getViewportOffsetX() + getChildOffset(i - 1);
+                        }
+                        newX = getViewportOffsetX() + getChildOffset(i);
+                    } else {
+                        oldX = getChildOffset(i) - getChildOffset(i - 1);
+                        newX = 0;
+                    }
+
+                    // Animate the view translation from its old position to its new
+                    // position
+                    AnimatorSet anim = (AnimatorSet) v.getTag();
+                    if (anim != null) {
+                        anim.cancel();
+                    }
+
+                    // Note: Hacky, but we want to skip any optimizations to not draw completely
+                    // hidden views
+                    v.setAlpha(Math.max(v.getAlpha(), 0.01f));
+                    v.setTranslationX(oldX - newX);
+                    anim = new AnimatorSet();
+                    anim.playTogether(
+                            ObjectAnimator.ofFloat(v, "translationX", 0f),
+                            ObjectAnimator.ofFloat(v, "alpha", 1f));
+                    animations.add(anim);
+                    v.setTag(anim);
+                }
+
+                AnimatorSet slideAnimations = new AnimatorSet();
+                slideAnimations.playTogether(animations);
+                slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
+                slideAnimations.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        final Runnable onCompleteRunnable = new Runnable() {
+                            @Override
+                            public void run() {
+                                mDeferringForDelete = false;
+                                onEndReordering();
+                            }
+                        };
+                        zoomIn(onCompleteRunnable);
+                    }
+                });
+                slideAnimations.start();
+
+                removeView(dragView);
+                onRemoveView(dragView);
+            }
+        };
+    }
+
     public void onFlingToDelete(PointF vel) {
         final long startTime = AnimationUtils.currentAnimationTimeMillis();
 
@@ -2222,59 +2404,7 @@
         AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
                 from, startTime, FLING_TO_DELETE_FRICTION);
 
-        final Runnable onAnimationEndRunnable = new Runnable() {
-            @Override
-            public void run() {
-                int dragViewIndex = indexOfChild(dragView);
-                // Setup the scroll to the correct page before we swap the views
-                snapToPageImmediately(dragViewIndex - 1);
-
-                // For each of the pages around the drag view, animate them from the previous
-                // position to the new position in the layout (as a result of the drag view moving
-                // in the layout)
-                // NOTE: We can make an assumption here because we have side-bound pages that we
-                //       will always have pages to animate in from the left
-                int lowerIndex = 0;
-                int upperIndex = dragViewIndex - 1;
-                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                    View v = getChildAt(i);
-                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                    // drag view all subsequent views to pageUnderPointIndex will
-                    // shift down.
-                    int oldX = 0;
-                    if (i == 0) {
-                        oldX = -(getViewportOffsetX() + getChildOffset(i));
-                    } else {
-                        oldX = getViewportOffsetX() + getChildOffset(i - 1);
-                    }
-                    int newX = getViewportOffsetX() + getChildOffset(i);
-
-                    // Animate the view translation from its old position to its new
-                    // position
-                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                    if (anim != null) {
-                        anim.cancel();
-                    }
-
-                    v.setTranslationX(oldX - newX);
-                    anim = new AnimatorSet();
-                    anim.setDuration(FLING_TO_DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
-                    anim.playTogether(
-                            ObjectAnimator.ofFloat(v, "translationX", 0f));
-                    anim.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mIsFlingingToDelete = false;
-                        }
-                    });
-                    anim.start();
-                    v.setTag(anim);
-                }
-
-                removeView(dragView);
-                onRemoveView(dragView);
-            }
-        };
+        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
 
         // Create and start the animation
         ValueAnimator mDropAnim = new ValueAnimator();
@@ -2288,11 +2418,57 @@
             }
         });
         mDropAnim.start();
-        mIsFlingingToDelete = true;
+        mDeferringForDelete = true;
+    }
+
+    /* Drag to delete */
+    private boolean isHoveringOverDeleteDropTarget(int x, int y) {
+        if (mDeleteDropTarget != null) {
+            mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
+            return mTmpRect.contains(x, y);
+        }
+        return false;
+    }
+
+    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
+
+    private void onDropToDelete() {
+        final View dragView = mDragView;
+
+        final float toScale = 0f;
+        final float toAlpha = 0f;
+
+        // Create and start the complex animation
+        ArrayList<Animator> animations = new ArrayList<Animator>();
+        AnimatorSet motionAnim = new AnimatorSet();
+        motionAnim.setInterpolator(new DecelerateInterpolator(2));
+        motionAnim.playTogether(
+                ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
+                ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
+        animations.add(motionAnim);
+
+        AnimatorSet alphaAnim = new AnimatorSet();
+        alphaAnim.setInterpolator(new LinearInterpolator());
+        alphaAnim.playTogether(
+                ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
+        animations.add(alphaAnim);
+
+        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
+
+        AnimatorSet anim = new AnimatorSet();
+        anim.playTogether(animations);
+        anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                onAnimationEndRunnable.run();
+            }
+        });
+        anim.start();
+
+        mDeferringForDelete = true;
     }
 
     /* Accessibility */
-
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
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 6156143..1f33fc3 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/SlidingChallengeLayout.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.policy.impl.keyguard;
 
+import com.android.internal.R;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -29,7 +31,6 @@
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
-import android.util.MathUtils;
 import android.util.Property;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -40,8 +41,6 @@
 import android.view.animation.Interpolator;
 import android.widget.Scroller;
 
-import com.android.internal.R;
-
 /**
  * This layout handles interaction with the sliding security challenge views
  * that overlay/resize other keyguard contents.
@@ -53,7 +52,7 @@
     // The drag handle is measured in dp above & below the top edge of the
     // challenge view; these parameters change based on whether the challenge 
     // is open or closed.
-    private static final int DRAG_HANDLE_CLOSED_ABOVE = 64; // dp
+    private static final int DRAG_HANDLE_CLOSED_ABOVE = 8; // dp
     private static final int DRAG_HANDLE_CLOSED_BELOW = 0; // dp
     private static final int DRAG_HANDLE_OPEN_ABOVE = 8; // dp
     private static final int DRAG_HANDLE_OPEN_BELOW = 0; // dp
@@ -123,6 +122,7 @@
     private final Rect mTempRect = new Rect();
 
     private boolean mHasGlowpad;
+    private boolean mChallengeInteractive = true;
 
     static final Property<SlidingChallengeLayout, Float> HANDLE_ALPHA =
             new FloatProperty<SlidingChallengeLayout>("handleAlpha") {
@@ -276,6 +276,13 @@
         }
     }
 
+    public void setChallengeInteractive(boolean interactive) {
+        mChallengeInteractive = interactive;
+        if (mExpandChallengeView != null) {
+            mExpandChallengeView.setEnabled(interactive);
+        }
+    }
+
     void animateHandle(boolean visible) {
         if (mHandleAnimation != null) {
             mHandleAnimation.cancel();
@@ -580,19 +587,17 @@
                 for (int i = 0; i < count; i++) {
                     final float x = ev.getX(i);
                     final float y = ev.getY(i);
-                    if (!mIsBouncing && mActivePointerId == INVALID_POINTER
-                                && ((isInDragHandle(x, y) && MathUtils.sq(x - mGestureStartX)
-                                        + MathUtils.sq(y - mGestureStartY) > mTouchSlopSquare)
-                                || crossedDragHandle(x, y, mGestureStartY)
+                    if (!mIsBouncing && mChallengeInteractive && mActivePointerId == INVALID_POINTER
+                                && (crossedDragHandle(x, y, mGestureStartY)
                                 || (isInChallengeView(x, y) &&
-                                       mScrollState == SCROLL_STATE_SETTLING))) {
+                                        mScrollState == SCROLL_STATE_SETTLING))) {
                         mActivePointerId = ev.getPointerId(i);
                         mGestureStartX = x;
                         mGestureStartY = y;
                         mGestureStartChallengeBottom = getChallengeBottom();
                         mDragging = true;
                         mChallengeView.setLayerType(LAYER_TYPE_HARDWARE, null);
-                    } else if (isInChallengeView(x, y)) {
+                    } else if (mChallengeShowing && isInChallengeView(x, y)) {
                         mBlockDrag = true;
                     }
                 }
@@ -630,7 +635,7 @@
                 break;
 
             case MotionEvent.ACTION_CANCEL:
-                if (mDragging) {
+                if (mDragging && mChallengeInteractive) {
                     showChallenge(0);
                 }
                 resetTouch();
@@ -641,7 +646,7 @@
                     break;
                 }
             case MotionEvent.ACTION_UP:
-                if (mDragging) {
+                if (mDragging && mChallengeInteractive) {
                     mVelocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
                     showChallenge((int) mVelocityTracker.getYVelocity(mActivePointerId));
                 }
@@ -657,7 +662,8 @@
 
                         if ((isInDragHandle(x, y) || crossedDragHandle(x, y, mGestureStartY) ||
                                 (isInChallengeView(x, y) && mScrollState == SCROLL_STATE_SETTLING))
-                                && mActivePointerId == INVALID_POINTER) {
+                                && mActivePointerId == INVALID_POINTER
+                                && mChallengeInteractive) {
                             mGestureStartX = x;
                             mGestureStartY = y;
                             mActivePointerId = ev.getPointerId(i);
@@ -767,11 +773,19 @@
     }
 
     private boolean crossedDragHandle(float x, float y, float initialY) {
+
         final int challengeTop = mChallengeView.getTop();
-        return  x >= 0 &&
-                x < getWidth() &&
-                initialY < (challengeTop - getDragHandleSizeAbove()) &&
-                y > challengeTop + getDragHandleSizeBelow();
+        final boolean horizOk = x >= 0 && x < getWidth();
+
+        final boolean vertOk;
+        if (mChallengeShowing) {
+            vertOk = initialY < (challengeTop - getDragHandleSizeAbove()) &&
+                    y > challengeTop + getDragHandleSizeBelow();
+        } else {
+            vertOk = initialY > challengeTop + getDragHandleSizeBelow() &&
+                    y < challengeTop - getDragHandleSizeAbove();
+        }
+        return horizOk && vertOk;
     }
 
     @Override
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index d0dd9cf..daa82f2 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -599,7 +599,7 @@
     }
 
     public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) {
-        mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET,
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET,
             "bindAppWidgetId appWidgetId=" + appWidgetId + " provider=" + provider);
         bindAppWidgetIdImpl(appWidgetId, provider, options);
     }
@@ -607,7 +607,7 @@
     public boolean bindAppWidgetIdIfAllowed(
             String packageName, int appWidgetId, ComponentName provider, Bundle options) {
         try {
-            mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, null);
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null);
         } catch (SecurityException se) {
             if (!callerHasBindAppWidgetPermission(packageName)) {
                 return false;